private void HandleSpawnRequest(SpawnRequestPacket packet, IIncommingMessage message) { if (_spawnRequestHandler == null) { DefaultSpawnRequestHandler(packet, message); return; } _spawnRequestHandler.Invoke(packet, message); }
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; } }); }
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); } }
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); } }
/// <summary> /// /// </summary> /// <param name="packet"></param> /// <param name="message"></param> protected virtual void SpawnRequestHandler(SpawnRequestPacket packet, IIncommingMessage message) { spawnerController.DefaultSpawnRequestHandler(packet, message); }