public async Task <byte[]?> Execute(RpcMethod method, RpcPeerInfo callingPeer)
        {
            await Task.Delay(delaysMs[callIndex % delaysMs.Count]);

            callIndex++;
            return(new byte[] { 42 });
        }
        public async Task <byte[]?> Execute(RpcMethod method, RpcPeerInfo callingPeer)
        {
            var  div = Div.FromMethod(method);
            byte ret = (byte)(div.dividend / div.divisor);  // Yes, may throw div/0 exception

            return(await Task.FromResult(new byte[] { ret }));
        }
Example #3
0
        /// <summary>
        /// Creates a new channel with the given information, already established connection,
        /// and optionally the given backlog.
        /// </summary>
        public static async Task <RpcChannel> Create(RpcPeerInfo remoteInfo, IRpcConnection connection,
                                                     IRpcMethodExecutor executor, IRpcBacklog?backlog = null)
        {
            var ret = new RpcChannel(remoteInfo, connection, executor);

            ret.callsQueue = await RpcQueue.Create(remoteInfo.PeerID, backlog);

            return(ret);
        }
Example #4
0
        public override async Task Start()
        {
            while (false == stopper.IsCancellationRequested)
            {
                ClientWebSocket?webSocket = null;
                try {
                    webSocket = new ClientWebSocket();
                    auth.Authenticate(webSocket);
                    await webSocket.ConnectAsync(new Uri(ServerUrl), stopper.Token);

                    Log.Debug($"Connection to server established");
                    serverInfo = RpcPeerInfo.Server(ServerUrl);
                    var connection = new WebSocketRpcConnection(serverInfo, webSocket);
                    channel = await RpcChannel.Create(serverInfo, connection, this, Settings.Backlog);

                    await channel.Start();

                    Log.Debug($"Connection to server closed");
                } catch (Exception ex) {
                    if ((ex as WebSocketException)?.Message.Contains("401") ?? false)
                    {
                        Log.Debug($"Connection to server denied: Unauthorized");
                    }
                    else if (ex is WebSocketException wsEx)
                    {
                        Log.Debug($"Connection to server unexpectedly closed: " + wsEx.WebSocketErrorCode);
                    }
                    else
                    {
                        Log.Debug($"Connection to server unexpectedly closed: " + ex.Message);
                    }
                } finally {
                    webSocket?.Dispose();
                }

                if (false == stopper.IsCancellationRequested)
                {
                    // Reconnect
                    Log.Info($"Trying to reconnect after {Settings.ReconnectTimeMs} ms");
                    await Task.Delay(Settings.ReconnectTimeMs);

                    if (Settings.ReconnectTimeMs >= 30_000) // Repeat logging after a long pause
                    {
                        Log.Info($"Trying to reconnect now");
                    }
                }
            }
        }
Example #5
0
 protected override RpcContext CreateRpcContext(RpcPeerInfo callingPeer) =>
 RpcContext.OnClient(callingPeer);
Example #6
0
        private async Task ProcessClient(HttpListenerContext httpContext)
        {
            string ip = httpContext.GetIP();

            // Check authentication
            var authResult = auth.Authenticate(httpContext.Request);

            if (false == authResult.Success || authResult.ClientID == null)
            {
                Log.Debug($"Connection from {ip} denied" +
                          (authResult.ClientID != null ? $" (client ID {authResult.ClientID})" : ""));
                httpContext.Close(HttpStatusCode.Unauthorized);
                return;
            }
            string clientID = authResult.ClientID;

            // Accept web socket
            var clientInfo = RpcPeerInfo.Client(clientID, ip);
            WebSocketContext context;

            try {
                context = await httpContext.AcceptWebSocketAsync(subProtocol : null);

                Log.Debug($"Connected {clientInfo}");
            } catch (Exception ex) {
                Log.Debug($"Could not accept WebSocket to {clientInfo}: {ex.Message}");
                httpContext.Close(HttpStatusCode.InternalServerError);
                return;
            }

            // WebSocket loop
            WebSocket webSocket = context.WebSocket;

            try {
                var connection = new WebSocketRpcConnection(clientInfo, webSocket);
                var channel    = await RpcChannel.Create(clientInfo, connection, this, Settings.Backlog);

                if (channelsByClientID.TryGetValue(clientID, out var oldChannel))
                {
                    Log.Debug($"Channel for client {clientID} was already open; close it and open a new one after 3 seconds.");
                    oldChannel.Stop();
                    await Task.Delay(3000);
                }
                channelsByClientID[clientID] = channel;
                await channel.Start();

                Log.Debug($"Connection to {clientInfo} closed");
            } catch (Exception ex) {
                if (ex is WebSocketException wsEx)
                {
                    Log.Debug($"Connection to {clientInfo} unexpectedly closed: " + wsEx.WebSocketErrorCode);
                }
                else
                {
                    Log.Debug($"Connection to {clientInfo} unexpectedly closed: " + ex.Message);
                }
            } finally {
                webSocket?.Dispose();
            }
            channelsByClientID.Remove(clientID);
        }
Example #7
0
 protected override RpcContext CreateRpcContext(RpcPeerInfo callingPeer) =>
 RpcContext.OnServer(callingPeer,
                     channelsByClientID.Values.Select(it => it.RemotePeer).ToList());
Example #8
0
 public WebSocketRpcConnection(RpcPeerInfo remoteInfo, WebSocket webSocket)
 {
     this.remoteInfo = remoteInfo;
     this.webSocket  = webSocket;
 }
Example #9
0
 public RpcContext(RpcPeerInfo remotePeer, List <RpcPeerInfo>?clients)
 {
     RemotePeer = remotePeer;
     Clients    = clients;
 }
Example #10
0
 public static RpcContext OnServer(RpcPeerInfo clientPeer, List <RpcPeerInfo> clients) =>
 new RpcContext(clientPeer, clients);
Example #11
0
 public static RpcContext OnClient(RpcPeerInfo serverPeer) =>
 new RpcContext(serverPeer, clients: null);
Example #12
0
 public Task <byte[]?> Execute(RpcMethod method, RpcPeerInfo callingPeer) =>
 Task.FromResult((byte[]?)new byte[] { 42 });
Example #13
0
 /// <summary>
 /// Use <see cref="Create"/> for creating new instances.
 /// </summary>
 private RpcChannel(RpcPeerInfo remotePeer, IRpcConnection connection, IRpcMethodExecutor executor)
 {
     RemotePeer      = remotePeer;
     this.connection = connection;
     this.executor   = executor;
 }