public async Task TestProcAsync(Func <JsonRpc, CancellationToken, Task> mainFunc) { var cancellationTokenSrc = new CancellationTokenSource(); var cancellationToken = cancellationTokenSrc.Token; using (var socket = new ClientWebSocket()) { socket.Options.RemoteCertificateValidationCallback = (a, b, c, d) => true; var uri = new Uri(LyraGlobal.SelectNode(NetworkId)); var wssUrl = $"wss://{uri.Host}:{uri.Port}/api/v1/socket"; await socket.ConnectAsync(new Uri(wssUrl), cancellationToken); using (var jsonRpc = new JsonRpc(new WebSocketMessageHandler(socket))) { try { jsonRpc.AddLocalRpcMethod("Sign", new Func <string, string, string, Task <string[]> >( async(type, msg, accountId) => { var sign = await SignMessageAsync(msg); return(new string[] { "p1393", sign }); } )); jsonRpc.AddLocalRpcMethod("Notify", new Action <JObject>( (newsObj) => { var news = newsObj.ToObject <News>(); if (news.catalog == "Receiving") { RecvNotify(news.content as JObject); } } )); jsonRpc.StartListening(); await mainFunc(jsonRpc, cancellationToken); cancellationTokenSrc.Cancel(); await jsonRpc.Completion.WithCancellation(cancellationToken); } catch (OperationCanceledException) { // Closing is initiated by Ctrl+C on the client. // Close the web socket gracefully -- before JsonRpc is disposed to avoid the socket going into an aborted state. await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client closing", CancellationToken.None); //throw; } catch { throw; } } } }
static async Task MainAsync(CancellationToken cancellationToken) { Console.WriteLine("Connecting to web socket..."); using (var socket = new ClientWebSocket()) { await socket.ConnectAsync(new Uri("wss://localhost:44392/socket"), cancellationToken); Console.WriteLine("Connected to web socket. Establishing JSON-RPC protocol..."); using (var jsonRpc = new JsonRpc(new WebSocketMessageHandler(socket))) { try { jsonRpc.AddLocalRpcMethod("Tick", new Action <int>(tick => Console.WriteLine($"Tick {tick}!"))); jsonRpc.StartListening(); Console.WriteLine("JSON-RPC protocol over web socket established."); int result = await jsonRpc.InvokeWithCancellationAsync <int>("Add", new object[] { 1, 2 }, cancellationToken); Console.WriteLine($"JSON-RPC server says 1 + 2 = {result}"); // Request notifications from the server. await jsonRpc.NotifyAsync("SendTicksAsync"); await jsonRpc.Completion.WithCancellation(cancellationToken); } catch (OperationCanceledException) { // Closing is initiated by Ctrl+C on the client. // Close the web socket gracefully -- before JsonRpc is disposed to avoid the socket going into an aborted state. await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client closing", CancellationToken.None); throw; } } } }
/// <summary> /// RPCに接続する /// </summary> /// <param name="ws">WebSocket</param> /// <returns></returns> private async Task ConnectRpcAsync(ClientWebSocket ws) { Rpc = new JsonRpc(new WebSocketMessageHandler(ws)); Rpc.Disconnected += (s, e) => { // 切断されたときの処理 if (Logger != null) { Logger.LogWarning($"切断されました {ToString()}"); isWebSocketConnected = false; var t = RunAsync(); } }; Rpc.AddLocalRpcMethod(ChannelMessage, new Action <JToken, CancellationToken>((@params, cancellationToken) => { // 受信したときの処理 var p = @params as dynamic; // 受信したメッセージ(json)をイベントに送る OnGetMessage(new TextEventArgs(p.message.ToString())); })); Rpc.StartListening(); await Rpc.InvokeWithParameterObjectAsync <object>("subscribe", new { channel = ChannelName }); }
internal LanguageServerTarget( AbstractRequestDispatcherFactory requestDispatcherFactory, JsonRpc jsonRpc, ICapabilitiesProvider capabilitiesProvider, LspWorkspaceRegistrationService workspaceRegistrationService, LspMiscellaneousFilesWorkspace?lspMiscellaneousFilesWorkspace, IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listenerProvider, ILspLogger logger, ImmutableArray <string> supportedLanguages, string?clientName, WellKnownLspServerKinds serverKind) { _requestDispatcher = requestDispatcherFactory.CreateRequestDispatcher(serverKind); _capabilitiesProvider = capabilitiesProvider; _logger = logger; _jsonRpc = jsonRpc; _jsonRpc.AddLocalRpcTarget(this); _jsonRpc.Disconnected += JsonRpc_Disconnected; _listener = listenerProvider.GetListener(FeatureAttribute.LanguageServer); _clientName = clientName; _queue = new RequestExecutionQueue( logger, workspaceRegistrationService, lspMiscellaneousFilesWorkspace, globalOptions, supportedLanguages, serverKind); _queue.RequestServerShutdown += RequestExecutionQueue_Errored; var entryPointMethod = typeof(DelegatingEntryPoint).GetMethod(nameof(DelegatingEntryPoint.EntryPointAsync)); Contract.ThrowIfNull(entryPointMethod, $"{typeof(DelegatingEntryPoint).FullName} is missing method {nameof(DelegatingEntryPoint.EntryPointAsync)}"); foreach (var metadata in _requestDispatcher.GetRegisteredMethods()) { // Instead of concretely defining methods for each LSP method, we instead dynamically construct // the generic method info from the exported handler types. This allows us to define multiple handlers for the same method // but different type parameters. This is a key functionality to support TS external access as we do not want to couple // our LSP protocol version dll to theirs. // // We also do not use the StreamJsonRpc support for JToken as the rpc method parameters because we want // StreamJsonRpc to do the deserialization to handle streaming requests using IProgress<T>. var delegatingEntryPoint = new DelegatingEntryPoint(metadata.MethodName, this); var genericEntryPointMethod = entryPointMethod.MakeGenericMethod(metadata.RequestType, metadata.ResponseType); _jsonRpc.AddLocalRpcMethod(genericEntryPointMethod, delegatingEntryPoint, new JsonRpcMethodAttribute(metadata.MethodName) { UseSingleObjectParameterDeserialization = true }); } }
/// <summary> /// Initializes a new instance of the <see cref="MessageFormatterEnumerableTracker"/> class. /// </summary> /// <param name="jsonRpc">The <see cref="JsonRpc"/> instance that may be used to send or receive RPC messages related to <see cref="IAsyncEnumerable{T}"/>.</param> /// <param name="formatterState">The formatter that owns this tracker.</param> public MessageFormatterEnumerableTracker(JsonRpc jsonRpc, IJsonRpcFormatterState formatterState) { Requires.NotNull(jsonRpc, nameof(jsonRpc)); Requires.NotNull(formatterState, nameof(formatterState)); this.jsonRpc = jsonRpc; this.formatterState = formatterState; jsonRpc.AddLocalRpcMethod(NextMethodName, OnNextAsyncMethodInfo, this); jsonRpc.AddLocalRpcMethod(DisposeMethodName, OnDisposeAsyncMethodInfo, this); this.formatterState = formatterState; // We don't offer a way to remove these handlers because this object should has a lifetime closely tied to the JsonRpc object anyway. IJsonRpcFormatterCallbacks callbacks = jsonRpc; callbacks.RequestTransmissionAborted += (s, e) => this.CleanUpResources(e.RequestId); callbacks.ResponseReceived += (s, e) => this.CleanUpResources(e.RequestId); }
private void AddLocalRpcMethod(string localMethodName, string rpcMethodName) { _rpc.AddLocalRpcMethod( handler: typeof(MsSqlServiceClient).GetMethod(localMethodName), target: this, methodRpcSettings: new JsonRpcMethodAttribute(rpcMethodName) { UseSingleObjectParameterDeserialization = true }); }
internal LanguageServerTarget( AbstractLspServiceProvider lspServiceProvider, JsonRpc jsonRpc, ICapabilitiesProvider capabilitiesProvider, IAsynchronousOperationListenerProvider listenerProvider, ILspLogger logger, ImmutableArray <string> supportedLanguages, WellKnownLspServerKinds serverKind) { _capabilitiesProvider = capabilitiesProvider; _logger = logger; _jsonRpc = jsonRpc; _jsonRpc.AddLocalRpcTarget(this); _jsonRpc.Disconnected += JsonRpc_Disconnected; _listener = listenerProvider.GetListener(FeatureAttribute.LanguageServer); // Add services that require base dependencies (jsonrpc) or are more complex to create to the set manually. _lspServices = lspServiceProvider.CreateServices(serverKind, ImmutableArray.Create( CreateLspServiceInstance <ILanguageServerNotificationManager>(new LanguageServerNotificationManager(_jsonRpc)), CreateLspServiceInstance(logger), CreateLspServiceInstance <IClientCapabilitiesProvider>(this))); _queue = new RequestExecutionQueue( supportedLanguages, serverKind, _lspServices); _queue.RequestServerShutdown += RequestExecutionQueue_Errored; _requestDispatcher = _lspServices.GetRequiredService <RequestDispatcher>(); var entryPointMethod = typeof(DelegatingEntryPoint).GetMethod(nameof(DelegatingEntryPoint.EntryPointAsync)); Contract.ThrowIfNull(entryPointMethod, $"{typeof(DelegatingEntryPoint).FullName} is missing method {nameof(DelegatingEntryPoint.EntryPointAsync)}"); foreach (var metadata in _requestDispatcher.GetRegisteredMethods()) { // Instead of concretely defining methods for each LSP method, we instead dynamically construct the // generic method info from the exported handler types. This allows us to define multiple handlers for // the same method but different type parameters. This is a key functionality to support TS external // access as we do not want to couple our LSP protocol version dll to theirs. // // We also do not use the StreamJsonRpc support for JToken as the rpc method parameters because we want // StreamJsonRpc to do the deserialization to handle streaming requests using IProgress<T>. var delegatingEntryPoint = new DelegatingEntryPoint(metadata.MethodName, this); var genericEntryPointMethod = entryPointMethod.MakeGenericMethod(metadata.RequestType, metadata.ResponseType); _jsonRpc.AddLocalRpcMethod(genericEntryPointMethod, delegatingEntryPoint, new JsonRpcMethodAttribute(metadata.MethodName) { UseSingleObjectParameterDeserialization = true }); }
static async Task Main(string[] args) { Console.WriteLine("Kurento Echo Test Client"); logger = AddConsoleLogger(); CancellationTokenSource cts = new CancellationTokenSource(); var ws = new ClientWebSocket(); await ws.ConnectAsync(new Uri(KURENTO_JSONRPC_URL), cts.Token); logger.LogDebug($"Successfully connected web socket client to {KURENTO_JSONRPC_URL}."); try { using (var jsonRpc = new JsonRpc(new WebSocketMessageHandler(ws))) { jsonRpc.AddLocalRpcMethod("ping", new Action(() => { logger.LogDebug($"Ping received"); } )); jsonRpc.AddLocalRpcMethod("onEvent", new Action <KurentoEvent>((evt) => { logger.LogDebug($"Event received type={evt.type}, source={evt.data.source}"); } )); jsonRpc.StartListening(); // Check the server is there. var pingResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.ping.ToString(), new { interval = KEEP_ALIVE_INTERVAL_MS }, cts.Token); logger.LogDebug($"Ping result={pingResult.value}."); // Create a media pipeline. var createPipelineResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.create.ToString(), new { type = "MediaPipeline" }, cts.Token); logger.LogDebug($"Create media pipeline result={createPipelineResult.value}, sessionID={createPipelineResult.sessionId}."); var sessionID = createPipelineResult.sessionId; var mediaPipeline = createPipelineResult.value; // Create a WebRTC end point. var createEndPointResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.create.ToString(), new { type = "WebRtcEndpoint", constructorParams = new { mediaPipeline = mediaPipeline }, sessionId = sessionID }, cts.Token); logger.LogDebug($"Create WebRTC endpoint result={createEndPointResult.value}."); var webRTCEndPointID = createEndPointResult.value; // Connect the WebRTC end point to itself to create a loopback connection (no result for this operation). await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.invoke.ToString(), new { @object = webRTCEndPointID, operation = "connect", operationParams = new { sink = webRTCEndPointID }, sessionId = sessionID }, cts.Token); // Subscribe for events from the WebRTC end point. var subscribeResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.subscribe.ToString(), new { @object = webRTCEndPointID, type = "IceCandidateFound", sessionId = sessionID }, cts.Token); logger.LogDebug($"Subscribe to WebRTC endpoint subscription ID={subscribeResult.value}."); var subscriptionID = subscribeResult.value; subscribeResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.subscribe.ToString(), new { @object = webRTCEndPointID, type = "OnIceCandidate", sessionId = sessionID }, cts.Token); logger.LogDebug($"Subscribe to WebRTC endpoint subscription ID={subscribeResult.value}."); var pc = CreatePeerConnection(); var offer = pc.createOffer(null); await pc.setLocalDescription(offer); // Send SDP offer. var processOfferResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.invoke.ToString(), new { @object = webRTCEndPointID, operation = "processOffer", operationParams = new { offer = offer.sdp }, sessionId = sessionID }, cts.Token); logger.LogDebug($"SDP answer={processOfferResult.value}."); var setAnswerResult = pc.setRemoteDescription(new RTCSessionDescriptionInit { type = RTCSdpType.answer, sdp = processOfferResult.value }); logger.LogDebug($"Set WebRTC peer connection answer result={setAnswerResult}."); // Tell Kurento to start ICE. var gatherCandidatesResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.invoke.ToString(), new { @object = webRTCEndPointID, operation = "gatherCandidates", sessionId = sessionID }, cts.Token); logger.LogDebug($"Gather candidates result={gatherCandidatesResult.value}."); Console.ReadLine(); } } catch (RemoteInvocationException invokeExcp) { logger.LogError($"JSON RPC invoke exception, error code={invokeExcp.ErrorCode}, msg={invokeExcp.Message}."); } }
/// <summary> /// Connects to the snapserver and sets up local RPC methods /// </summary> /// <param name="ip">IP address to connect to</param> /// <param name="port">port to connect on</param> /// <returns></returns> public async Task ConnectAsync(string ip, int port, int timeout = 3000) { // connect m_Ip = ip; m_Port = port; ConnectionFailed = false; ServerData = null; m_TcpClient = new TcpClient(); try { //if (m_TcpClient.ConnectAsync(ip, port).Wait(timeout) == false) var connectAsync = m_TcpClient.ConnectAsync(ip, port); //await (m_TcpClient.ConnectAsync(ip, port)). if ((await Task.WhenAny(connectAsync, Task.Delay(timeout)) != connectAsync) || string.IsNullOrEmpty(ip)) { _HandleConnectionFailure(); return; } } catch (Exception e) { // logging this to debug because we don't want to spam the log file (connection gets retried indefinitely if it had previously succeeded) Debug("Connect exception: ", e.Message); _HandleConnectionFailure(); return; } if (m_TcpClient.Connected == false) { _HandleConnectionFailure(); return; } // attach StreamJsonRpc (NewLineDelimited) m_Stream = m_TcpClient.GetStream(); // UnbatchingNewLineDelimitedMessageHandler adapted from UnbatchingWebSocketMessageHandler // https://github.com/microsoft/vs-streamjsonrpc/compare/master...AArnott:sampleUnbatchingMessageHandler m_JsonRpc = new StreamJsonRpc.JsonRpc(new UnbatchingNewLineDelimitedMessageHandler(m_Stream, m_Stream)); //m_JsonRpc.TraceSource.Switch.Level = SourceLevels.All; // uncomment if you need detailed json-rpc logs // register methods (must be done before listening starts) m_JsonRpc.AddLocalRpcMethod("Server.OnUpdate", new Action <JsonRpcData.ServerData>((server) => { Debug("Received Server.OnUpdate - {0}", server); _ServerUpdated(server); })); m_JsonRpc.AddLocalRpcMethod("Client.OnVolumeChanged", new Action <string, JsonRpcData.Volume>((id, volume) => { Debug("Received Client.OnVolumeChanged - id {0}, volume {1}", id, volume); _ClientVolumeChanged(id, volume); })); m_JsonRpc.AddLocalRpcMethod("Client.OnNameChanged", new Action <string, string>((id, name) => { Debug("Received Client.OnNameChanged - id {0}, name {1}", id, name); _ClientNameChanged(id, name); })); m_JsonRpc.AddLocalRpcMethod("Client.OnLatencyChanged", new Action <string, int>((id, latency) => { Debug("Received Client.OnLatencyChanged - id {0}, latency {1}", id, latency); _ClientLatencyChanged(id, latency); })); m_JsonRpc.AddLocalRpcMethod("Client.OnConnect", new Action <string, JsonRpcData.Client>((id, client) => { // when the server's been down, we keep trying to reconnect (as does every other client) // when reconnection succeeds, we might see other clients' OnConnect calls come in // before our own Server.GetStatus has completed. In that case, we queue these // and execute them as soon as we've received the server data Debug("Received Client.OnConnect - id {0}, client {1}", id, client); if (ServerData != null) { _ClientConnectedOrDisconnected(id, client); } else { m_QueuedMessages.Enqueue(() => { _ClientConnectedOrDisconnected(id, client); }); } })); m_JsonRpc.AddLocalRpcMethod("Client.OnDisconnect", new Action <string, JsonRpcData.Client>((id, client) => { Debug("Received Client.OnDisconnect - id {0}, client {1}", id, client); _ClientConnectedOrDisconnected(id, client); })); m_JsonRpc.AddLocalRpcMethod("Group.OnMute", new Action <string, bool>((id, mute) => { Debug("Received Group.OnMute - id {0}, mute {1}", id, mute); _GroupMuteChanged(id, mute); })); m_JsonRpc.AddLocalRpcMethod("Group.OnNameChanged", new Action <string, string>((id, name) => { Debug("Received Group.OnNameChanged - id {0}, name {1}", id, name); _GroupNameChanged(id, name); })); m_JsonRpc.AddLocalRpcMethod("Group.OnStreamChanged", new Action <string, string>((id, stream_id) => { Debug("Received Group.OnStreamChanged - id {0}, stream_id {1}", id, stream_id); _GroupStreamChanged(id, stream_id); })); m_JsonRpc.AddLocalRpcMethod("Stream.OnUpdate", new Action <string, Stream>((id, stream) => { Debug("Received Stream.OnUpdate - id {0}, stream {1}", id, stream); _StreamUpdated(id, stream); })); m_JsonRpc.AddLocalRpcMethod("Stream.OnProperties", new Action <string, Properties>((id, properties) => { Debug("Received Stream.OnProperties - id {0}, properties {1}", id, properties); _StreamPropertiesUpdated(id, properties); })); m_JsonRpc.StartListening(); // call Server.GetStatus to get all metadata await GetServerStatusAsync(); // make sure we find out if connection drops _StartReconnectLoop(); }
private async static Task OfferAsync(IHttpContext context) { var offer = await context.GetRequestDataAsync <RTCSessionDescriptionInit>(); logger.LogDebug($"SDP Offer={offer.sdp}"); var jsonOptions = new JsonSerializerOptions(); jsonOptions.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter()); CancellationTokenSource cts = new CancellationTokenSource(); var ws = new ClientWebSocket(); await ws.ConnectAsync(new Uri(KURENTO_JSONRPC_URL), cts.Token); logger.LogDebug($"Successfully connected web socket client to {KURENTO_JSONRPC_URL}."); try { using (var jsonRpc = new JsonRpc(new WebSocketMessageHandler(ws))) { jsonRpc.AddLocalRpcMethod("ping", new Action(() => { logger.LogDebug($"Ping received"); } )); jsonRpc.AddLocalRpcMethod("onEvent", new Action <KurentoEvent>((evt) => { logger.LogDebug($"Event received type={evt.type}, source={evt.data.source}"); } )); jsonRpc.StartListening(); // Check the server is there. var pingResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.ping.ToString(), new { interval = KEEP_ALIVE_INTERVAL_MS }, cts.Token); logger.LogDebug($"Ping result={pingResult.value}."); // Create a media pipeline. var createPipelineResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.create.ToString(), new { type = "MediaPipeline" }, cts.Token); logger.LogDebug($"Create media pipeline result={createPipelineResult.value}, sessionID={createPipelineResult.sessionId}."); var sessionID = createPipelineResult.sessionId; var mediaPipeline = createPipelineResult.value; // Create a WebRTC end point. var createEndPointResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.create.ToString(), new { type = "WebRtcEndpoint", constructorParams = new { mediaPipeline = mediaPipeline }, sessionId = sessionID }, cts.Token); logger.LogDebug($"Create WebRTC endpoint result={createEndPointResult.value}."); var webRTCEndPointID = createEndPointResult.value; // Connect the WebRTC end point to itself to create a loopback connection (no result for this operation). await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.invoke.ToString(), new { @object = webRTCEndPointID, operation = "connect", operationParams = new { sink = webRTCEndPointID }, sessionId = sessionID }, cts.Token); // Subscribe for events from the WebRTC end point. var subscribeResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.subscribe.ToString(), new { @object = webRTCEndPointID, type = "IceCandidateFound", sessionId = sessionID }, cts.Token); logger.LogDebug($"Subscribe to WebRTC endpoint subscription ID={subscribeResult.value}."); var subscriptionID = subscribeResult.value; subscribeResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.subscribe.ToString(), new { @object = webRTCEndPointID, type = "OnIceCandidate", sessionId = sessionID }, cts.Token); logger.LogDebug($"Subscribe to WebRTC endpoint subscription ID={subscribeResult.value}."); // Send SDP offer. var processOfferResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.invoke.ToString(), new { @object = webRTCEndPointID, operation = "processOffer", operationParams = new { offer = offer.sdp }, sessionId = sessionID }, cts.Token); logger.LogDebug($"SDP answer={processOfferResult.value}."); RTCSessionDescriptionInit answerInit = new RTCSessionDescriptionInit { type = RTCSdpType.answer, sdp = processOfferResult.value }; context.Response.ContentType = "application/json"; using (var responseStm = context.OpenResponseStream(false, false)) { await JsonSerializer.SerializeAsync(responseStm, answerInit, jsonOptions); } // Tell Kurento to start ICE. var gatherCandidatesResult = await jsonRpc.InvokeWithParameterObjectAsync <KurentoResult>( KurentoMethodsEnum.invoke.ToString(), new { @object = webRTCEndPointID, operation = "gatherCandidates", sessionId = sessionID }, cts.Token); logger.LogDebug($"Gather candidates result={gatherCandidatesResult.value}."); } } catch (RemoteInvocationException invokeExcp) { logger.LogError($"JSON RPC invoke exception, error code={invokeExcp.ErrorCode}, msg={invokeExcp.Message}."); } }