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)); } }
/// <summary> /// Call this method when the client called the "/rpc/push"-endpoint. /// It executes the given RPC command immediately and returns the result. /// No exception is thrown, but a <see cref="RpcFailure"/> result is set in case of a failure. /// </summary> public async Task <RpcCommandResult> OnClientPush(string clientID, RpcCommand command, RpcCommandRunner runner) { // Do not run the same command twice. If the command with this ID was already // executed, return the cached result. If the cache is not available any more, return a // obsolete function call failure. var client = clients.GetClient(clientID, commandBacklog); if (client.GetCachedResult(command.ID) is RpcCommandResult result) { return(result); } // Execute the command try { result = await runner.Execute(clientID, command); } catch (Exception ex) { result = RpcCommandResult.FromFailure(command.ID, new RpcFailure(RpcFailureType.RemoteException, ex.Message)); } // Cache result, if there was no network problem if (false == (result.Failure?.IsNetworkProblem == true)) { client.CacheResult(result); } return(result); }
/// <summary> /// Executes the given RPC command locally on the client immediately and returns the result. /// No exception is thrown, but a <see cref="RpcFailure"/> result is set in case of a failure. /// </summary> public async Task <RpcCommandResult> ExecuteLocallyNow(RpcCommand command) { // Do not run the same command twice. If the command with this ID was already // executed, return the cached result. If the cache is not available any more, return a // obsolete function call failure. if (serverCache.GetCachedResult(command.ID) is RpcCommandResult result) { return(result); } // Execute the command try { var runner = new RpcCommandRunner(clientMethods(), null); result = await runner.Execute(clientConfig.ClientID, command); } catch (Exception ex) { result = RpcCommandResult.FromFailure(command.ID, new RpcFailure(RpcFailureType.RemoteException, ex.Message)); } // Cache result, if there was no network problem if (false == (result.Failure?.IsNetworkProblem == true)) { serverCache.CacheResult(result); } return(result); }
static async Task <string> LoadSharedImage(HttpClient client, string rpcUri) { var imageName = "image-1"; // 共享图像名 var fmt = "rgb24"; // 图像像素格式 var w = 2048; // 图像宽度 var h = 1024; // 图像高度 var channels = 3; // 图像颜色通道数 var bytes = w * h * channels; // 图像字节数 using (var mapFile = System.IO.MemoryMappedFiles.MemoryMappedFile.CreateNew(imageName, bytes)) using (var accessor = mapFile.CreateViewAccessor()) { // 生成图像 for (var y = 0; y < h; ++y) { for (var x = 0; x < w; ++x) { var i = ((y * w) + x) * 3; var r = (x % w) * 256 / w; var g = (y % h) * 256 / h; accessor.Write(i + 0, (byte)r); accessor.Write(i + 1, (byte)g); accessor.Write(i + 2, (byte)0); } } var data = new byte[bytes]; accessor.ReadArray(0, data, 0, data.Length); // 构建远程过程调用命令 var cmds = new RpcCommand[] { new RpcCommandWithId { id = 1, method = "load_shared_image", @params = new object[] { imageName, fmt, w, h }, }, new RpcCommandWithId { id = 2, method = "inspect", @params = new object[0], }, new RpcCommand { method = "zoom", @params = new object[] { 0.5 }, }, }; // 远程过程调用 var json = Newtonsoft.Json.JsonConvert.SerializeObject(cmds); var content = new StringContent(json, Encoding.UTF8, "application/json-rpc"); var resp = await client.PostAsync(rpcUri, content); return(await resp.Content.ReadAsStringAsync()); } }
public static string GetCommandName(this RpcCommand command) { var attr = (DescriptionAttribute)command.GetType() .GetCustomAttributes(typeof(DescriptionAttribute), false) .FirstOrDefault(); if (attr != null) { return(attr.Description); } return(null); }
public async Task <string> Any(RpcCommand request) { var validation = CommandValidator.Validate(request); if (validation.Valid) { return(await PostRequest(request)); } else { throw new HttpError(HttpStatusCode.BadRequest, validation.ErrorText); } }
/// <summary> /// Runs the given command on the client ID. /// </summary> public async Task <RpcCommandResult> Execute(string clientID, RpcCommand command) { foreach (var rpc in rpcFunctions) { rpc.Context = new RpcContext(clientID, serviceScopeFactory); if (rpc.Execute(command) is Task <string?> task) { // Method found in this class return(RpcCommandResult.FromSuccess(command.ID, await task)); } } // Called method is not implemented in any registered class throw new Exception("Unknown method name: " + command.MethodName); }
private async Task <T> Post <T>(RpcMethod method, string[] parameters = null) { using (var client = new JsonServiceClient(baseUrl)) { var command = new RpcCommand { Method = method, Params = parameters }; var response = await client.PostAsync(command); var rpcresult = response.FromJson <RpcResult <T> >(); return(rpcresult.result); } }
/// <summary> /// Writes a command with arguments to the RPC pipe. /// </summary> /// <param name="command">The command to execute, from <see cref="Commands"/></param> /// <param name="arguments">The command arguments object, to be serialized as JSON</param> /// <returns>Task that resolves when the command has been sent</returns> public Task SendCommandAsync(string command, object arguments) { var frame = new RpcFrame(); var cmd = new RpcCommand { Arguments = JObject.FromObject(arguments), Command = command }; frame.OpCode = OpCode.Frame; frame.SetContent(JsonConvert.SerializeObject(cmd)); return(_pipe.WriteAsync(frame)); }
/// <summary> /// Dispatches a command with arguments to pipe. /// </summary> /// <param name="command">The command to execute</param> /// <param name="args"></param> public void DispatchCommand(RpcCommand command, object args = null) { var dispatch = new RpcDispatch(); dispatch.Command = command.GetCommandName(); dispatch.Arguments = args; var packet = new RpcPacket(); packet.OpCode = RpcOpCode.Frame; packet.SetData(dispatch.ToJson()); rpc.RaiseLogEvent(this, LogLevel.Debug, $"Dispatching command {command.GetCommandName()}"); Write(packet); }
private async Task <string> PostRequest(RpcCommand request) { try { using (var client = new JsonHttpClient(VergeConfig.GetUri())) { client.AddHeader("Authorization", VergeConfig.GetAuthHeaderValue()); var response = await client.PostAsync <string>(new Payload(request)); return(response); } } catch (Exception ex) { throw new HttpError(HttpStatusCode.InternalServerError, ex); } }
public string Serialize(RpcCommand cmd) { ApiCommands.RpcCommand target = null; if (cmd is GameCmd) { if (cmd is CmdPlayerMove move) { target = new ApiCommands.CmdPlayerMove() { current_pos = move.current_pos, next_pos = move.next_pos, use_time = move.use_time, speed = move.speed, move_mode = (byte)move.move_mode, stamp = move.stamp }; } if (cmd is CmdPlayerStopMove stopMove) { target = new ApiCommands.CmdPlayerStopMove() { current_pos = stopMove.current_pos, speed = stopMove.speed, dir = stopMove.dir, move_mode = (byte)stopMove.move_mode, stamp = stopMove.stamp, use_time = stopMove.use_time }; } if (cmd is CmdReviveVillage) { target = new ApiCommands.CmdReviveVillage(); } if (cmd is CmdGetAllData getAllData) { target = new ApiCommands.CmdGetAllData() { include_equip_info = getAllData.include_equip_info, include_pack_info = getAllData.include_pack_info, include_task_info = getAllData.include_task_info }; } } return(JsonConvert.SerializeObject(target.IntoRpc(), Formatting.None)); }
public frmMain() { InitializeComponent(); var iniReader = new IniReader(Resx.iniFileName); var config = new SetupConfig(); var rpcCommand = new RpcCommand(config.GetKodiIP()); var kodi = new Kodi(rpcCommand); var yamahaCommand = new YamahaCommand(); var soapCommand = new SoapCommand(); var yamahaResponse = new YamahaResponse(); var avReceiver = new AVReceiver(yamahaCommand, soapCommand, yamahaResponse); mediator = new Mediator(kodi, avReceiver, iniReader); RegisterButtons(); mediator.SetStripColors(); }
/// <summary> /// Enqueues the given command in the queue. /// When the queue would become too long, an <see cref="RpcException"/> of type /// <see cref="RpcFailureType.LocalQueueOverflow"/> is thrown. /// </summary> public void EnqueueCommand(RpcCommand command) { try { // When it is a command which should be retried in case of network failure, enqueue it in the command backlog. if (command.RetryStrategy != null && command.RetryStrategy != RpcRetryStrategy.None) { CommandBacklog.EnqueueCommand(ClientID, command); } // Always (additionally to the command backlog) add it to our normal query for immediate execution queue.Enqueue(command); command.SetState(RpcCommandState.Enqueued); } catch { throw new RpcException(new RpcFailure( RpcFailureType.QueueOverflow, $"Queue already full " + (ClientID != null ? $"for the client { ClientID}" : "for the server"))); } }
/// <summary> /// Runs the given RPC command on the server as soon as possible /// and returns the result or throws an <see cref="RpcException"/>. /// </summary> public async Task <T> ExecuteOnServer <T>(RpcCommand command) { try { // Apply [RpcOptions(...)] from method declaration command.ApplyRpcOptionsFromCallStack(); // Enqueue (and execute) serverCache.EnqueueCommand(command); // Wait for result until timeout return(await command.WaitForResult <T>()); } catch (RpcException ex) { // Rethrow RPC exception throw; } catch (Exception ex) { throw new RpcException(new RpcFailure(RpcFailureType.Other, ex.Message)); // Wrap any other exception } }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @SuppressWarnings({ "rawtypes", "unchecked" }) private void process(RemotingContext ctx, Object msg) private void process(RemotingContext ctx, object msg) { try { //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final rpc.RpcCommand cmd = (rpc.RpcCommand) msg; RpcCommand cmd = (RpcCommand)msg; //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final RemotingProcessor processor = processorManager.getProcessor(cmd.getCmdCode()); var processor = processorManager.getProcessor(cmd.CmdCode); processor.process(ctx, cmd, processorManager.DefaultExecutor); } //JAVA TO C# CONVERTER WARNING: 'final' catch parameters are not available in C#: //ORIGINAL LINE: catch (final Throwable t) catch (System.Exception t) { processException(ctx, msg, t); } }
/// <summary> /// Runs the given RPC command on the client with the given <see cref="RpcCommand.TargetPeerID"/> /// as soon as possible and returns the result or throws an <see cref="RpcException"/>. /// </summary> public async Task <T> ExecuteOnClient <T>(RpcCommand command) { try { var clientID = command.TargetPeerID; if (clientID.Length == 0) { throw new Exception("No client ID given"); } // Apply [RpcOptions(...)] from method declaration command.ApplyRpcOptionsFromCallStack(); // Enqueue (and execute) clients.GetClient(clientID, commandBacklog).EnqueueCommand(command); // Wait for result until timeout return(await command.WaitForResult <T>()); } catch (RpcException ex) { throw; // Rethrow RPC exception } catch (Exception ex) { throw new RpcException(new RpcFailure(RpcFailureType.Other, ex.Message)); // Wrap any other exception } }
/// <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); }
/// <summary> /// Runs the given RPC command on the client as soon as possible /// and returns the result or throws an <see cref="RpcException"/>. /// See <see cref="RpcCommand.CreateForClient"/> for the parameters. /// </summary> protected Task <T> ExecuteOnClient <T>(string methodName, params object[] methodParameters) => RpcServerEngine.Instance.ExecuteOnClient <T>( RpcCommand.CreateForClient(ClientID, methodName, methodParameters));
private static void DefineCommand(string command, RpcCommand handler) { CommandHandlers[command] = handler; }
/// <summary> /// Implement this method to map the encoded RPC commands to /// the real methods in this class. Thrown exceptions are catched /// and the calling peer gets notified about a /// <see cref="RpcFailureType.RemoteException"> failure. /// If successfull, returns a task with the JSON-encoded result or null /// if the method has no return type (void). /// If the given command name is undefined in this implementation, returns null /// (not a Task with value null, but null itself!). /// </summary> public abstract Task <string?>?Execute(RpcCommand command);
// Mapping of RpcCommand to real method calls (boilerplate code; we could auto-generate this method later) public override Task <string?>?Execute(RpcCommand command) => command.MethodName switch { "SayHelloToClient" => SayHelloToClient(command.GetParam <Greeting>(0)).ToJson(),
// Mapping of RpcCommand to real method calls (boilerplate code; we could auto-generate this method later) public override Task <string?>?Execute(RpcCommand command) => command.MethodName switch { "GetBalance" => GetBalance(command.GetParam <int>(0)).ToJson(),
// Mapping of RpcCommand to real method calls (boilerplate code; we could auto-generate this method later) public override Task <string?>?Execute(RpcCommand command) => command.MethodName switch { "AddNumbers" => AddNumbers(command.GetParam <int>(0), command.GetParam <int>(1)).ToJson(),
/// <summary> /// Runs the given RPC command on the server as soon as possible /// and returns the result or throws an <see cref="RpcException"/>. /// See <see cref="RpcCommand.CreateForServer"/> for the parameters. /// </summary> protected Task <T> ExecuteOnServer <T>(string methodName, params object[] methodParameters) => RpcClientEngine.Instance.ExecuteOnServer <T>(RpcCommand.CreateForServer(methodName, methodParameters));
/// <seealso cref= CommandEncoder#encode(io.netty.channel.IChannelHandlerContext, java.io.Serializable, io.netty.buffer.IByteBuffer) </seealso> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: @Override public void encode(io.netty.channel.IChannelHandlerContext ctx, java.io.Serializable msg, io.netty.buffer.IByteBuffer out) throws Exception public virtual void encode(IChannelHandlerContext ctx, object msg, IByteBuffer @out) { try { if (msg is RpcCommand) { /* * ver: version for protocol * type: request/response/request oneway * cmdcode: code for remoting command * ver2:version for remoting command * requestId: id of request * codec: code for codec * (req)timeout: request timeout. * (resp)respStatus: response status * classLen: length of request or response class name * headerLen: length of header * cotentLen: length of content * className * header * content */ RpcCommand cmd = (RpcCommand)msg; @out.WriteByte(RpcProtocol.PROTOCOL_CODE); @out.WriteByte(cmd.Type); @out.WriteShort(((RpcCommand)msg).CmdCode.value()); @out.WriteByte(cmd.Version); @out.WriteInt(cmd.Id); @out.WriteByte(cmd.Serializer); if (cmd is RequestCommand) { //timeout @out.WriteInt(((RequestCommand)cmd).Timeout); } if (cmd is ResponseCommand) { //response status ResponseCommand response = (ResponseCommand)cmd; @out.WriteShort((short)response.ResponseStatus); } @out.WriteShort(cmd.ClazzLength); @out.WriteShort(cmd.HeaderLength); @out.WriteInt(cmd.ContentLength); if (cmd.ClazzLength > 0) { @out.WriteBytes(cmd.Clazz); } if (cmd.HeaderLength > 0) { @out.WriteBytes(cmd.Header); } if (cmd.ContentLength > 0) { @out.WriteBytes(cmd.Content); } } else { string warnMsg = "msg type [" + msg.GetType() + "] is not subclass of RpcCommand"; logger.LogWarning(warnMsg); } } catch (Exception e) { logger.LogError("Exception caught!", e); throw; } }
public async Task Send(RpcCommand cmd) { await client.SendInstant(api.Serialize(cmd)); }
/// <seealso cref= CommandEncoder#encode(IChannelHandlerContext, Serializable, IByteBuffer) </seealso> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: @Override public void encode(io.netty.channel.IChannelHandlerContext ctx, java.io.Serializable msg, io.netty.buffer.IByteBuffer out) throws Exception public virtual void encode(IChannelHandlerContext ctx, object msg, IByteBuffer @out) { try { if (msg is RpcCommand) { /* * proto: magic code for protocol * ver: version for protocol * type: request/response/request oneway * cmdcode: code for remoting command * ver2:version for remoting command * requestId: id of request * codec: code for codec * switch: function switch * (req)timeout: request timeout. * (resp)respStatus: response status * classLen: length of request or response class name * headerLen: length of header * cotentLen: length of content * className * header * content * crc (optional) */ int index = @out.WriterIndex; RpcCommand cmd = (RpcCommand)msg; @out.WriteByte(RpcProtocolV2.PROTOCOL_CODE); var version = ctx.Channel.GetAttribute(Connection.VERSION); byte ver = RpcProtocolV2.PROTOCOL_VERSION_1; if (version != null && version.Get() != null) { ver = (byte)version.Get(); } @out.WriteByte(ver); @out.WriteByte(cmd.Type); @out.WriteShort(((RpcCommand)msg).CmdCode.value()); @out.WriteByte(cmd.Version); @out.WriteInt(cmd.Id); @out.WriteByte(cmd.Serializer); @out.WriteByte(cmd.ProtocolSwitch.toByte()); if (cmd is RequestCommand) { //timeout @out.WriteInt(((RequestCommand)cmd).Timeout); } if (cmd is ResponseCommand) { //response status ResponseCommand response = (ResponseCommand)cmd; @out.WriteShort((short)response.ResponseStatus); } @out.WriteShort(cmd.ClazzLength); @out.WriteShort(cmd.HeaderLength); @out.WriteInt(cmd.ContentLength); if (cmd.ClazzLength > 0) { @out.WriteBytes(cmd.Clazz); } if (cmd.HeaderLength > 0) { @out.WriteBytes(cmd.Header); } if (cmd.ContentLength > 0) { @out.WriteBytes(cmd.Content); } if (ver == RpcProtocolV2.PROTOCOL_VERSION_2 && cmd.ProtocolSwitch.isOn(ProtocolSwitch.CRC_SWITCH_INDEX)) { // compute the crc32 and write to out byte[] frame = new byte[@out.ReadableBytes]; @out.GetBytes(index, frame); @out.WriteInt(CrcUtil.crc32(frame)); } } else { string warnMsg = "msg type [" + msg.GetType() + "] is not subclass of RpcCommand"; logger.LogWarning(warnMsg); } } catch (Exception e) { logger.LogError("Exception caught!", e); throw; } }