protected abstract Task OnRequestAsync(StratumClient <TClientContext> client, Timestamped <JsonRpcRequest> request);
protected virtual void OnReceiveComplete(StratumClient <TClientContext> client) { logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] Received EOF"); DisconnectClient(client); }
protected abstract void OnConnect(StratumClient <TClientContext> client);
private void OnClientConnected(Tcp con, IPEndPoint endpointConfig, Loop loop) { try { var remoteEndPoint = con.GetPeerEndPoint(); // get rid of banned clients as early as possible if (banManager?.IsBanned(remoteEndPoint.Address) == true) { logger.Trace(() => $"[{LogCat}] Disconnecting banned ip {remoteEndPoint.Address}"); con.Dispose(); return; } var connectionId = CorrelationIdGenerator.GetNextId(); logger.Trace(() => $"[{LogCat}] Accepting connection [{connectionId}] from {remoteEndPoint.Address}:{remoteEndPoint.Port}"); // setup client var client = new StratumClient <TClientContext>(); client.Init(loop, con, ctx, endpointConfig, connectionId); // request subscription var sub = client.Requests .Do(x => logger.Trace(() => $"[{LogCat}] [{client.ConnectionId}] Received request {x.Value.Method} [{x.Value.Id}]")) .Select(tsRequest => Observable.FromAsync(() => Task.Run(() => // get off of LibUV event-loop-thread immediately { var request = tsRequest.Value; logger.Trace(() => $"[{LogCat}] [{client.ConnectionId}] Dispatching request {request.Method} [{request.Id}]"); try { // boot pre-connected clients if (banManager?.IsBanned(client.RemoteEndpoint.Address) == true) { logger.Trace(() => $"[{LogCat}] [{connectionId}] Disconnecting banned client @ {remoteEndPoint.Address}"); DisconnectClient(client); return; } OnRequestAsync(client, tsRequest).Wait(); } catch (Exception ex) { logger.Error(ex, () => $"Error handling request: {request.Method}"); } }))) .Concat() .Subscribe(_ => { }, ex => OnReceiveError(client, ex), () => OnReceiveComplete(client)); // ensure subscription is disposed on loop thread var disposer = loop.CreateAsync((handle) => { sub.Dispose(); handle.Dispose(); }); client.Subscription = Disposable.Create(() => { disposer.Send(); }); // register client lock (clients) { clients[connectionId] = client; } OnConnect(client); } catch (Exception ex) { logger.Error(ex, () => nameof(OnClientConnected)); } }