/// <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); } } } }
/// <summary> /// /// </summary> /// <returns></returns> public void Poll() { for (int i = 0; i < States.Count; i++) { RemoteActionClientState State = States[i]; // Something we are running locally. if (State.RemoteInitiated) { // Handled by task runner. } // Something a remote peer is running. else { // We lost connection, aborted. if (!Client.IsConnected) { Logger.Log(LogLevel.Info, LogCategory.Main, "Removed remote action '{0}' as lost server connection.", State.Id.ToString()); State.ResultMessage = "Lost connection to server."; State.Completed = true; State.Failed = true; State.Dirty = true; } // Timed out waiting for progress update from server. else if (TimeUtils.Ticks - State.LastUpdateRecieved > RemoteActionClientState.LastUpdateTimeout) { Logger.Log(LogLevel.Info, LogCategory.Main, "Removed remote action '{0}' as timed out.", State.Id.ToString()); State.ResultMessage = "Timed out waiting for update from server."; State.Completed = true; State.Failed = true; State.Dirty = true; } } // Send progress update to the server if we are running it. if (TimeUtils.Ticks - State.LastUpdateSent > RemoteActionClientState.UpdateInterval || State.Dirty) { // Send update to server if required. if (Client.IsConnected && State.RemoteInitiated) { 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; Client.Connection.Send(Msg); State.LastUpdateSent = TimeUtils.Ticks; } } State.Dirty = false; // If completed (and remote initiated), clean up state. // If local initiated, the code starting the action is responsible for cleaning it up. if (State.Completed && State.RemoteInitiated) { States.RemoveAt(i); i--; } } } }