Example #1
0
        /// <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);
            }
        }
Example #2
0
 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));
     }
 }
Example #3
0
 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));
     }
 }
Example #4
0
 /// <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();
 }
Example #5
0
        /// <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);
        }