/// <summary> /// /// </summary> /// <param name="Client"></param> public RemoteActionServer(Server InServer) { Server = InServer; Server.OnRequestRemoteActionRecieved += RequestRecieved; Server.OnCancelRemoteActionRecieved += CancelRecieved; Server.OnSolicitAcceptRemoteActionRecieved += SolicitAcceptRecieved; Server.OnRemoteActionProgressRecieved += (NetMessage_RemoteActionProgress Msg) => { RemoteActionServerState Action = GetActionState(Msg.ActionId); if (Action != null) { if (Action.Completed != Msg.Completed || Action.Failed != Msg.Failed || Action.ResultMessage != Msg.ResultMessage || Action.Progress != Msg.Progress || Action.ProgressText != Msg.ProgressText) { Action.Completed = Msg.Completed; Action.Failed = Msg.Failed; Action.ResultMessage = Msg.ResultMessage; Action.Progress = Msg.Progress; Action.ProgressText = Msg.ProgressText; Action.Dirty = true; } Action.LastUpdateRecieved = TimeUtils.Ticks; } }; }
/// <summary> /// /// </summary> /// <param name="Msg"></param> private void RequestRecieved(NetConnection Client, NetMessage_RequestRemoteAction Msg) { RemoteActionServerState State = AllocateState(Msg.ActionId, Msg.Type); State.Settings = Msg.Settings; State.ForClient = Client; State.Progress = 0.0f; State.ProgressText = "Waiting for available client ..."; State.Dirty = true; }
/// <summary> /// /// </summary> /// <param name="Client"></param> /// <param name="ActionId"></param> private void CancelRecieved(NetConnection Client, Guid ActionId) { RemoteActionServerState State = GetActionState(ActionId); if (State == null) { return; } State.Cancelled = true; }
/// <summary> /// /// </summary> /// <param name="Client"></param> /// <param name="ActionId"></param> private void SolicitAcceptRecieved(NetConnection Client, Guid ActionId) { RemoteActionServerState State = GetActionState(ActionId); if (State == null) { return; } State.SolicitationReplies.Add(Client); }
/// <summary> /// /// </summary> /// <returns></returns> public RemoteActionServerState AllocateState(Guid Id, RemoteActionType Type) { RemoteActionServerState State = new RemoteActionServerState(); State.Id = Id; State.Type = Type; States.Add(State); Logger.Log(LogLevel.Info, LogCategory.Main, "Allocated new remote action '{0}' of type {1}.", State.Id.ToString(), State.Type.ToString()); return(State); }
/// <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); } } } }