public TransactionQueue(string serverName, string connectionString, SigningKey key, IConfigurationSection clientConfig ) { _client = new FederationClient(serverName, key, clientConfig); _userPresence = new Dictionary <string, PresenceState>(); _destOngoingTrans = new Dictionary <string, Task>(); _destPendingTransactions = new Dictionary <string, Transaction>(); _destLastDeviceMsgStreamId = new Dictionary <string, long>(); _destLastDeviceListStreamId = new Dictionary <string, long>(); _presenceProcessing = Task.CompletedTask; _eventsProcessing = Task.CompletedTask; _serverName = serverName; _txnId = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; _connString = connectionString; _lastEventPoke = -1; _signingKey = key; _backoff = new Backoff(); var txConcurrency = clientConfig.GetValue <int>("maxConcurrency"); if (txConcurrency == 0) { txConcurrency = 100; } concurrentTransactionLock = new SemaphoreSlim(txConcurrency, txConcurrency); }
public FederationClient(string serverName, SigningKey key, IConfigurationSection config) { origin = serverName; client = new HttpClient(new HttpClientHandler { ServerCertificateCustomValidationCallback = ServerCertificateValidationCallback }); client.Timeout = TimeSpan.FromSeconds(30); this.key = key; destinationUris = new Dictionary <string, Uri>(); hostResolver = new HostResolver(config.GetValue <bool>("defaultToSecurePort") ? 8448 : 8008); allowSelfSigned = config.GetValue <bool>("allowSelfSigned"); }
public async Task Start() { log.Information("Starting FederationWorker"); _synapseReplication = new SynapseReplication(); _synapseReplication.ClientName = "NetCoreFederationWorker"; _synapseReplication.ServerName += Replication_ServerName; var synapseConfig = _config.GetSection("Synapse"); key = SigningKey.ReadFromFile(synapseConfig.GetValue <string>("signingKeyPath")); connectionString = _config.GetConnectionString("synapse"); _presenceEnabled = synapseConfig.GetValue("presenceEnabled", true); await _synapseReplication.Connect(synapseConfig.GetValue <string>("replicationHost"), synapseConfig.GetValue <int>("replicationPort")); _fedStream = _synapseReplication.BindStream <FederationStreamRow>(); _fedStream.DataRow += OnFederationRow; _eventStream = _synapseReplication.BindStream <EventStreamRow>(); _eventStream.PositionUpdate /**/ += OnEventPositionUpdate; _stream_position = await GetFederationPos("federation"); }
public async Task SendTransaction(Transaction transaction) { var record = await hostResolver.GetHostRecord(transaction.destination); var uri = new UriBuilder(record.GetUri()) { Path = $"/_matrix/federation/v1/send/{transaction.transaction_id}/", Scheme = "https" }; var msg = new HttpRequestMessage { Method = HttpMethod.Put, RequestUri = uri.Uri }; msg.Headers.Host = record.GetHost(); var body = SigningKey.SortPropertiesAlphabetically(JObject.FromObject(transaction)); SignRequest(msg, transaction.destination, body); var json = JsonConvert.SerializeObject(body, Formatting.None); var content = new StringContent(json, Encoding.UTF8, "application/json"); msg.Content = content; HttpResponseMessage resp; var sw = new Stopwatch(); try { log.Information("[TX] {destination} PUT {uri} Host={hostHeader} PDUs={pduCount} EDUs={eduCount}" , transaction.destination, uri, msg.Headers.Host, transaction.pdus.Count, transaction.edus.Count); sw.Start(); resp = await client.SendAsync(msg); } catch (HttpRequestException ex) { //TODO: This is probably a little extreme. log.Warning("Failed to reach {destination} {message}", transaction.destination, ex.Message); destinationUris.Remove(transaction.destination); throw; } finally { sw.Stop(); } log.Information("[TX] {destination} Response: {statusCode} {timeTaken}ms", transaction.destination, resp.StatusCode, sw.ElapsedMilliseconds); if (resp.IsSuccessStatusCode) { return; } if (resp.StatusCode == HttpStatusCode.NotFound) { destinationUris.Remove(transaction.destination); } // TODO: Should we drop well known for other reasons? var error = await resp.Content.ReadAsStringAsync(); var err = JObject.Parse(error); if (resp.StatusCode == HttpStatusCode.Unauthorized) { try { var errCode = (string)err["errcode"]; var errorString = (string)err["error"]; if (errCode == "M_UNAUTHORIZED" && errorString.StartsWith("Invalid signature")) { log.Information("Got invalid signature, debug info:"); log.Information("Auth: {auth}\nBody: {body}", msg.Headers.Authorization.Parameter, body.ToString(Formatting.Indented)); } } catch { // ignored } } throw new TransactionFailureException(transaction.destination, resp.StatusCode, err); }