diff --git a/Centaurus.Common/Settings/Settings.cs b/Centaurus.Common/Settings/Settings.cs index 80408327..f7e63c11 100644 --- a/Centaurus.Common/Settings/Settings.cs +++ b/Centaurus.Common/Settings/Settings.cs @@ -38,6 +38,9 @@ public abstract class BaseSettings [Option("connection_string", Required = true, HelpText = "Database connection string.")] public string ConnectionString { get; set; } + [Option("extensions_config_file_path", Required = false, HelpText = "Path to extensions config file.")] + public string ExtensionsConfigFilePath { get; set; } + public virtual void Build() { KeyPair = KeyPair.FromSecretSeed(Secret); diff --git a/Centaurus.DAL/Mongo/MongoStorage.cs b/Centaurus.DAL/Mongo/MongoStorage.cs index 85fc31eb..6d133463 100644 --- a/Centaurus.DAL/Mongo/MongoStorage.cs +++ b/Centaurus.DAL/Mongo/MongoStorage.cs @@ -202,17 +202,23 @@ public override async Task Update(DiffObject update) if (update.StellarInfoData != null) updateTasks.Add(constellationStateCollection.BulkWriteAsync(GetStellarDataUpdate(update.StellarInfoData))); - updateTasks.Add(accountsCollection.BulkWriteAsync(GetAccountUpdates(update.Accounts))); + if (update.Accounts != null && update.Accounts.Count > 0) + updateTasks.Add(accountsCollection.BulkWriteAsync(GetAccountUpdates(update.Accounts))); - updateTasks.Add(balancesCollection.BulkWriteAsync(GetBalanceUpdates(update.Balances))); + if (update.Balances != null && update.Balances.Count > 0) + updateTasks.Add(balancesCollection.BulkWriteAsync(GetBalanceUpdates(update.Balances))); - updateTasks.Add(ordersCollection.BulkWriteAsync(GetOrderUpdates(update.Orders))); + if (update.Orders != null && update.Orders.Count > 0) + updateTasks.Add(ordersCollection.BulkWriteAsync(GetOrderUpdates(update.Orders))); - updateTasks.Add(withdrawalsCollection.BulkWriteAsync(GetWithdrawalsUpdates(update.Widthrawals))); + if (update.Widthrawals != null && update.Widthrawals.Count > 0) + updateTasks.Add(withdrawalsCollection.BulkWriteAsync(GetWithdrawalsUpdates(update.Widthrawals))); updateTasks.Add(quantaCollection.InsertManyAsync(update.Quanta)); updateTasks.Add(effectsCollection.InsertManyAsync(update.Effects)); + await Task.WhenAll(updateTasks); + await session.CommitTransactionAsync(); } catch diff --git a/Centaurus.Domain/Catchups/AlphaCatchup.cs b/Centaurus.Domain/Catchups/AlphaCatchup.cs index 89ccc872..0d98abbd 100644 --- a/Centaurus.Domain/Catchups/AlphaCatchup.cs +++ b/Centaurus.Domain/Catchups/AlphaCatchup.cs @@ -82,7 +82,7 @@ private static async Task ApplyAuditorsData() alphaStateManager.AlphaRised(); - Notifier.NotifyAuditors(alphaStateManager.GetCurrentAlphaState()); + Notifier.NotifyAuditors(alphaStateManager.GetCurrentAlphaState().CreateEnvelope()); } private static async Task ApplyQuanta(List quanta) diff --git a/Centaurus.Domain/Effects/EffectProcessorsContainer.cs b/Centaurus.Domain/Effects/EffectProcessorsContainer.cs index bf6c4d08..cae4d4a1 100644 --- a/Centaurus.Domain/Effects/EffectProcessorsContainer.cs +++ b/Centaurus.Domain/Effects/EffectProcessorsContainer.cs @@ -208,5 +208,13 @@ public void AddNonceUpdate(Account account, ulong newNonce, ulong currentNonce) account )); } + + public void AddLedgerCommit(LedgerManager ledgerManager, long newLedger, long prevLedger) + { + Add(new LedgerUpdateEffectProcessor( + new LedgerUpdateEffect { Apex = Apex, Ledger = newLedger, PrevLedger = prevLedger }, + ledgerManager + )); + } } } diff --git a/Centaurus.Domain/Effects/LedgerUpdateEffectProcessor.cs b/Centaurus.Domain/Effects/LedgerUpdateEffectProcessor.cs index a516cd0a..5c0be4f4 100644 --- a/Centaurus.Domain/Effects/LedgerUpdateEffectProcessor.cs +++ b/Centaurus.Domain/Effects/LedgerUpdateEffectProcessor.cs @@ -26,18 +26,5 @@ public override void RevertEffect() MarkAsProcessed(); ledgerManager.SetLedger(Effect.PrevLedger); } - - public static LedgerUpdateEffectProcessor GetProcessor(long apex, long ledger, LedgerManager ledgerManager) - { - return GetProcessor( - new LedgerUpdateEffect { Apex = apex, Ledger = ledger, PrevLedger = ledgerManager.Ledger }, - ledgerManager - ); - } - - public static LedgerUpdateEffectProcessor GetProcessor(LedgerUpdateEffect effect, LedgerManager ledgerManager) - { - return new LedgerUpdateEffectProcessor(effect, ledgerManager); - } } } diff --git a/Centaurus.Domain/Extensions/ExtensionConfig.cs b/Centaurus.Domain/Extensions/ExtensionConfig.cs new file mode 100644 index 00000000..eec5fc6e --- /dev/null +++ b/Centaurus.Domain/Extensions/ExtensionConfig.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Centaurus.Domain +{ + public class ExtensionConfig + { + public List Extensions { get; set; } + } +} diff --git a/Centaurus.Domain/Extensions/ExtensionConfigItem.cs b/Centaurus.Domain/Extensions/ExtensionConfigItem.cs new file mode 100644 index 00000000..4ffb9be0 --- /dev/null +++ b/Centaurus.Domain/Extensions/ExtensionConfigItem.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Centaurus.Domain +{ + public class ExtensionConfigItem + { + public bool IsDisabled { get; set; } + + public string Name { get; set; } + + public Dictionary ExtensionConfig { get; set; } + } +} diff --git a/Centaurus.Domain/Extensions/ExtensionItem.cs b/Centaurus.Domain/Extensions/ExtensionItem.cs new file mode 100644 index 00000000..90cb89b8 --- /dev/null +++ b/Centaurus.Domain/Extensions/ExtensionItem.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Centaurus.Domain +{ + public class ExtensionItem + { + private ExtensionItem(string name, Version version, Dictionary config, IExtension extensionInstance) + { + Name = name; + Version = version; + ExtensionInstance = extensionInstance; + Config = config; + } + + public string Name { get; } + + public Version Version { get; } + + public IExtension ExtensionInstance { get; } + + public Dictionary Config { get; } + + public static ExtensionItem Load(ExtensionConfigItem extensionConfigItem) + { + var extensionPath = Path.Combine(Path.GetDirectoryName(Global.Settings.ExtensionsConfigFilePath), extensionConfigItem.Name + ".dll"); + if (!File.Exists(extensionPath)) + throw new Exception($"Extension {extensionConfigItem.Name} is not found."); + var extensionAssenmbly = Assembly.LoadFile(extensionPath); + var extensionTypes = extensionAssenmbly.GetTypes().Where(t => typeof(IExtension).IsAssignableFrom(t)); + if (extensionTypes.Count() < 1) + throw new Exception($"Extension {extensionConfigItem.Name} doesn't contain types that implement IExtension interface."); + else if (extensionTypes.Count() > 1) + throw new Exception($"Extension {extensionConfigItem.Name} contains multiple types that implement IExtension interface."); + + return new ExtensionItem(extensionConfigItem.Name, extensionAssenmbly.GetName().Version, extensionConfigItem.ExtensionConfig, (IExtension)Activator.CreateInstance(extensionTypes.First())); + } + } +} diff --git a/Centaurus.Domain/Extensions/ExtensionsManager.cs b/Centaurus.Domain/Extensions/ExtensionsManager.cs new file mode 100644 index 00000000..fb239657 --- /dev/null +++ b/Centaurus.Domain/Extensions/ExtensionsManager.cs @@ -0,0 +1,149 @@ +using Centaurus.Models; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.WebSockets; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace Centaurus.Domain +{ + public class EnvelopeEventArgs + { + public BaseWebSocketConnection Connection { get; set; } + + public MessageEnvelope Message { get; set; } + + } + + public class EnvelopeErrorEventArgs : EnvelopeEventArgs + { + public Exception Exception { get; set; } + } + + public class NotifyEventArgs + { + public RawPubKey Account { get; set; } + public MessageEnvelope Envelope { get; set; } + } + + public class ExtensionsManager + { + public async Task RegisterAllExtensions() + { + if (string.IsNullOrWhiteSpace(Global.Settings.ExtensionsConfigFilePath)) + return; + + var configFilePath = Path.GetFullPath(Global.Settings.ExtensionsConfigFilePath); + if (!File.Exists(configFilePath)) + throw new Exception("Extensions config file is not found."); + + var extensionConfig = JsonConvert.DeserializeObject(File.ReadAllText(configFilePath)); + + foreach (var configItem in extensionConfig.Extensions) + { + var extension = ExtensionItem.Load(configItem); + await extension.ExtensionInstance.Init(configItem.ExtensionConfig); + + extensions.Add(extension); + } + } + + private List extensions = new List(); + + public IEnumerable Extensions => extensions; + + public event EventHandler OnBeforeNewConnection; + public event EventHandler OnConnectionValidated; + public void ConnectionValidated(BaseWebSocketConnection args) + { + OnConnectionValidated?.Invoke(this, args); + } + public void BeforeNewConnection(WebSocket args) + { + OnBeforeNewConnection?.Invoke(this, args); + } + + public event EventHandler OnHandleMessageFailed; + public void HandleMessageFailed(EnvelopeErrorEventArgs args) + { + OnHandleMessageFailed?.Invoke(this, args); + } + + public event EventHandler OnBeforeSendMessage; + public event EventHandler OnAfterSendMessage; + public event EventHandler OnSendMessageFailed; + public void BeforeSendMessage(EnvelopeEventArgs args) + { + OnBeforeSendMessage?.Invoke(this, args); + } + public void AfterSendMessage(EnvelopeEventArgs args) + { + OnAfterSendMessage?.Invoke(this, args); + } + public void SendMessageFailed(EnvelopeErrorEventArgs args) + { + OnSendMessageFailed?.Invoke(this, args); + } + + public event EventHandler OnBeforeConnectionClose; + + public void BeforeConnectionClose(BaseWebSocketConnection args) + { + OnBeforeConnectionClose?.Invoke(this, args); + } + + public event EventHandler OnBeforeNotify; + public event EventHandler OnBeforeNotifyAuditors; + + + public void BeforeNotify(NotifyEventArgs args) + { + OnBeforeNotify?.Invoke(this, args); + } + + public void BeforeNotifyAuditors(MessageEnvelope args) + { + OnBeforeNotifyAuditors?.Invoke(this, args); + } + + public event EventHandler OnBeforeValidateMessage; + public event EventHandler OnAfterValidateMessage; + public event EventHandler OnBeforeHandleMessage; + public event EventHandler OnAfterHandleMessage; + + public void BeforeValidateMessage(EnvelopeEventArgs args) + { + OnBeforeValidateMessage?.Invoke(this, args); + } + + public void AfterValidateMessage(EnvelopeEventArgs args) + { + OnAfterValidateMessage?.Invoke(this, args); + } + + public void BeforeHandleMessage(EnvelopeEventArgs args) + { + OnBeforeHandleMessage?.Invoke(this, args); + } + + public void AfterHandleMessage(EnvelopeEventArgs args) + { + OnAfterHandleMessage?.Invoke(this, args); + } + + public event EventHandler OnBeforeQuantumHandle; + public event EventHandler OnAfterQuantumHandle; + public void BeforeQuantumHandle(MessageEnvelope args) + { + OnBeforeQuantumHandle?.Invoke(this, args); + } + + public void AfterQuantumHandle(ResultMessage args) + { + OnAfterQuantumHandle?.Invoke(this, args); + } + } +} diff --git a/Centaurus.Domain/Extensions/IExtension.cs b/Centaurus.Domain/Extensions/IExtension.cs new file mode 100644 index 00000000..951cf0f8 --- /dev/null +++ b/Centaurus.Domain/Extensions/IExtension.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Centaurus.Domain +{ + public interface IExtension + { + Task Init(Dictionary settings); + } +} diff --git a/Centaurus.Domain/Global.cs b/Centaurus.Domain/Global.cs index 485109d8..fd5ef0aa 100644 --- a/Centaurus.Domain/Global.cs +++ b/Centaurus.Domain/Global.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Timers; @@ -21,6 +22,8 @@ public static class Global /// Permanent storage object public static void Init(BaseSettings settings, BaseStorage storage) { + ExtensionsManager = new ExtensionsManager(); + Settings = settings ?? throw new ArgumentNullException(nameof(settings)); DynamicSerializersInitializer.Init(); @@ -79,6 +82,9 @@ public static void Setup(Snapshot snapshot) WithdrawalStorage = new WithdrawalStorage(snapshot.Withdrawals); LedgerManager = new LedgerManager(snapshot.Ledger); + + ExtensionsManager = new ExtensionsManager(); + ExtensionsManager.RegisterAllExtensions().Wait(); } public static Exchange Exchange { get; private set; } @@ -107,6 +113,7 @@ private set public static AuditLedgerManager AuditLedgerManager { get; private set; } public static AuditResultManager AuditResultManager { get; private set; } public static LedgerManager LedgerManager { get; private set; } + public static ExtensionsManager ExtensionsManager { get; private set; } public static StateManager AppState { get; private set; } public static QuantumProcessorsStorage QuantumProcessor { get; private set; } diff --git a/Centaurus.Domain/MessageHandlers/Common/MessageHandlers.cs b/Centaurus.Domain/MessageHandlers/Common/MessageHandlers.cs index 92f3dab8..4723b2e6 100644 --- a/Centaurus.Domain/MessageHandlers/Common/MessageHandlers.cs +++ b/Centaurus.Domain/MessageHandlers/Common/MessageHandlers.cs @@ -47,8 +47,13 @@ public static async Task HandleMessage(T connetction, MessageEnvelope enve return false; var handler = handlers[envelope.Message.MessageType]; + var envelopeArgs = new EnvelopeEventArgs { Connection = connetction, Message = envelope }; + Global.ExtensionsManager.BeforeValidateMessage(envelopeArgs); await handler.Validate(connetction, envelope); + Global.ExtensionsManager.AfterValidateMessage(envelopeArgs); + Global.ExtensionsManager.BeforeHandleMessage(envelopeArgs); await handler.HandleMessage(connetction, envelope); + Global.ExtensionsManager.AfterHandleMessage(envelopeArgs); return true; } } diff --git a/Centaurus.Domain/Quanta/Handlers/QuantumHandler.cs b/Centaurus.Domain/Quanta/Handlers/QuantumHandler.cs index f3497645..331998bd 100644 --- a/Centaurus.Domain/Quanta/Handlers/QuantumHandler.cs +++ b/Centaurus.Domain/Quanta/Handlers/QuantumHandler.cs @@ -68,24 +68,27 @@ async Task ProcessQuantum(HandleItem handleItem) { var envelope = handleItem.Quantum; var tcs = handleItem.HandlingTaskSource; + ResultMessage result; try - { - var res = await HandleQuantum(envelope); - - tcs.SetResult(res); + { + Global.ExtensionsManager.BeforeQuantumHandle(envelope); + result = await HandleQuantum(envelope); + tcs.SetResult(result); } catch (Exception exc) { logger.Error(exc); - Notifier.OnMessageProcessResult(new ResultMessage + result = new ResultMessage { Status = ClientExceptionHelper.GetExceptionStatusCode(exc), OriginalMessage = envelope - }); + }; + Notifier.OnMessageProcessResult(result); tcs.SetException(exc); } + Global.ExtensionsManager.AfterQuantumHandle(result); } MessageEnvelope GetQuantumEnvelope(MessageEnvelope envelope) @@ -134,7 +137,7 @@ async Task AlphaHandleQuantum(MessageEnvelope envelope) Notifier.OnMessageProcessResult(resultMessage); - logger.Trace($"Message of type {envelope.Message.ToString()} with apex {quantum.Apex} is handled."); + logger.Trace($"Message of type {envelope.Message} with apex {quantum.Apex} is handled."); return resultMessage; } @@ -163,7 +166,7 @@ async Task AuditorHandleQuantum(MessageEnvelope envelope) ProcessTransaction(envelope, result); - logger.Trace($"Message of type {messageType.ToString()} with apex {((Quantum)envelope.Message).Apex} is handled."); + logger.Trace($"Message of type {messageType} with apex {((Quantum)envelope.Message).Apex} is handled."); } catch (Exception exc) { @@ -175,7 +178,7 @@ async Task AuditorHandleQuantum(MessageEnvelope envelope) { OutgoingMessageStorage.EnqueueMessage(result); } - return result; + return result; } void ValidateAccountRequestRate(MessageEnvelope envelope) diff --git a/Centaurus.Domain/Quanta/Processors/InitQuantumProcessor.cs b/Centaurus.Domain/Quanta/Processors/InitQuantumProcessor.cs index 0e22cb99..f56aa950 100644 --- a/Centaurus.Domain/Quanta/Processors/InitQuantumProcessor.cs +++ b/Centaurus.Domain/Quanta/Processors/InitQuantumProcessor.cs @@ -13,7 +13,7 @@ public class InitQuantumProcessor : IQuantumRequestProcessor public async Task Process(MessageEnvelope envelope) { - await SnapshotManager.ApplyInitUpdates(envelope); + var initEffects = await SnapshotManager.ApplyInitUpdates(envelope); var snapshot = await SnapshotManager.GetSnapshot(); @@ -27,7 +27,7 @@ public async Task Process(MessageEnvelope envelope) OutgoingMessageStorage.EnqueueMessage(new SetApexCursor { Apex = 1 }); } - return null; + return envelope.CreateResult(ResultStatusCodes.Success, new List(initEffects)); } public Task Validate(MessageEnvelope envelope) diff --git a/Centaurus.Domain/Quanta/Processors/LedgerRequestProcessor.cs b/Centaurus.Domain/Quanta/Processors/LedgerRequestProcessor.cs index bd982a1a..d186d86d 100644 --- a/Centaurus.Domain/Quanta/Processors/LedgerRequestProcessor.cs +++ b/Centaurus.Domain/Quanta/Processors/LedgerRequestProcessor.cs @@ -19,7 +19,7 @@ public Task Process(MessageEnvelope envelope) var effectsContainer = new EffectProcessorsContainer(envelope, Global.AddEffects); - effectsContainer.Add(LedgerUpdateEffectProcessor.GetProcessor(ledgerQuantum.Apex, ledgerNotification.LedgerTo, Global.LedgerManager)); + effectsContainer.AddLedgerCommit(Global.LedgerManager, ledgerNotification.LedgerTo, Global.LedgerManager.Ledger); for (var i = 0; i < ledgerNotification.Payments.Count; i++) { @@ -38,7 +38,7 @@ public Task Process(MessageEnvelope envelope) } } - return Task.FromResult(envelope.CreateResult(ResultStatusCodes.Success)); + return Task.FromResult(envelope.CreateResult(ResultStatusCodes.Success, effectsContainer.GetEffects().ToList())); } public Task Validate(MessageEnvelope envelope) diff --git a/Centaurus.Domain/Quanta/QuantumStorage.cs b/Centaurus.Domain/Quanta/QuantumStorage.cs index 7e7f23ae..c2482616 100644 --- a/Centaurus.Domain/Quanta/QuantumStorage.cs +++ b/Centaurus.Domain/Quanta/QuantumStorage.cs @@ -13,12 +13,12 @@ public class QuantumStorage { static Logger logger = LogManager.GetCurrentClassLogger(); - public List apexes = new List(); + private List apexes = new List(); - public List quanta = new List(); + private List quanta = new List(); - public int QuantaCacheCapacity = 1_000_000; - int capacityThreshold = 1000; + private int QuantaCacheCapacity = 1_000_000; + private int capacityThreshold = 1000; public long CurrentApex { get; private set; } public byte[] LastQuantumHash { get; private set; } diff --git a/Centaurus.Domain/Snapshot/SnapshotManager.cs b/Centaurus.Domain/Snapshot/SnapshotManager.cs index 39d8d0f4..06e5f392 100644 --- a/Centaurus.Domain/Snapshot/SnapshotManager.cs +++ b/Centaurus.Domain/Snapshot/SnapshotManager.cs @@ -31,28 +31,32 @@ public SnapshotManager(Action _onSnapshotSuccess, Action _onSnapshotFail /// Makes initial save to DB /// /// Envelope that contains constellation init quantum. - public static async Task ApplyInitUpdates(MessageEnvelope envelope) + public static async Task ApplyInitUpdates(MessageEnvelope envelope) { var initQuantum = (ConstellationInitQuantum)envelope.Message; - var initEffect = new ConstellationInitEffect - { - Apex = initQuantum.Apex, - Assets = initQuantum.Assets, - Auditors = initQuantum.Auditors, - MinAccountBalance = initQuantum.MinAccountBalance, - MinAllowedLotSize = initQuantum.MinAllowedLotSize, - Vault = initQuantum.Vault, - VaultSequence = initQuantum.VaultSequence, - Ledger = initQuantum.Ledger, - RequestRateLimits = initQuantum.RequestRateLimits + var initEffects = new Effect[] { + new ConstellationInitEffect { + Apex = initQuantum.Apex, + Assets = initQuantum.Assets, + Auditors = initQuantum.Auditors, + MinAccountBalance = initQuantum.MinAccountBalance, + MinAllowedLotSize = initQuantum.MinAllowedLotSize, + Vault = initQuantum.Vault, + VaultSequence = initQuantum.VaultSequence, + Ledger = initQuantum.Ledger, + RequestRateLimits = initQuantum.RequestRateLimits + + } }; var updates = new PendingUpdates(); - updates.Add(envelope, new Effect[] { initEffect }); + updates.Add(envelope, initEffects); await SaveSnapshotInternal(updates); + + return initEffects; } //only one thread can save snapshots. We need make sure that previous snapshot is permanent diff --git a/Centaurus.Domain/WebSockets/Alpha/ConnectionManager.cs b/Centaurus.Domain/WebSockets/Alpha/ConnectionManager.cs index fb91ec15..0a3fc168 100644 --- a/Centaurus.Domain/WebSockets/Alpha/ConnectionManager.cs +++ b/Centaurus.Domain/WebSockets/Alpha/ConnectionManager.cs @@ -51,6 +51,7 @@ public static List GetAuditorConnections() /// New websocket connection public static async Task OnNewConnection(WebSocket webSocket) { + Global.ExtensionsManager.BeforeNewConnection(webSocket); if (webSocket == null) throw new ArgumentNullException(nameof(webSocket)); @@ -166,6 +167,7 @@ static void Validated(BaseWebSocketConnection baseConnection) { lock (baseConnection) { + Global.ExtensionsManager.ConnectionValidated(baseConnection); var connection = (AlphaWebSocketConnection)baseConnection; AddConnection(connection); } diff --git a/Centaurus.Domain/WebSockets/Alpha/Notifier.cs b/Centaurus.Domain/WebSockets/Alpha/Notifier.cs index 51025310..4368be02 100644 --- a/Centaurus.Domain/WebSockets/Alpha/Notifier.cs +++ b/Centaurus.Domain/WebSockets/Alpha/Notifier.cs @@ -9,17 +9,6 @@ namespace Centaurus.Domain { public static class Notifier { - /// - /// Sends the message to the account - /// - /// Target account - /// Message to send - public static void Notify(RawPubKey account, Message message) - { - if (ConnectionManager.TryGetConnection(account, out AlphaWebSocketConnection connection)) - _ = connection.SendMessage(message); - } - /// /// Sends the message to the account /// @@ -27,27 +16,18 @@ public static void Notify(RawPubKey account, Message message) /// Message to send public static void Notify(RawPubKey account, MessageEnvelope envelope) { + Global.ExtensionsManager.BeforeNotify(new NotifyEventArgs { Account = account, Envelope = envelope }); if (ConnectionManager.TryGetConnection(account, out AlphaWebSocketConnection connection)) _ = connection.SendMessage(envelope); } - /// - /// Sends the message to all connected auditors - /// - /// Message to send - public static void NotifyAuditors(Message message) - { - var auditors = ConnectionManager.GetAuditorConnections(); - for (var i = 0; i < auditors.Count; i++) - _ = auditors[i].SendMessage(message); - } - /// /// Sends the message to all connected auditors /// /// Message to send public static void NotifyAuditors(MessageEnvelope envelope) { + Global.ExtensionsManager.BeforeNotifyAuditors(envelope); var auditors = ConnectionManager.GetAuditorConnections(); for (var i = 0; i < auditors.Count; i++) _ = auditors[i].SendMessage(envelope); @@ -67,11 +47,11 @@ public static void OnMessageProcessResult(ResultMessage result) //unwrap if it is RequestQuantum if (result.OriginalMessage.Message is RequestQuantum) signatures = ((RequestQuantum)result.OriginalMessage.Message).RequestEnvelope.Signatures; - + var envelope = result.CreateEnvelope(); for (var i = 0; i < signatures.Count; i++) { var accountToNotify = signatures[i]; - Notify(accountToNotify.Signer, result); + Notify(accountToNotify.Signer, envelope); } } } diff --git a/Centaurus.Domain/WebSockets/Auditor/OutgoingMessageStorage.cs b/Centaurus.Domain/WebSockets/Auditor/OutgoingMessageStorage.cs index 6279072f..548fc211 100644 --- a/Centaurus.Domain/WebSockets/Auditor/OutgoingMessageStorage.cs +++ b/Centaurus.Domain/WebSockets/Auditor/OutgoingMessageStorage.cs @@ -1,6 +1,8 @@ using Centaurus.Domain; using Centaurus.Models; +using System; using System.Collections.Concurrent; +using System.Diagnostics; namespace Centaurus.Domain { @@ -16,6 +18,8 @@ public static void OnLedger(LedgerUpdateNotification ledger) public static void EnqueueMessage(Message message) { + if (message == null) + throw new ArgumentNullException(nameof(message)); outgoingMessages.Enqueue(message); } diff --git a/Centaurus.Domain/WebSockets/BaseWebSocketConnection.cs b/Centaurus.Domain/WebSockets/BaseWebSocketConnection.cs index bb192a5e..075d32b6 100644 --- a/Centaurus.Domain/WebSockets/BaseWebSocketConnection.cs +++ b/Centaurus.Domain/WebSockets/BaseWebSocketConnection.cs @@ -73,6 +73,7 @@ public async Task CloseConnection(WebSocketCloseStatus status = WebSocketCloseSt return; try { + Global.ExtensionsManager.BeforeConnectionClose(this); if (webSocket.State == WebSocketState.Open || webSocket.State == WebSocketState.Connecting) { var connectionPubKey = "no public key"; @@ -103,11 +104,22 @@ public virtual async Task SendMessage(Message message, CancellationToken ct = de public virtual async Task SendMessage(MessageEnvelope envelope, CancellationToken ct = default) { - if (!envelope.IsSignedBy(Global.Settings.KeyPair.PublicKey)) - envelope.Sign(Global.Settings.KeyPair); - - var serializedData = XdrConverter.Serialize(envelope); - await webSocket.SendAsync(serializedData, WebSocketMessageType.Binary, true, (ct == default ? CancellationToken.None : ct)); + try + { + var messageArgs = new EnvelopeEventArgs { Connection = this, Message = envelope }; + Global.ExtensionsManager.BeforeSendMessage(messageArgs); + if (!envelope.IsSignedBy(Global.Settings.KeyPair.PublicKey)) + envelope.Sign(Global.Settings.KeyPair); + + var serializedData = XdrConverter.Serialize(envelope); + await webSocket.SendAsync(serializedData, WebSocketMessageType.Binary, true, (ct == default ? CancellationToken.None : ct)); + Global.ExtensionsManager.AfterSendMessage(messageArgs); + } + catch(Exception exc) + { + Global.ExtensionsManager.SendMessageFailed(new EnvelopeErrorEventArgs { Connection = this, Message = envelope, Exception = exc }); + throw; + } } public async Task Listen() @@ -130,6 +142,8 @@ public async Task Listen() if (exc is ConnectionCloseException) throw; + Global.ExtensionsManager.HandleMessageFailed(new EnvelopeErrorEventArgs { Connection = this, Exception = exc, Message = envelope }); + var statusCode = ClientExceptionHelper.GetExceptionStatusCode(exc); //prevent recursive error sending @@ -147,11 +161,13 @@ public async Task Listen() } catch (WebSocketException e) { + Global.ExtensionsManager.HandleMessageFailed(new EnvelopeErrorEventArgs { Connection = this, Exception = e }); logger.Error(e); await CloseConnection(WebSocketCloseStatus.InternalServerError); } catch (Exception e) { + Global.ExtensionsManager.HandleMessageFailed(new EnvelopeErrorEventArgs { Connection = this, Exception = e }); logger.Error(e); } } diff --git a/Centaurus.DynamicSerializers/Centaurus.DynamicSerializers.csproj b/Centaurus.DynamicSerializers/Centaurus.DynamicSerializers.csproj index 3c66892f..dc584fc8 100644 --- a/Centaurus.DynamicSerializers/Centaurus.DynamicSerializers.csproj +++ b/Centaurus.DynamicSerializers/Centaurus.DynamicSerializers.csproj @@ -11,11 +11,11 @@ - - - + + + \ No newline at end of file diff --git a/Centaurus.Test.DynamicSerializers/Centaurus.Test.DynamicSerializers.csproj b/Centaurus.Test.DynamicSerializers/Centaurus.Test.DynamicSerializers.csproj index a9e5e231..b1c1eb72 100644 --- a/Centaurus.Test.DynamicSerializers/Centaurus.Test.DynamicSerializers.csproj +++ b/Centaurus.Test.DynamicSerializers/Centaurus.Test.DynamicSerializers.csproj @@ -7,7 +7,7 @@ - + diff --git a/Centaurus.sln b/Centaurus.sln index 3b714f07..a99d9e94 100644 --- a/Centaurus.sln +++ b/Centaurus.sln @@ -37,88 +37,162 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Centaurus.Test.Xdr.Contract EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Centaurus.DynamicSerializers", "Centaurus.DynamicSerializers\Centaurus.DynamicSerializers.csproj", "{148326BF-1439-4863-8F2A-3B72D5F56485}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Centaurus.Test.DynamicSerializers", "Centaurus.Test.DynamicSerializers\Centaurus.Test.DynamicSerializers.csproj", "{60177E3D-1970-40A2-8779-28F246F51955}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Centaurus.Test.DynamicSerializers", "Centaurus.Test.DynamicSerializers\Centaurus.Test.DynamicSerializers.csproj", "{60177E3D-1970-40A2-8779-28F246F51955}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Centaurus.Test.Contracts", "Centaurus.Test.Contracts\Centaurus.Test.Contracts.csproj", "{296B43F1-D12D-4D39-8A06-F6929B68D6F3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Centaurus.Test.Contracts", "Centaurus.Test.Contracts\Centaurus.Test.Contracts.csproj", "{296B43F1-D12D-4D39-8A06-F6929B68D6F3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {65A5ABB7-9610-4BDA-9541-050D1BD9C314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {65A5ABB7-9610-4BDA-9541-050D1BD9C314}.Debug|Any CPU.Build.0 = Debug|Any CPU + {65A5ABB7-9610-4BDA-9541-050D1BD9C314}.Debug|x64.ActiveCfg = Debug|Any CPU + {65A5ABB7-9610-4BDA-9541-050D1BD9C314}.Debug|x64.Build.0 = Debug|Any CPU {65A5ABB7-9610-4BDA-9541-050D1BD9C314}.Release|Any CPU.ActiveCfg = Release|Any CPU {65A5ABB7-9610-4BDA-9541-050D1BD9C314}.Release|Any CPU.Build.0 = Release|Any CPU + {65A5ABB7-9610-4BDA-9541-050D1BD9C314}.Release|x64.ActiveCfg = Release|Any CPU + {65A5ABB7-9610-4BDA-9541-050D1BD9C314}.Release|x64.Build.0 = Release|Any CPU {CF1A091E-8818-4C46-B806-819C0A70D2D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CF1A091E-8818-4C46-B806-819C0A70D2D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF1A091E-8818-4C46-B806-819C0A70D2D9}.Debug|x64.ActiveCfg = Debug|Any CPU + {CF1A091E-8818-4C46-B806-819C0A70D2D9}.Debug|x64.Build.0 = Debug|Any CPU {CF1A091E-8818-4C46-B806-819C0A70D2D9}.Release|Any CPU.ActiveCfg = Release|Any CPU {CF1A091E-8818-4C46-B806-819C0A70D2D9}.Release|Any CPU.Build.0 = Release|Any CPU + {CF1A091E-8818-4C46-B806-819C0A70D2D9}.Release|x64.ActiveCfg = Release|Any CPU + {CF1A091E-8818-4C46-B806-819C0A70D2D9}.Release|x64.Build.0 = Release|Any CPU {15ECC1EE-A850-4939-BCDD-9F37ED548856}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {15ECC1EE-A850-4939-BCDD-9F37ED548856}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15ECC1EE-A850-4939-BCDD-9F37ED548856}.Debug|x64.ActiveCfg = Debug|Any CPU + {15ECC1EE-A850-4939-BCDD-9F37ED548856}.Debug|x64.Build.0 = Debug|Any CPU {15ECC1EE-A850-4939-BCDD-9F37ED548856}.Release|Any CPU.ActiveCfg = Release|Any CPU {15ECC1EE-A850-4939-BCDD-9F37ED548856}.Release|Any CPU.Build.0 = Release|Any CPU + {15ECC1EE-A850-4939-BCDD-9F37ED548856}.Release|x64.ActiveCfg = Release|Any CPU + {15ECC1EE-A850-4939-BCDD-9F37ED548856}.Release|x64.Build.0 = Release|Any CPU {DF8642AE-71B9-4600-9258-39BAC9365F5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DF8642AE-71B9-4600-9258-39BAC9365F5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF8642AE-71B9-4600-9258-39BAC9365F5B}.Debug|x64.ActiveCfg = Debug|Any CPU + {DF8642AE-71B9-4600-9258-39BAC9365F5B}.Debug|x64.Build.0 = Debug|Any CPU {DF8642AE-71B9-4600-9258-39BAC9365F5B}.Release|Any CPU.ActiveCfg = Release|Any CPU {DF8642AE-71B9-4600-9258-39BAC9365F5B}.Release|Any CPU.Build.0 = Release|Any CPU + {DF8642AE-71B9-4600-9258-39BAC9365F5B}.Release|x64.ActiveCfg = Release|Any CPU + {DF8642AE-71B9-4600-9258-39BAC9365F5B}.Release|x64.Build.0 = Release|Any CPU {2AF78799-BBF2-4E52-9284-E88EFF243C60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2AF78799-BBF2-4E52-9284-E88EFF243C60}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2AF78799-BBF2-4E52-9284-E88EFF243C60}.Debug|x64.ActiveCfg = Debug|Any CPU + {2AF78799-BBF2-4E52-9284-E88EFF243C60}.Debug|x64.Build.0 = Debug|Any CPU {2AF78799-BBF2-4E52-9284-E88EFF243C60}.Release|Any CPU.ActiveCfg = Release|Any CPU {2AF78799-BBF2-4E52-9284-E88EFF243C60}.Release|Any CPU.Build.0 = Release|Any CPU + {2AF78799-BBF2-4E52-9284-E88EFF243C60}.Release|x64.ActiveCfg = Release|Any CPU + {2AF78799-BBF2-4E52-9284-E88EFF243C60}.Release|x64.Build.0 = Release|Any CPU {6801D81E-683C-450F-8EB8-00F216A419ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6801D81E-683C-450F-8EB8-00F216A419ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6801D81E-683C-450F-8EB8-00F216A419ED}.Debug|x64.ActiveCfg = Debug|Any CPU + {6801D81E-683C-450F-8EB8-00F216A419ED}.Debug|x64.Build.0 = Debug|Any CPU {6801D81E-683C-450F-8EB8-00F216A419ED}.Release|Any CPU.ActiveCfg = Release|Any CPU {6801D81E-683C-450F-8EB8-00F216A419ED}.Release|Any CPU.Build.0 = Release|Any CPU + {6801D81E-683C-450F-8EB8-00F216A419ED}.Release|x64.ActiveCfg = Release|Any CPU + {6801D81E-683C-450F-8EB8-00F216A419ED}.Release|x64.Build.0 = Release|Any CPU {0C672C85-5DD9-4B80-84B0-BB64C6BC4411}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0C672C85-5DD9-4B80-84B0-BB64C6BC4411}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C672C85-5DD9-4B80-84B0-BB64C6BC4411}.Debug|x64.ActiveCfg = Debug|Any CPU + {0C672C85-5DD9-4B80-84B0-BB64C6BC4411}.Debug|x64.Build.0 = Debug|Any CPU {0C672C85-5DD9-4B80-84B0-BB64C6BC4411}.Release|Any CPU.ActiveCfg = Release|Any CPU {0C672C85-5DD9-4B80-84B0-BB64C6BC4411}.Release|Any CPU.Build.0 = Release|Any CPU + {0C672C85-5DD9-4B80-84B0-BB64C6BC4411}.Release|x64.ActiveCfg = Release|Any CPU + {0C672C85-5DD9-4B80-84B0-BB64C6BC4411}.Release|x64.Build.0 = Release|Any CPU {50877E96-277B-45C8-8FEF-EC8AE95ED2D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {50877E96-277B-45C8-8FEF-EC8AE95ED2D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50877E96-277B-45C8-8FEF-EC8AE95ED2D7}.Debug|x64.ActiveCfg = Debug|Any CPU + {50877E96-277B-45C8-8FEF-EC8AE95ED2D7}.Debug|x64.Build.0 = Debug|Any CPU {50877E96-277B-45C8-8FEF-EC8AE95ED2D7}.Release|Any CPU.ActiveCfg = Release|Any CPU {50877E96-277B-45C8-8FEF-EC8AE95ED2D7}.Release|Any CPU.Build.0 = Release|Any CPU + {50877E96-277B-45C8-8FEF-EC8AE95ED2D7}.Release|x64.ActiveCfg = Release|Any CPU + {50877E96-277B-45C8-8FEF-EC8AE95ED2D7}.Release|x64.Build.0 = Release|Any CPU {9AAF521F-06D4-4E93-8C64-C4872FDC4BD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9AAF521F-06D4-4E93-8C64-C4872FDC4BD9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AAF521F-06D4-4E93-8C64-C4872FDC4BD9}.Debug|x64.ActiveCfg = Debug|Any CPU + {9AAF521F-06D4-4E93-8C64-C4872FDC4BD9}.Debug|x64.Build.0 = Debug|Any CPU {9AAF521F-06D4-4E93-8C64-C4872FDC4BD9}.Release|Any CPU.ActiveCfg = Release|Any CPU {9AAF521F-06D4-4E93-8C64-C4872FDC4BD9}.Release|Any CPU.Build.0 = Release|Any CPU + {9AAF521F-06D4-4E93-8C64-C4872FDC4BD9}.Release|x64.ActiveCfg = Release|Any CPU + {9AAF521F-06D4-4E93-8C64-C4872FDC4BD9}.Release|x64.Build.0 = Release|Any CPU {42D637FA-6868-48BC-8101-814DAFFFED69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {42D637FA-6868-48BC-8101-814DAFFFED69}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42D637FA-6868-48BC-8101-814DAFFFED69}.Debug|x64.ActiveCfg = Debug|Any CPU + {42D637FA-6868-48BC-8101-814DAFFFED69}.Debug|x64.Build.0 = Debug|Any CPU {42D637FA-6868-48BC-8101-814DAFFFED69}.Release|Any CPU.ActiveCfg = Release|Any CPU {42D637FA-6868-48BC-8101-814DAFFFED69}.Release|Any CPU.Build.0 = Release|Any CPU + {42D637FA-6868-48BC-8101-814DAFFFED69}.Release|x64.ActiveCfg = Release|Any CPU + {42D637FA-6868-48BC-8101-814DAFFFED69}.Release|x64.Build.0 = Release|Any CPU {B47246E7-516D-4F9A-9BEA-C6C375896149}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B47246E7-516D-4F9A-9BEA-C6C375896149}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B47246E7-516D-4F9A-9BEA-C6C375896149}.Debug|x64.ActiveCfg = Debug|Any CPU + {B47246E7-516D-4F9A-9BEA-C6C375896149}.Debug|x64.Build.0 = Debug|Any CPU {B47246E7-516D-4F9A-9BEA-C6C375896149}.Release|Any CPU.ActiveCfg = Release|Any CPU {B47246E7-516D-4F9A-9BEA-C6C375896149}.Release|Any CPU.Build.0 = Release|Any CPU + {B47246E7-516D-4F9A-9BEA-C6C375896149}.Release|x64.ActiveCfg = Release|Any CPU + {B47246E7-516D-4F9A-9BEA-C6C375896149}.Release|x64.Build.0 = Release|Any CPU {4B04C9FD-55A6-4A6D-BEF9-97BCA068127B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4B04C9FD-55A6-4A6D-BEF9-97BCA068127B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B04C9FD-55A6-4A6D-BEF9-97BCA068127B}.Debug|x64.ActiveCfg = Debug|Any CPU + {4B04C9FD-55A6-4A6D-BEF9-97BCA068127B}.Debug|x64.Build.0 = Debug|Any CPU {4B04C9FD-55A6-4A6D-BEF9-97BCA068127B}.Release|Any CPU.ActiveCfg = Release|Any CPU {4B04C9FD-55A6-4A6D-BEF9-97BCA068127B}.Release|Any CPU.Build.0 = Release|Any CPU + {4B04C9FD-55A6-4A6D-BEF9-97BCA068127B}.Release|x64.ActiveCfg = Release|Any CPU + {4B04C9FD-55A6-4A6D-BEF9-97BCA068127B}.Release|x64.Build.0 = Release|Any CPU {3EC15C42-A808-4E9B-BE97-A189024FC419}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3EC15C42-A808-4E9B-BE97-A189024FC419}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3EC15C42-A808-4E9B-BE97-A189024FC419}.Debug|x64.ActiveCfg = Debug|Any CPU + {3EC15C42-A808-4E9B-BE97-A189024FC419}.Debug|x64.Build.0 = Debug|Any CPU {3EC15C42-A808-4E9B-BE97-A189024FC419}.Release|Any CPU.ActiveCfg = Release|Any CPU {3EC15C42-A808-4E9B-BE97-A189024FC419}.Release|Any CPU.Build.0 = Release|Any CPU + {3EC15C42-A808-4E9B-BE97-A189024FC419}.Release|x64.ActiveCfg = Release|Any CPU + {3EC15C42-A808-4E9B-BE97-A189024FC419}.Release|x64.Build.0 = Release|Any CPU {23E8A167-3FC6-401D-870A-44FF234B251C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {23E8A167-3FC6-401D-870A-44FF234B251C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23E8A167-3FC6-401D-870A-44FF234B251C}.Debug|x64.ActiveCfg = Debug|Any CPU + {23E8A167-3FC6-401D-870A-44FF234B251C}.Debug|x64.Build.0 = Debug|Any CPU {23E8A167-3FC6-401D-870A-44FF234B251C}.Release|Any CPU.ActiveCfg = Release|Any CPU {23E8A167-3FC6-401D-870A-44FF234B251C}.Release|Any CPU.Build.0 = Release|Any CPU + {23E8A167-3FC6-401D-870A-44FF234B251C}.Release|x64.ActiveCfg = Release|Any CPU + {23E8A167-3FC6-401D-870A-44FF234B251C}.Release|x64.Build.0 = Release|Any CPU {81C741D7-2931-4AC6-BD94-38D8E214258B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {81C741D7-2931-4AC6-BD94-38D8E214258B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81C741D7-2931-4AC6-BD94-38D8E214258B}.Debug|x64.ActiveCfg = Debug|Any CPU + {81C741D7-2931-4AC6-BD94-38D8E214258B}.Debug|x64.Build.0 = Debug|Any CPU {81C741D7-2931-4AC6-BD94-38D8E214258B}.Release|Any CPU.ActiveCfg = Release|Any CPU {81C741D7-2931-4AC6-BD94-38D8E214258B}.Release|Any CPU.Build.0 = Release|Any CPU + {81C741D7-2931-4AC6-BD94-38D8E214258B}.Release|x64.ActiveCfg = Release|Any CPU + {81C741D7-2931-4AC6-BD94-38D8E214258B}.Release|x64.Build.0 = Release|Any CPU {148326BF-1439-4863-8F2A-3B72D5F56485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {148326BF-1439-4863-8F2A-3B72D5F56485}.Debug|Any CPU.Build.0 = Debug|Any CPU + {148326BF-1439-4863-8F2A-3B72D5F56485}.Debug|x64.ActiveCfg = Debug|Any CPU + {148326BF-1439-4863-8F2A-3B72D5F56485}.Debug|x64.Build.0 = Debug|Any CPU {148326BF-1439-4863-8F2A-3B72D5F56485}.Release|Any CPU.ActiveCfg = Release|Any CPU {148326BF-1439-4863-8F2A-3B72D5F56485}.Release|Any CPU.Build.0 = Release|Any CPU + {148326BF-1439-4863-8F2A-3B72D5F56485}.Release|x64.ActiveCfg = Release|Any CPU + {148326BF-1439-4863-8F2A-3B72D5F56485}.Release|x64.Build.0 = Release|Any CPU {60177E3D-1970-40A2-8779-28F246F51955}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {60177E3D-1970-40A2-8779-28F246F51955}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60177E3D-1970-40A2-8779-28F246F51955}.Debug|x64.ActiveCfg = Debug|Any CPU + {60177E3D-1970-40A2-8779-28F246F51955}.Debug|x64.Build.0 = Debug|Any CPU {60177E3D-1970-40A2-8779-28F246F51955}.Release|Any CPU.ActiveCfg = Release|Any CPU {60177E3D-1970-40A2-8779-28F246F51955}.Release|Any CPU.Build.0 = Release|Any CPU + {60177E3D-1970-40A2-8779-28F246F51955}.Release|x64.ActiveCfg = Release|Any CPU + {60177E3D-1970-40A2-8779-28F246F51955}.Release|x64.Build.0 = Release|Any CPU {296B43F1-D12D-4D39-8A06-F6929B68D6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {296B43F1-D12D-4D39-8A06-F6929B68D6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {296B43F1-D12D-4D39-8A06-F6929B68D6F3}.Debug|x64.ActiveCfg = Debug|Any CPU + {296B43F1-D12D-4D39-8A06-F6929B68D6F3}.Debug|x64.Build.0 = Debug|Any CPU {296B43F1-D12D-4D39-8A06-F6929B68D6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU {296B43F1-D12D-4D39-8A06-F6929B68D6F3}.Release|Any CPU.Build.0 = Release|Any CPU + {296B43F1-D12D-4D39-8A06-F6929B68D6F3}.Release|x64.ActiveCfg = Release|Any CPU + {296B43F1-D12D-4D39-8A06-F6929B68D6F3}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index 3a333128..65d70aa7 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,7 @@ minimal attack surface. - [Quantum structure](docs/quantum-flow.md) - [Snapshots](docs/snapshots.md) - [Administration](docs/administration.md) +- [Extensions](docs/extensions.md) --- diff --git a/docs/extensions.md b/docs/extensions.md new file mode 100644 index 00000000..3591e704 --- /dev/null +++ b/docs/extensions.md @@ -0,0 +1,23 @@ +# Extensions + +Centaurus supports extensions. +To create new extension you need to start new library project and add references to Centaurus.Domain and Centaurus.Common projects. +Then you need to implement IExtension interface from Centaurus.Domain project. After that you can subscribe to events of Global.ExtensionsManager instance. +Create extensions configurable file and place your extension dll file to the same folder. Specify path to the extension config file for Alpha or auditor. To do that, run executable with param `--extensions_config_file_path path-to-config` + +### Config example +``` +{ + "extensions": [ + { + name: "SomeExtension", //extension name + isDisabled: false, //false is default value + extensionConfig: { //this is where your extension settings should be placed. It will be passed to extension as a dictionary + prop1: 1, + prop2: false, + prop3: "test" + } + } + ] +} +``` \ No newline at end of file