예제 #1
0
파일: RpcApi.cs 프로젝트: lulzzz/RpcLib
        public async Task <IActionResult> Pull()
        {
            // Identify calling client. If now allowed, return RPC failure.
            string?clientID = auth.GetClientID(Request);

            if (clientID == null)
            {
                return(Unauthorized());
            }
            // Read request body (if any). We do not use a [FromBody] parameter, because
            // we want to explicitly use our JsonLib for deserializing (and not overwrite the
            // user's selected default ASP.NET Core JSON serializer)
            RpcCommandResult?lastResult = null;

            using (var reader = new StreamReader(Request.Body)) {
                var body = await reader.ReadToEndAsync();

                if (body.Length > 0)
                {
                    lastResult = JsonLib.FromJson <RpcCommandResult>(body);
                }
            }
            // Report result and query next method
            return(Ok(await RpcServerEngine.Instance.OnClientPull(clientID, lastResult)));
        }
예제 #2
0
        /// <summary>
        /// Call this method after enqueuing the command to wait for the result of its execution.
        /// The returned task finishes when the call was either successfully executed and
        /// acknowledged, or failed (e.g. because of a timeout).
        /// The result is stored in the given command itself. If successful, the return value
        /// is also returned, otherwise an <see cref="RpcException"/> is thrown.
        /// </summary>
        public async Task <T> WaitForResult <T>()
        {
            try {
                // Wait for result until timeout
                await Task.WhenAny(runningTask.Task, Task.Delay(TimeoutMs ?? defaultTimeoutMs));

                // Timeout?
                if (false == IsFinished())
                {
                    throw new RpcException(new RpcFailure(RpcFailureType.Timeout, "Timeout"));
                }
                // Failed? Then throw RPC exception
                var result = GetResult();
                if (result.Failure is RpcFailure failure)
                {
                    throw new RpcException(failure);
                }
                // Return JSON-encoded result (or null for void return type)
                if (result.ResultJson is string json)
                {
                    return(JsonLib.FromJson <T>(json));
                }
                else
                {
                    return(default !);
예제 #3
0
파일: RpcApi.cs 프로젝트: lulzzz/RpcLib
        public async Task <IActionResult> Push()
        {
            // Identify calling client. If now allowed, return RPC failure.
            string?clientID = auth.GetClientID(Request);

            if (clientID == null)
            {
                return(Unauthorized());
            }
            // Read request body (if any). We do not use a [FromBody] parameter, because
            // we want to explicitly use our JsonLib for deserializing (and not overwrite the
            // user's selected default ASP.NET Core JSON serializer)
            try {
                using (var reader = new StreamReader(Request.Body)) {
                    var body = await reader.ReadToEndAsync();

                    if (body.Length > 0)
                    {
                        // Run command and return the result
                        var command = JsonLib.FromJson <RpcCommand>(body);
                        return(Ok(await RpcServerEngine.Instance.OnClientPush(clientID, command, runner)));
                    }
                }
            }
            catch { // Can happen when the client cancelled the request
            }
            // Command missing
            return(BadRequest());
        }
예제 #4
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);
            }
        }
예제 #5
0
 public void DequeueCommand(string clientID, ulong commandID)
 {
     lock (syncLock) {
         if (GetLatestFile(clientID) is FileInfo file)
         {
             var command = JsonLib.FromJson <RpcCommand>(File.ReadAllText(file.FullName));
             if (command.ID == commandID)
             {
                 file.Delete();
             }
         }
     }
 }
예제 #6
0
 public RpcCommand?PeekCommand(string clientID)
 {
     lock (syncLock) {
         if (GetLatestFile(clientID) is FileInfo file)
         {
             return(JsonLib.FromJson <RpcCommand>(File.ReadAllText(file.FullName)));
         }
         else
         {
             return(null);
         }
     }
 }
예제 #7
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);
        }
예제 #8
0
 /// <summary>
 /// Gets the decoded message parameter with the given index.
 /// </summary>
 public T GetParam <T>(int index) =>
 JsonLib.FromJson <T>(MethodParameters[index]);