/// <summary> /// Polls the next command to execute locally from the server. The result of the /// last executed command must be given, if there is one. The returned Task may block /// some time, because the server uses the long polling technique to reduce network traffic. /// If the server can not be reached, an exception is thrown (because the last result /// has to be transmitted again). /// </summary> private async Task <RpcCommand?> PullFromServer(RpcCommandResult?lastResult) { // Long polling. The server returns null after the long polling time. var bodyJson = lastResult != null?JsonLib.ToJson(lastResult) : null; var httpResponse = await httpPull.PostAsync(clientConfig.ServerUrl + "/pull", bodyJson != null?new StringContent(bodyJson, Encoding.UTF8, "application/json") : null); if (httpResponse.IsSuccessStatusCode) { // Last result was received. The server responded with the next command or null, // if there is currently none. if (httpResponse.Content.Headers.ContentLength > 0) { return(JsonLib.FromJson <RpcCommand>(await httpResponse.Content.ReadAsStringAsync())); } else { return(null); } } else { // Remote exception. throw new Exception("Server responded with status code " + httpResponse.StatusCode); } }
public void EnqueueCommand(string clientID, RpcCommand command) { lock (syncLock) { var dir = GetDirectory(clientID); // Apply strategy var strategy = command.RetryStrategy; if (strategy == null || strategy == RpcRetryStrategy.None) { // No retry strategy chosen. This method should not have been called at all. Do nothing. return; } else if (strategy == RpcRetryStrategy.RetryWhenOnline) { // No preparation needed; just enqueue this command } else if (strategy == RpcRetryStrategy.RetryNewestWhenOnline) { // Remove all preceding commands of this type foreach (var file in GetFilesByCommandName(clientID, command.MethodName)) { file.Delete(); } } var filename = command.ID + "-" + command.MethodName; File.WriteAllText(Path.Combine(dir.FullName, filename), JsonLib.ToJson(command)); } }
public async Task SayHelloToClient(Greeting greeting) { Console.WriteLine("Hello " + greeting.Name + "!"); if (greeting.MoreData is SampleData moreData) { Console.WriteLine("More information for you: " + JsonLib.ToJson(moreData)); } }
/// <summary> /// Creates a new encoded RPC command, using the given method name and parameters. /// The parameters must be JSON-encodable objects. /// </summary> private RpcCommand(string methodName, params object[] methodParameters) { lock (syncLock) { loop++; if (loop > 999) { loop = 0; } ID = ((ulong)CoreUtils.TimeNow()) * 1000 + loop; } MethodName = methodName; MethodParameters = methodParameters.Select(it => JsonLib.ToJson(it)).ToList(); }
/// <summary> /// Sends the given command to the server now, reads the result or catches the /// exception, and sets the command's state accordingly. /// </summary> private async Task ExecuteOnServerNow(RpcCommand command) { RpcCommandResult result; var bodyJson = JsonLib.ToJson(command); try { var httpResponse = await httpPush.PostAsync(clientConfig.ServerUrl + "/push", new StringContent(bodyJson, Encoding.UTF8, "application/json")); if (httpResponse.IsSuccessStatusCode) { // Response (either success or remote failure) received. result = JsonLib.FromJson <RpcCommandResult>(await httpResponse.Content.ReadAsStringAsync()); } else { // The server did not respond with 200 (which it should do even in case of // a remote exception). So there is a communication error. result = RpcCommandResult.FromFailure(command.ID, new RpcFailure(RpcFailureType.RpcError, "Remote side problem with RPC call. HTTP status code " + (int)httpResponse.StatusCode)); } } catch { // Could not reach server. result = RpcCommandResult.FromFailure(command.ID, new RpcFailure(RpcFailureType.Timeout, "Could not reach the server")); } // When a result was received (i.e. when there was no network problem), the command is finished if (false == (result.Failure?.IsNetworkProblem == true) && command.ID == serverCache.CurrentCommand?.ID) { serverCache.FinishCurrentCommand(); } // Finish command command.Finish(result); }