/// <summary> /// /// </summary> /// <param name="Msg"></param> private void SolicitRemoteActionRecieved(NetMessage_SolicitRemoteAction Msg) { bool Accepted = false; // Don't accept if we are running any other actions. if (!IsRunningRemoteActions()) { if (Msg.Type == RemoteActionType.Install) { Guid ManifestId = Guid.Parse(Msg.Settings["ManifestId"]); ManifestDownloadState State = DownloadManager.GetDownload(ManifestId); if (State != null && State.State == ManifestDownloadProgressState.Complete) { try { // TODO: We don't support json files here. Should we just remove them? Nobody uses them. string ConfigFilePath = Path.Combine(State.LocalFolder, "buildsync.cs"); BuildSettings Settings = new BuildSettings(); Settings.ScriptSource = File.ReadAllText(ConfigFilePath); List <BuildLaunchMode> Modes; Modes = Settings.Compile(); Accepted = (Modes.Count > 0); } catch (Exception Ex) { // We cannot compile or use this script :( } } } } if (Accepted) { NetMessage_SolicitAcceptRemoteAction Reply = new NetMessage_SolicitAcceptRemoteAction(); Reply.ActionId = Msg.ActionId; Client.Connection.Send(Reply); } }
/// <summary> /// /// </summary> /// <returns></returns> public void Poll() { for (int i = 0; i < States.Count; i++) { RemoteActionServerState State = States[i]; // If this action has been allocated a client, wait for result. if (State.AllocatedClient != null) { // Client has not updated us in quite a while :( if (TimeUtils.Ticks - State.LastUpdateRecieved > RemoteActionServerState.LastUpdateTimeout) { Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' failed as no response has been heard from allocated client.", State.Id.ToString()); State.ResultMessage = "Remote client failed to send update in time."; State.Completed = true; State.Failed = true; State.Dirty = true; } // Client who was allocated this action has disconnected, so abort. else if (!State.AllocatedClient.IsConnected) { Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' failed as allocated client disconnected.", State.Id.ToString()); State.ResultMessage = "Remote client unexpected disconnected."; State.Completed = true; State.Failed = true; State.Dirty = true; } } // Otherwise send out a solicitation to perform action. else { // Client who requested this action has disconnected, so abort. if (!State.ForClient.IsConnected) { Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' failed as requesting client disconnected.", State.Id.ToString()); State.ResultMessage = "Requesting client unexpected disconnected."; State.Completed = true; State.Failed = true; State.Dirty = true; } // Client has cancelled this state. else if (State.Cancelled) { Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' failed as client cancelled it.", State.Id.ToString()); State.ResultMessage = "Cancelled by user."; State.Completed = true; State.Failed = true; State.Dirty = true; // Tell client allocated the job to cancel. if (State.AllocatedClient != null && State.AllocatedClient.IsConnected) { NetMessage_CancelRemoteAction Msg = new NetMessage_CancelRemoteAction(); Msg.ActionId = State.Id; State.AllocatedClient.Send(Msg); } } // Send new solicitation. else if (TimeUtils.Ticks - State.LastSolicitBroadcast > RemoteActionServerState.SolicitInterval) { Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' sending new solicitation request.", State.Id.ToString()); List <NetConnection> Clients = Server.ListenConnection.AllClients; foreach (NetConnection ClientConnection in Clients) { if (ClientConnection != State.ForClient && ClientConnection.Metadata != null) { ServerConnectedClient ClientState = ClientConnection.Metadata as ServerConnectedClient; if (ClientState.AllowRemoteActions) { NetMessage_SolicitRemoteAction Msg = new NetMessage_SolicitRemoteAction(); Msg.ActionId = State.Id; Msg.Type = State.Type; Msg.Settings = State.Settings; ClientConnection.Send(Msg); } } } State.LastSolicitBroadcast = TimeUtils.Ticks; } // Nobody responded saying they can perform the action :| else if (TimeUtils.Ticks - State.RecievedTime > RemoteActionServerState.SolicitTimeout) { Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' failed as nobody responded to solicitation.", State.Id.ToString()); State.ResultMessage = "No remote clients accepted request."; State.Completed = true; State.Failed = true; State.Dirty = true; } // We have a client who can do the job! else if (State.SolicitationReplies.Count > 0 && TimeUtils.Ticks - State.LastSolicitBroadcast > RemoteActionServerState.MinSolicitWait) { Logger.Log(LogLevel.Info, LogCategory.Main, "Remote action '{0}' recieved solicitation reply and is starting.", State.Id.ToString()); State.AllocatedClient = State.SolicitationReplies[SolicitSelectionRandom.Next(0, State.SolicitationReplies.Count - 1)]; State.SolicitationReplies.Clear(); State.LastUpdateRecieved = TimeUtils.Ticks; NetMessage_RequestRemoteAction Msg = new NetMessage_RequestRemoteAction(); Msg.ActionId = State.Id; Msg.Type = State.Type; Msg.Settings = State.Settings; State.AllocatedClient.Send(Msg); } } // Send progress update to the client. if (TimeUtils.Ticks - State.LastUpdateSent > RemoteActionServerState.UpdateInterval || State.Dirty) { if (State.ForClient.IsConnected) { if (State.Completed || TimeUtils.Ticks - State.LastUpdateSent > RemoteActionClientState.MinUpdateInterval) { NetMessage_RemoteActionProgress Msg = new NetMessage_RemoteActionProgress(); Msg.ActionId = State.Id; Msg.Completed = State.Completed; Msg.Failed = State.Failed; Msg.ResultMessage = State.ResultMessage; Msg.Progress = State.Progress; Msg.ProgressText = State.ProgressText; State.ForClient.Send(Msg); State.LastUpdateSent = TimeUtils.Ticks; } } State.Dirty = false; // If completed, clean up state. if (State.Completed) { RemoveActionState(State.Id); } } } }