Exemplo n.º 1
0
        private void HandleSpawnRequest(SpawnRequestPacket packet, IIncommingMessage message)
        {
            if (_spawnRequestHandler == null)
            {
                DefaultSpawnRequestHandler(packet, message);
                return;
            }

            _spawnRequestHandler.Invoke(packet, message);
        }
Exemplo n.º 2
0
        public void UpdateQueue()
        {
            // Ignore if there's no connection with the peer
            if (!Peer.IsConnected)
            {
                return;
            }

            // Ignore if nothing's in the queue
            if (_queue.Count == 0)
            {
                return;
            }

            if (_beingSpawned.Count >= MaxConcurrentRequests)
            {
                // If we're currently at the maximum available concurrent spawn count
                var finishedSpawns = _beingSpawned.Where(s => s.IsDoneStartingProcess);

                // Remove finished spawns
                foreach (var finishedSpawn in finishedSpawns)
                {
                    _beingSpawned.Remove(finishedSpawn);
                }
            }

            // If we're still at the maximum concurrent requests
            if (_beingSpawned.Count >= MaxConcurrentRequests)
            {
                return;
            }

            var task = _queue.Dequeue();

            var data = new SpawnRequestPacket()
            {
                SpawnerId  = SpawnerId,
                CustomArgs = task.CustomArgs,
                Properties = task.Properties,
                SpawnId    = task.SpawnId,
                SpawnCode  = task.UniqueCode
            };

            var msg = Msf.Create.Message((short)MsfMessageCodes.SpawnProcessRequest, data);

            Peer.SendMessage(msg, (status, response) =>
            {
                if (status != ResponseStatus.Success)
                {
                    task.Abort();
                    Logs.Error("Spawn request was not handled. Status: " + status + " | " + response.AsString("Unknown Error"));
                    return;
                }
            });
        }
Exemplo n.º 3
0
        public void DefaultSpawnRequestHandler(SpawnRequestPacket packet, IIncommingMessage message)
        {
            Logger.Debug("Default spawn handler started handling a request to spawn process");

            var controller = Msf.Server.Spawners.GetController(packet.SpawnerId);

            if (controller == null)
            {
                message.Respond("Failed to spawn a process. Spawner controller not found", ResponseStatus.Failed);
                return;
            }

            var port = Msf.Server.Spawners.GetAvailablePort();

            // Check if we're overriding an IP to master server
            var masterIp = string.IsNullOrEmpty(controller.DefaultSpawnerSettings.MasterIp) ?
                           controller.Connection.ConnectionIp : controller.DefaultSpawnerSettings.MasterIp;

            // Check if we're overriding a port to master server
            var masterPort = controller.DefaultSpawnerSettings.MasterPort < 0 ?
                             controller.Connection.ConnectionPort : controller.DefaultSpawnerSettings.MasterPort;

            // Machine Ip
            var machineIp = controller.DefaultSpawnerSettings.MachineIp;

            // Path to executable
            var path = controller.DefaultSpawnerSettings.ExecutablePath;

            if (string.IsNullOrEmpty(path))
            {
                path = File.Exists(Environment.GetCommandLineArgs()[0])
                    ? Environment.GetCommandLineArgs()[0]
                    : Process.GetCurrentProcess().MainModule.FileName;
            }

            // In case a path is provided with the request
            if (packet.Properties.ContainsKey(MsfDictKeys.ExecutablePath))
            {
                path = packet.Properties[MsfDictKeys.ExecutablePath];
            }

            // Get the scene name
            var sceneNameArgument = packet.Properties.ContainsKey(MsfDictKeys.SceneName)
                ? string.Format("{0} {1} ", Msf.Args.Names.LoadScene, packet.Properties[MsfDictKeys.SceneName])
                : "";

            if (!string.IsNullOrEmpty(packet.OverrideExePath))
            {
                path = packet.OverrideExePath;
            }

            // If spawn in batchmode was set and `DontSpawnInBatchmode` arg is not provided
            var spawnInBatchmode = controller.DefaultSpawnerSettings.SpawnInBatchmode &&
                                   !Msf.Args.DontSpawnInBatchmode;


            #region Custom Albot Data
            //Albot Edit! We add so that the gameserver knows if it is a realtime game and what type.
            //These values will be read in the Msf.Args and accesable after startup
            string realTimeValue   = packet.Properties[MsfDictKeys.IsRealtime];
            string gameTypeValue   = packet.Properties[MsfDictKeys.GameType];
            string spectatorsValue = packet.Properties[MsfDictKeys.Spectators];

            string realtimeInfo   = string.Format("{0} {1} ", Msf.Args.Names.Realtime, realTimeValue);
            string gameTypeInfo   = string.Format("{0} {1} ", Msf.Args.Names.GameType, gameTypeValue);
            string SpectatorsInfo = string.Format("{0} {1} ", Msf.Args.Names.Spectators, spectatorsValue);
            #endregion



            var startProcessInfo = new ProcessStartInfo(path)
            {
                CreateNoWindow  = false,
                UseShellExecute = false,
                Arguments       = " " +
                                  (spawnInBatchmode ? "-batchmode -nographics " : "") +
                                  (controller.DefaultSpawnerSettings.AddWebGlFlag ? Msf.Args.Names.WebGl + " " : "") +
                                  sceneNameArgument +
                                  string.Format("{0} {1} ", Msf.Args.Names.MasterIp, masterIp) +
                                  string.Format("{0} {1} ", Msf.Args.Names.MasterPort, masterPort) +
                                  string.Format("{0} {1} ", Msf.Args.Names.SpawnId, packet.SpawnId) +
                                  string.Format("{0} {1} ", Msf.Args.Names.AssignedPort, port) +
                                  string.Format("{0} {1} ", Msf.Args.Names.MachineIp, machineIp) +
                                  (Msf.Args.DestroyUi ? Msf.Args.Names.DestroyUi + " " : "") +
                                  string.Format("{0} \"{1}\" ", Msf.Args.Names.SpawnCode, packet.SpawnCode) +
                                  packet.CustomArgs +
                                  realtimeInfo +
                                  gameTypeInfo +
                                  SpectatorsInfo
            };

            Logger.Debug("Starting process with args: " + startProcessInfo.Arguments);

            var processStarted = false;

            try
            {
                new Thread(() =>
                {
                    try
                    {
                        Logger.Debug("New thread started");

                        using (var process = Process.Start(startProcessInfo))
                        {
                            Logger.Debug("Process started. Spawn Id: " + packet.SpawnId + ", pid: " + process.Id);
                            processStarted = true;

                            Logger.Debug(_processLock);
                            lock (_processLock)
                            {
                                // Save the process
                                _processes[packet.SpawnId] = process;
                            }

                            var processId = process.Id;
                            // Notify server that we've successfully handled the request
                            BTimer.ExecuteOnMainThread(() =>
                            {
                                Logger.Debug("Sending Success");
                                message.Respond(ResponseStatus.Success);
                                controller.NotifyProcessStarted(packet.SpawnId, processId, startProcessInfo.Arguments);
                                Logger.Debug("Post Sending Success");
                            });

                            process.WaitForExit();
                        }
                    }
                    catch {
                        if (!processStarted)
                        {
                            BTimer.ExecuteOnMainThread(() => { message.Respond(ResponseStatus.Failed); });
                        }

                        Logger.Debug("An exception was thrown while starting a process. Make sure that you have set a correct build path. " +
                                     "We've tried to start a process at: '" + path + "'. You can change it at 'SpawnerBehaviour' component");
                    }
                    finally
                    {
                        lock (_processLock)
                        {
                            // Remove the process
                            _processes.Remove(packet.SpawnId);
                        }

                        BTimer.ExecuteOnMainThread(() =>
                        {
                            // Release the port number
                            Msf.Server.Spawners.ReleasePort(port);

                            Logger.Debug("Notifying about killed process with spawn id: " + packet.SpawnerId);
                            controller.NotifyProcessKilled(packet.SpawnId);
                        });
                    }
                }).Start();
            }
            catch (Exception e)
            {
                message.Respond(e.Message, ResponseStatus.Error);
                Logs.Error(e);
            }
        }
Exemplo n.º 4
0
        public void DefaultSpawnRequestHandler(SpawnRequestPacket packet, IIncommingMessage message)
        {
            Logger.Debug("Default spawn handler started handling a request to spawn process");

            var controller = Msf.Server.Spawners.GetController(packet.SpawnerId);

            if (controller == null)
            {
                message.Respond("Failed to spawn a process. Spawner controller not found", ResponseStatus.Failed);
                return;
            }

            ////////////////////////////////////////////
            /// Create process args string
            var processArguments = new StringBuilder();

            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// Check if we're overriding an IP to master server
            var masterIpArgument = string.IsNullOrEmpty(controller.DefaultSpawnerSettings.MasterIp) ?
                                   controller.Connection.ConnectionIp : controller.DefaultSpawnerSettings.MasterIp;

            ////////////////////////////////////////////
            /// Create msater IP arg
            processArguments.Append($"{Msf.Args.Names.MasterIp} {masterIpArgument}");
            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// Check if we're overriding a port to master server
            var masterPortArgument = controller.DefaultSpawnerSettings.MasterPort < 0 ?
                                     controller.Connection.ConnectionPort : controller.DefaultSpawnerSettings.MasterPort;

            ////////////////////////////////////////////
            /// Create master port arg
            processArguments.Append($"{Msf.Args.Names.MasterPort} {masterPortArgument}");
            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// Machine Ip
            var machineIpArgument = controller.DefaultSpawnerSettings.MachineIp;

            /// Create room IP arg
            processArguments.Append($"{Msf.Args.Names.RoomIp} {machineIpArgument}");
            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// Create port for room arg
            int machinePortArgument = Msf.Server.Spawners.GetAvailablePort();

            processArguments.Append($"{Msf.Args.Names.RoomPort} {machinePortArgument}");
            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// Get the scene name
            var sceneNameArgument = packet.Properties.ContainsKey(MsfDictKeys.sceneName)
                ? $"{Msf.Args.Names.LoadScene} {packet.Properties[MsfDictKeys.sceneName]}" : string.Empty;

            /// Create scene name arg
            processArguments.Append(sceneNameArgument);
            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// If spawn in batchmode was set and `DontSpawnInBatchmode` arg is not provided
            var spawnInBatchmodeArgument = controller.DefaultSpawnerSettings.SpawnInBatchmode && !Msf.Args.DontSpawnInBatchmode;

            processArguments.Append((spawnInBatchmodeArgument ? "-batchmode -nographics" : string.Empty));
            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// Create scene name arg
            processArguments.Append((controller.DefaultSpawnerSettings.UseWebSockets ? Msf.Args.Names.UseWebSockets + " " : string.Empty));
            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// Create spawn id arg
            processArguments.Append($"{Msf.Args.Names.SpawnId} {packet.SpawnId}");
            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// Create spawn code arg
            processArguments.Append($"{Msf.Args.Names.SpawnCode} \"{packet.SpawnCode}\"");
            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// Create destroy ui arg
            processArguments.Append((Msf.Args.DestroyUi ? Msf.Args.Names.DestroyUi + " " : string.Empty));
            processArguments.Append(" ");

            ////////////////////////////////////////////
            /// Create custom args
            processArguments.Append(packet.CustomArgs);
            processArguments.Append(" ");

            ///////////////////////////////////////////
            /// Path to executable
            var executablePath = controller.DefaultSpawnerSettings.ExecutablePath;

            if (string.IsNullOrEmpty(executablePath))
            {
                executablePath = File.Exists(Environment.GetCommandLineArgs()[0])
                    ? Environment.GetCommandLineArgs()[0]
                    : Process.GetCurrentProcess().MainModule.FileName;
            }

            // In case a path is provided with the request
            if (packet.Properties.ContainsKey(MsfDictKeys.executablePath))
            {
                executablePath = packet.Properties[MsfDictKeys.executablePath];
            }

            if (!string.IsNullOrEmpty(packet.OverrideExePath))
            {
                executablePath = packet.OverrideExePath;
            }

            /// Create info about starting process
            var startProcessInfo = new ProcessStartInfo(executablePath)
            {
                CreateNoWindow  = false,
                UseShellExecute = false,
                Arguments       = processArguments.ToString()
            };

            Logger.Debug("Starting process with args: " + startProcessInfo.Arguments);

            var processStarted = false;

            try
            {
                new Thread(() =>
                {
                    try
                    {
                        using (var process = Process.Start(startProcessInfo))
                        {
                            Logger.Debug("Process started. Spawn Id: " + packet.SpawnId + ", pid: " + process.Id);
                            processStarted = true;

                            lock (processLock)
                            {
                                // Save the process
                                processes[packet.SpawnId] = process;
                            }

                            var processId = process.Id;

                            // Notify server that we've successfully handled the request
                            MsfTimer.RunInMainThread(() =>
                            {
                                message.Respond(ResponseStatus.Success);
                                controller.NotifyProcessStarted(packet.SpawnId, processId, startProcessInfo.Arguments);
                            });

                            process.WaitForExit();
                        }
                    }
                    catch (Exception e)
                    {
                        if (!processStarted)
                        {
                            MsfTimer.RunInMainThread(() => { message.Respond(ResponseStatus.Failed); });
                        }

                        Logger.Error("An exception was thrown while starting a process. Make sure that you have set a correct build path. " +
                                     "We've tried to start a process at: '" + executablePath + "'. You can change it at 'SpawnerBehaviour' component");
                        Logger.Error(e);
                    }
                    finally
                    {
                        lock (processLock)
                        {
                            // Remove the process
                            processes.Remove(packet.SpawnId);
                        }

                        MsfTimer.RunInMainThread(() =>
                        {
                            // Release the port number
                            Msf.Server.Spawners.ReleasePort(machinePortArgument);

                            Logger.Debug("Notifying about killed process with spawn id: " + packet.SpawnerId);
                            controller.NotifyProcessKilled(packet.SpawnId);
                        });
                    }
                }).Start();
            }
            catch (Exception e)
            {
                message.Respond(e.Message, ResponseStatus.Error);
                Logs.Error(e);
            }
        }
        /// <summary>
        /// Default spawn spawned process request handler that will be used by controller if <see cref="spawnRequestHandler"/> is not overriden
        /// </summary>
        /// <param name="data"></param>
        /// <param name="message"></param>
        public virtual void SpawnRequestHandler(SpawnRequestPacket data, IIncommingMessage message)
        {
            Logger.Debug($"Default spawn handler started handling a request to spawn process for spawn controller [{SpawnerId}]");

            /************************************************************************/
            // Create process args string
            var processArguments = new DictionaryOptions();

            /************************************************************************/
            // Check if we're overriding an IP to master server
            var masterIpArgument = string.IsNullOrEmpty(SpawnSettings.MasterIp) ?
                                   Connection.ConnectionIp : SpawnSettings.MasterIp;

            // Create msater IP arg
            processArguments.Set(Msf.Args.Names.MasterIp, masterIpArgument);

            /************************************************************************/
            /// Check if we're overriding a port to master server
            var masterPortArgument = SpawnSettings.MasterPort < 0 ?
                                     Connection.ConnectionPort : SpawnSettings.MasterPort;

            // Create master port arg
            processArguments.Set(Msf.Args.Names.MasterPort, masterPortArgument);

            /************************************************************************/
            // Room Name
            processArguments.Set(Msf.Args.Names.RoomName, $"\"{data.Options.AsString(MsfDictKeys.roomName, "Room_" + Msf.Helper.CreateRandomString(6))}\"");

            /************************************************************************/
            // Room Region
            processArguments.Set(Msf.Args.Names.RoomRegion, $"\"{SpawnSettings.Region}\"");

            /************************************************************************/
            // Room Max Connections
            if (data.Options.Has(MsfDictKeys.maxPlayers))
            {
                processArguments.Set(Msf.Args.Names.RoomMaxConnections, data.Options.AsString(MsfDictKeys.maxPlayers));
            }

            /************************************************************************/
            // Machine Ip
            processArguments.Set(Msf.Args.Names.RoomIp, SpawnSettings.MachineIp);

            /************************************************************************/
            // Create port for room arg
            int machinePortArgument = Msf.Server.Spawners.GetAvailablePort();

            processArguments.Set(Msf.Args.Names.RoomPort, machinePortArgument);

            /************************************************************************/
            // Get the scene name
            if (data.Options.Has(MsfDictKeys.sceneName))
            {
                processArguments.Set(Msf.Args.Names.LoadScene, data.Options.AsString(MsfDictKeys.sceneName));
            }

            /************************************************************************/
            // If spawn in batchmode was set and DontSpawnInBatchmode arg is not provided
            if (SpawnSettings.SpawnInBatchmode && !Msf.Args.DontSpawnInBatchmode)
            {
                processArguments.Set("-batchmode -nographics", string.Empty);
            }

            /************************************************************************/
            // Create use websockets arg
            if (SpawnSettings.UseWebSockets)
            {
                processArguments.Set(Msf.Args.Names.UseWebSockets, string.Empty);
            }

            /************************************************************************/
            // Create spawn id arg
            processArguments.Set(Msf.Args.Names.SpawnTaskId, data.SpawnTaskId);

            /************************************************************************/
            // Create spawn code arg
            processArguments.Set(Msf.Args.Names.SpawnTaskUniqueCode, data.SpawnTaskUniqueCode);

            /************************************************************************/
            // Create destroy ui arg
            if (Msf.Args.DestroyUi)
            {
                processArguments.Set(Msf.Args.Names.DestroyUi, string.Empty);
            }

            /************************************************************************/
            // Create custom args
            processArguments.Append(data.CustomOptions);

            /************************************************************************/
            // Path to executable
            var executablePath = SpawnSettings.ExecutablePath;

            if (string.IsNullOrEmpty(executablePath))
            {
                executablePath = File.Exists(Environment.GetCommandLineArgs()[0])
                    ? Environment.GetCommandLineArgs()[0]
                    : Process.GetCurrentProcess().MainModule.FileName;
            }

            // In case a path is provided with the request
            if (data.Options.Has(MsfDictKeys.executablePath))
            {
                executablePath = data.Options.AsString(MsfDictKeys.executablePath);
            }

            if (!string.IsNullOrEmpty(data.OverrideExePath))
            {
                executablePath = data.OverrideExePath;
            }

            /// Create info about starting process
            var startProcessInfo = new ProcessStartInfo(executablePath)
            {
                CreateNoWindow  = false,
                UseShellExecute = false,
                Arguments       = processArguments.ToReadableString(" ", " ")
            };

            Logger.Debug("Starting process with args: " + startProcessInfo.Arguments);

            var processStarted = false;

            try
            {
                new Thread(() =>
                {
                    try
                    {
                        using (var process = Process.Start(startProcessInfo))
                        {
                            Logger.Debug("Process started. Spawn Id: " + data.SpawnTaskId + ", pid: " + process.Id);
                            processStarted = true;

                            lock (processLock)
                            {
                                // Save the process
                                processes[data.SpawnTaskId] = process;
                            }

                            var processId = process.Id;

                            // Notify server that we've successfully handled the request
                            MsfTimer.RunInMainThread(() =>
                            {
                                message.Respond(ResponseStatus.Success);
                                NotifyProcessStarted(data.SpawnTaskId, processId, startProcessInfo.Arguments);
                            });

                            process.WaitForExit();
                        }
                    }
                    catch (Exception e)
                    {
                        if (!processStarted)
                        {
                            MsfTimer.RunInMainThread(() => { message.Respond(ResponseStatus.Failed); });
                        }

                        Logger.Error("An exception was thrown while starting a process. Make sure that you have set a correct build path. " +
                                     $"We've tried to start a process at [{executablePath}]. You can change it at 'SpawnerBehaviour' component");
                        Logger.Error(e);
                    }
                    finally
                    {
                        lock (processLock)
                        {
                            // Remove the process
                            processes.Remove(data.SpawnTaskId);
                        }

                        MsfTimer.RunInMainThread(() =>
                        {
                            // Release the port number
                            Msf.Server.Spawners.ReleasePort(machinePortArgument);
                            Logger.Debug($"Notifying about killed process with spawn id [{data.SpawnTaskId}]");
                            NotifyProcessKilled(data.SpawnTaskId);
                        });
                    }
                }).Start();
            }
            catch (Exception e)
            {
                message.Respond(e.Message, ResponseStatus.Error);
                Logs.Error(e);
            }
        }
Exemplo n.º 6
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="packet"></param>
 /// <param name="message"></param>
 protected virtual void SpawnRequestHandler(SpawnRequestPacket packet, IIncommingMessage message)
 {
     spawnerController.DefaultSpawnRequestHandler(packet, message);
 }