From 8677f26f574bf3c9bc6f164d4ad5750f725101aa Mon Sep 17 00:00:00 2001 From: Weijie Lin Date: Wed, 28 Jun 2023 19:05:37 -0700 Subject: [PATCH 01/10] wrote a basic worknet plugin --- .vscode/launch.json | 11 ++++++ dirs.proj | 1 + src/worknet-ext/logger/WorkNetFileLogger.cs | 29 ++++++++++++++ src/worknet-ext/logger/filelogger.csproj | 34 ++++++++++++++++ src/worknet/Node/PluginHandler.cs | 44 +++++++++++++++++++++ src/worknet/Node/WorkNetNode.cs | 2 +- 6 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/worknet-ext/logger/WorkNetFileLogger.cs create mode 100644 src/worknet-ext/logger/filelogger.csproj create mode 100644 src/worknet/Node/PluginHandler.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index 8518253..f20c42b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,6 +14,17 @@ "console": "integratedTerminal", "stopAtEntry": false }, + { + "name": "worknet run", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/src/worknet/bin/Debug/net6.0/neo-worknet", + "args": ["run"], + "cwd": "${workspaceFolder}/src/worknet", + "console": "integratedTerminal", + "stopAtEntry": false + }, { "name": "list storage", "type": "coreclr", diff --git a/dirs.proj b/dirs.proj index a250c25..9288d53 100644 --- a/dirs.proj +++ b/dirs.proj @@ -4,5 +4,6 @@ + \ No newline at end of file diff --git a/src/worknet-ext/logger/WorkNetFileLogger.cs b/src/worknet-ext/logger/WorkNetFileLogger.cs new file mode 100644 index 0000000..ac3ebc0 --- /dev/null +++ b/src/worknet-ext/logger/WorkNetFileLogger.cs @@ -0,0 +1,29 @@ +using Neo; +using Neo.BlockchainToolkit.Persistence; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.Plugins; +using Neo.SmartContract; +using Neo.SmartContract.Native; + +namespace WorkNetExt; + +public class WorkNetFileLogger : Plugin +{ + public WorkNetFileLogger() + { + Blockchain.Committing += OnCommitting; + } + + public override void Dispose() + { + Blockchain.Committing -= OnCommitting; + GC.SuppressFinalize(this); + } + + void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + Console.WriteLine("Blockchain Committing"); + } +} diff --git a/src/worknet-ext/logger/filelogger.csproj b/src/worknet-ext/logger/filelogger.csproj new file mode 100644 index 0000000..df057f5 --- /dev/null +++ b/src/worknet-ext/logger/filelogger.csproj @@ -0,0 +1,34 @@ + + + + worknet-ext-filelogger + library + WorkNetExt.FileLogger + true + WorkNetExt + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/worknet/Node/PluginHandler.cs b/src/worknet/Node/PluginHandler.cs new file mode 100644 index 0000000..be62b94 --- /dev/null +++ b/src/worknet/Node/PluginHandler.cs @@ -0,0 +1,44 @@ +using System.Reflection; +using Neo.Plugins; + +class PluginHandler +{ + public static void LoadPlugins(string directory) + { + if (!Directory.Exists(directory)) return; + List assemblies = new(); + + foreach (var filename in Directory.EnumerateFiles(directory, "*.dll", SearchOption.TopDirectoryOnly)) + { + try + { + assemblies.Add(Assembly.Load(File.ReadAllBytes(filename))); + } + catch { } + } + + foreach (Assembly assembly in assemblies) + { + LoadPlugin(assembly); + } + } + + public static void LoadPlugin(Assembly assembly) + { + foreach (Type type in assembly.ExportedTypes) + { + if (!type.IsSubclassOf(typeof(Plugin))) continue; + if (type.IsAbstract) continue; + + ConstructorInfo? constructor = type.GetConstructor(Type.EmptyTypes); + try + { + constructor?.Invoke(null); + } + catch (Exception ex) + { + throw new Exception($"Failed to load plugin: {type.FullName}", ex); + } + } + } +} \ No newline at end of file diff --git a/src/worknet/Node/WorkNetNode.cs b/src/worknet/Node/WorkNetNode.cs index be4fcb8..33a231f 100644 --- a/src/worknet/Node/WorkNetNode.cs +++ b/src/worknet/Node/WorkNetNode.cs @@ -216,7 +216,7 @@ public async Task RunAsync(uint secondsPerBlock, IConsole console, CancellationT using var dbftPlugin = new Neo.Consensus.DBFTPlugin(GetConsensusSettings(chain)); using var rpcServerPlugin = new WorknetRpcServerPlugin(GetRpcServerSettings(chain), persistencePlugin, chain.Uri); using var neoSystem = new Neo.NeoSystem(protocolSettings, storeProvider.Name); - + PluginHandler.LoadPlugins(Path.Combine(AppContext.BaseDirectory, "plugins")); neoSystem.StartNode(new Neo.Network.P2P.ChannelsConfig { Tcp = new IPEndPoint(IPAddress.Loopback, chain.ConsensusNode.TcpPort), From ddbcabdf18d25fbde9fb739db5186e766da73a23 Mon Sep 17 00:00:00 2001 From: Weijie Lin Date: Wed, 28 Jun 2023 19:07:11 -0700 Subject: [PATCH 02/10] also seek plugins in ~/.neo folder --- src/worknet/Node/WorkNetNode.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/worknet/Node/WorkNetNode.cs b/src/worknet/Node/WorkNetNode.cs index 33a231f..fe00700 100644 --- a/src/worknet/Node/WorkNetNode.cs +++ b/src/worknet/Node/WorkNetNode.cs @@ -217,6 +217,7 @@ public async Task RunAsync(uint secondsPerBlock, IConsole console, CancellationT using var rpcServerPlugin = new WorknetRpcServerPlugin(GetRpcServerSettings(chain), persistencePlugin, chain.Uri); using var neoSystem = new Neo.NeoSystem(protocolSettings, storeProvider.Name); PluginHandler.LoadPlugins(Path.Combine(AppContext.BaseDirectory, "plugins")); + PluginHandler.LoadPlugins(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".neo", "plugins")); neoSystem.StartNode(new Neo.Network.P2P.ChannelsConfig { Tcp = new IPEndPoint(IPAddress.Loopback, chain.ConsensusNode.TcpPort), From df8144d73967b510cc759ccaa53871139e4fed07 Mon Sep 17 00:00:00 2001 From: Weijie Lin Date: Wed, 5 Jul 2023 11:15:05 -0700 Subject: [PATCH 03/10] added console out logging when plugins are loaded --- src/worknet/Node/PluginHandler.cs | 4 +++- src/worknet/Node/WorkNetNode.cs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/worknet/Node/PluginHandler.cs b/src/worknet/Node/PluginHandler.cs index be62b94..8b5280c 100644 --- a/src/worknet/Node/PluginHandler.cs +++ b/src/worknet/Node/PluginHandler.cs @@ -1,9 +1,10 @@ using System.Reflection; using Neo.Plugins; +using McMaster.Extensions.CommandLineUtils; class PluginHandler { - public static void LoadPlugins(string directory) + public static void LoadPlugins(string directory, IConsole console) { if (!Directory.Exists(directory)) return; List assemblies = new(); @@ -13,6 +14,7 @@ public static void LoadPlugins(string directory) try { assemblies.Add(Assembly.Load(File.ReadAllBytes(filename))); + console.Out.WriteLine($"Loaded plugin: {filename}"); } catch { } } diff --git a/src/worknet/Node/WorkNetNode.cs b/src/worknet/Node/WorkNetNode.cs index fe00700..5157fce 100644 --- a/src/worknet/Node/WorkNetNode.cs +++ b/src/worknet/Node/WorkNetNode.cs @@ -216,8 +216,8 @@ public async Task RunAsync(uint secondsPerBlock, IConsole console, CancellationT using var dbftPlugin = new Neo.Consensus.DBFTPlugin(GetConsensusSettings(chain)); using var rpcServerPlugin = new WorknetRpcServerPlugin(GetRpcServerSettings(chain), persistencePlugin, chain.Uri); using var neoSystem = new Neo.NeoSystem(protocolSettings, storeProvider.Name); - PluginHandler.LoadPlugins(Path.Combine(AppContext.BaseDirectory, "plugins")); - PluginHandler.LoadPlugins(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".neo", "plugins")); + PluginHandler.LoadPlugins(Path.Combine(AppContext.BaseDirectory, "plugins"), console); + PluginHandler.LoadPlugins(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".neo", "plugins"), console); neoSystem.StartNode(new Neo.Network.P2P.ChannelsConfig { Tcp = new IPEndPoint(IPAddress.Loopback, chain.ConsensusNode.TcpPort), From 6482eb39bbc7230ead5549f7f01d6e194b8f1689 Mon Sep 17 00:00:00 2001 From: Weijie Lin Date: Wed, 5 Jul 2023 11:15:33 -0700 Subject: [PATCH 04/10] renamed sample logger and added more events to listen to --- src/worknet-ext/logger/WorkNetFileLogger.cs | 29 -------- src/worknet-ext/logger/WorkNetLogger.cs | 73 +++++++++++++++++++++ 2 files changed, 73 insertions(+), 29 deletions(-) delete mode 100644 src/worknet-ext/logger/WorkNetFileLogger.cs create mode 100644 src/worknet-ext/logger/WorkNetLogger.cs diff --git a/src/worknet-ext/logger/WorkNetFileLogger.cs b/src/worknet-ext/logger/WorkNetFileLogger.cs deleted file mode 100644 index ac3ebc0..0000000 --- a/src/worknet-ext/logger/WorkNetFileLogger.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Neo; -using Neo.BlockchainToolkit.Persistence; -using Neo.Ledger; -using Neo.Network.P2P.Payloads; -using Neo.Persistence; -using Neo.Plugins; -using Neo.SmartContract; -using Neo.SmartContract.Native; - -namespace WorkNetExt; - -public class WorkNetFileLogger : Plugin -{ - public WorkNetFileLogger() - { - Blockchain.Committing += OnCommitting; - } - - public override void Dispose() - { - Blockchain.Committing -= OnCommitting; - GC.SuppressFinalize(this); - } - - void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) - { - Console.WriteLine("Blockchain Committing"); - } -} diff --git a/src/worknet-ext/logger/WorkNetLogger.cs b/src/worknet-ext/logger/WorkNetLogger.cs new file mode 100644 index 0000000..b30b14e --- /dev/null +++ b/src/worknet-ext/logger/WorkNetLogger.cs @@ -0,0 +1,73 @@ +using System.Diagnostics; +using Neo; +using Neo.BlockchainToolkit.Persistence; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.Plugins; +using Neo.SmartContract; +using Neo.SmartContract.Native; + +namespace WorkNetExt; + +public class WorkNetLogger : Plugin +{ + NeoSystem? neoSystem; + + public WorkNetLogger() + { + Blockchain.Committing += OnCommitting; + ApplicationEngine.Log += OnAppEngineLog!; + Neo.Utility.Logging += OnNeoUtilityLog; + + } + + public override void Dispose() + { + Neo.Utility.Logging -= OnNeoUtilityLog; + ApplicationEngine.Log -= OnAppEngineLog!; + Blockchain.Committing -= OnCommitting; + GC.SuppressFinalize(this); + } + + protected override void OnSystemLoaded(NeoSystem system) + { + if (neoSystem is not null) throw new Exception($"{nameof(OnSystemLoaded)} already called"); + neoSystem = system; + base.OnSystemLoaded(system); + } + + void OnAppEngineLog(object sender, LogEventArgs args) + { + var container = args.ScriptContainer is null + ? string.Empty + : $" [{args.ScriptContainer.GetType().Name}]"; + + + Console.WriteLine($"{GetContractName(args.ScriptHash)} Log: \"{args.Message}\" {container}"); + } + + void OnNeoUtilityLog(string source, LogLevel level, object message) + { + Console.WriteLine($"{DateTimeOffset.Now:HH:mm:ss.ff} {source} {level} {message}"); + } + + void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + Console.WriteLine("Blockchain Committing"); + } + + protected string GetContractName(UInt160 scriptHash) + { + if (neoSystem is not null) + { + var contract = NativeContract.ContractManagement.GetContract(neoSystem.StoreView, scriptHash); + if (contract is not null) + { + return contract.Manifest.Name; + } + } + + return scriptHash.ToString(); + } +} From a283e03dd2af6bd398d6f2e5da9273d88337f204 Mon Sep 17 00:00:00 2001 From: Weijie Lin Date: Wed, 5 Jul 2023 11:41:26 -0700 Subject: [PATCH 05/10] added more info to console out onCommitting --- README.md | 17 +++++++++++++++-- src/worknet-ext/logger/WorkNetLogger.cs | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0a2448e..cc11795 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,9 @@ dotnet tool update Neo.WorkNet -g --prerelease different directories. Full details on installing and updating .NET tools are available in the [official documentation](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools). -## Installation (Preview) +## Shell + +### Installation (Preview) The Neo Blockchain Toolkit has a public [package feed](https://dev.azure.com/ngdenterprise/Build/_artifacts). that contains interim builds of Neo Shell and Worknet. You can unreleased preview builds of Neo-Shell by using the @@ -93,7 +95,7 @@ Several Neo sample projects like [NeoContributorToken](https://github.com/ngdenterprise/neo-contrib-token) use a NuGet.config file. -## Extending NEO Shell +### Extending NEO Shell NEO Shell allows developers to extend its functionality by adding custom commands. To do this, create a ~/.neo/neosh-extensions.json file that contains a list of commands executable from the shell. NEO Shell communicates with extensions using standard input/output. @@ -155,3 +157,14 @@ var script = contractHash.MakeScript("transfer", toHash, idBytes, string.Empty); var payload = new { Script = Convert.ToBase64String(script), Account = this.Account, Trace = this.Trace, Json = this.Json }; Console.WriteLine(JsonConvert.SerializeObject(payload)); ``` + +## Worknet + +### Extending NEO Worknet + +Plugins/modules can be created to extend the functionality of Neo Worknet. [Neo Modules](https://github.com/neo-project/neo-modules/tree/master) contains a set of plugins that can be used with Neo. Many of these plugins can be used with Neo Worknet as well. + +We have included a sample worknet plugin in the /workenet-ext folder. We will use this plugin as an example to show how to create and use a plugin for Neo Worknet. + +Example + diff --git a/src/worknet-ext/logger/WorkNetLogger.cs b/src/worknet-ext/logger/WorkNetLogger.cs index b30b14e..79f616d 100644 --- a/src/worknet-ext/logger/WorkNetLogger.cs +++ b/src/worknet-ext/logger/WorkNetLogger.cs @@ -54,7 +54,7 @@ void OnNeoUtilityLog(string source, LogLevel level, object message) void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) { - Console.WriteLine("Blockchain Committing"); + Console.WriteLine($"Blockchain Committing: {block.Hash} {block.Index} {block.Timestamp} {block.Transactions.Length} txs"); } protected string GetContractName(UInt160 scriptHash) From dbdae3c59c26ec96b3d3a73b5d7a52f83f6878c3 Mon Sep 17 00:00:00 2001 From: Weijie Lin Date: Wed, 5 Jul 2023 12:19:06 -0700 Subject: [PATCH 06/10] updated Extending NEO Worknet readme --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index cc11795..aa2c4d6 100644 --- a/README.md +++ b/README.md @@ -162,9 +162,6 @@ Console.WriteLine(JsonConvert.SerializeObject(payload)); ### Extending NEO Worknet -Plugins/modules can be created to extend the functionality of Neo Worknet. [Neo Modules](https://github.com/neo-project/neo-modules/tree/master) contains a set of plugins that can be used with Neo. Many of these plugins can be used with Neo Worknet as well. - -We have included a sample worknet plugin in the /workenet-ext folder. We will use this plugin as an example to show how to create and use a plugin for Neo Worknet. - -Example +Plugins/modules can be created to extend the functionality of Neo Worknet. [Neo Modules](https://github.com/neo-project/neo-modules/tree/master) contains a set of plugins that can be used with Neo. Many of these plugins can also be used with Neo Worknet. To use them, simply drop the dlls containing the plugins into the ~/.neo/plugins folder or /plugins folder in the worknet exe folder. Neo Worknet will automatically load and execute the plugins. +A sample WorkNet plugin, WorkNetLogger, has been included in the /workenet-ext folder. The WorkNetLogger plugin serves as a simple example of a plugin. After building the plugin, a DLL file named "worknet-ext-filelogger.dll" will be generated. This DLL can be copied to the ~/.neo/plugins folder. Neo Worknet will automatically load and execute the plugin. Alternatively, you can create a /plugins directory in the same folder as the neo-worknet executable and copy the DLL to the /plugins folder. From 0af5f7285479a3603646809c26b72fb5d11a49d7 Mon Sep 17 00:00:00 2001 From: Weijie Lin Date: Mon, 10 Jul 2023 10:43:36 -0700 Subject: [PATCH 07/10] -updated worknet plugin sample to read from config file and write output to a file - updated pluginHandler method to take TextWriter instead of IConsole so we don't have to depend on console --- src/worknet-ext/logger/WorkNetLogger.cs | 29 ++++++++++++++++++++----- src/worknet-ext/logger/config.json | 6 +++++ src/worknet/Node/PluginHandler.cs | 18 ++++++++++----- src/worknet/Node/WorkNetNode.cs | 4 ++-- 4 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 src/worknet-ext/logger/config.json diff --git a/src/worknet-ext/logger/WorkNetLogger.cs b/src/worknet-ext/logger/WorkNetLogger.cs index 79f616d..782643b 100644 --- a/src/worknet-ext/logger/WorkNetLogger.cs +++ b/src/worknet-ext/logger/WorkNetLogger.cs @@ -1,6 +1,5 @@ -using System.Diagnostics; +using Microsoft.Extensions.Configuration; using Neo; -using Neo.BlockchainToolkit.Persistence; using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; @@ -12,6 +11,8 @@ namespace WorkNetExt; public class WorkNetLogger : Plugin { + private string _logFile = "./logger.log"; + NeoSystem? neoSystem; public WorkNetLogger() @@ -30,6 +31,15 @@ public override void Dispose() GC.SuppressFinalize(this); } + // Overwrite Config file method to find the config.json from the same directory as the plugin dll directory + public override string ConfigFile => System.IO.Path.Combine(AppContext.BaseDirectory, "plugins", "config.json"); + + protected override void Configure() + { + IConfigurationSection config = GetConfiguration(); + _logFile = config.GetValue("LogFile", _logFile); + + } protected override void OnSystemLoaded(NeoSystem system) { if (neoSystem is not null) throw new Exception($"{nameof(OnSystemLoaded)} already called"); @@ -43,18 +53,17 @@ void OnAppEngineLog(object sender, LogEventArgs args) ? string.Empty : $" [{args.ScriptContainer.GetType().Name}]"; - - Console.WriteLine($"{GetContractName(args.ScriptHash)} Log: \"{args.Message}\" {container}"); + WriteToFile($"{GetContractName(args.ScriptHash)} Log: \"{args.Message}\" {container}"); } void OnNeoUtilityLog(string source, LogLevel level, object message) { - Console.WriteLine($"{DateTimeOffset.Now:HH:mm:ss.ff} {source} {level} {message}"); + WriteToFile($"{DateTimeOffset.Now:HH:mm:ss.ff} {source} {level} {message}"); } void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) { - Console.WriteLine($"Blockchain Committing: {block.Hash} {block.Index} {block.Timestamp} {block.Transactions.Length} txs"); + WriteToFile($"Blockchain Committing: {block.Hash} {block.Index} {block.Timestamp} {block.Transactions.Length} txs"); } protected string GetContractName(UInt160 scriptHash) @@ -70,4 +79,12 @@ protected string GetContractName(UInt160 scriptHash) return scriptHash.ToString(); } + + private void WriteToFile(string logMessage) + { + using(StreamWriter writer = new StreamWriter(_logFile, true)) + { + writer.WriteLine(logMessage); + } + } } diff --git a/src/worknet-ext/logger/config.json b/src/worknet-ext/logger/config.json new file mode 100644 index 0000000..de73986 --- /dev/null +++ b/src/worknet-ext/logger/config.json @@ -0,0 +1,6 @@ +{ + "PluginConfiguration": { + "LogFile": "./samplePlugLogger.log" + + } + } \ No newline at end of file diff --git a/src/worknet/Node/PluginHandler.cs b/src/worknet/Node/PluginHandler.cs index 8b5280c..3a9041b 100644 --- a/src/worknet/Node/PluginHandler.cs +++ b/src/worknet/Node/PluginHandler.cs @@ -1,10 +1,9 @@ using System.Reflection; using Neo.Plugins; -using McMaster.Extensions.CommandLineUtils; class PluginHandler { - public static void LoadPlugins(string directory, IConsole console) + public static void LoadPlugins(string directory, TextWriter? writer = null) { if (!Directory.Exists(directory)) return; List assemblies = new(); @@ -14,18 +13,18 @@ public static void LoadPlugins(string directory, IConsole console) try { assemblies.Add(Assembly.Load(File.ReadAllBytes(filename))); - console.Out.WriteLine($"Loaded plugin: {filename}"); + Log(writer, $"Loaded plugin: {filename}"); } catch { } } foreach (Assembly assembly in assemblies) { - LoadPlugin(assembly); + LoadPlugin(assembly, writer); } } - public static void LoadPlugin(Assembly assembly) + public static void LoadPlugin(Assembly assembly, TextWriter? writer = null) { foreach (Type type in assembly.ExportedTypes) { @@ -39,8 +38,15 @@ public static void LoadPlugin(Assembly assembly) } catch (Exception ex) { - throw new Exception($"Failed to load plugin: {type.FullName}", ex); + Log(writer, $"Failed to load plugin: {type.FullName}"); + Log(writer, ex.Message); } } } + + private static void Log(TextWriter? writer, string message) + { + if (writer is null) return; + writer.WriteLine(message); + } } \ No newline at end of file diff --git a/src/worknet/Node/WorkNetNode.cs b/src/worknet/Node/WorkNetNode.cs index 5157fce..3eae730 100644 --- a/src/worknet/Node/WorkNetNode.cs +++ b/src/worknet/Node/WorkNetNode.cs @@ -216,8 +216,8 @@ public async Task RunAsync(uint secondsPerBlock, IConsole console, CancellationT using var dbftPlugin = new Neo.Consensus.DBFTPlugin(GetConsensusSettings(chain)); using var rpcServerPlugin = new WorknetRpcServerPlugin(GetRpcServerSettings(chain), persistencePlugin, chain.Uri); using var neoSystem = new Neo.NeoSystem(protocolSettings, storeProvider.Name); - PluginHandler.LoadPlugins(Path.Combine(AppContext.BaseDirectory, "plugins"), console); - PluginHandler.LoadPlugins(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".neo", "plugins"), console); + PluginHandler.LoadPlugins(Path.Combine(AppContext.BaseDirectory, "plugins"), console.Out); + PluginHandler.LoadPlugins(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".neo", "plugins"), console.Out); neoSystem.StartNode(new Neo.Network.P2P.ChannelsConfig { Tcp = new IPEndPoint(IPAddress.Loopback, chain.ConsensusNode.TcpPort), From 4dec8aa19157a5f03b718e868973c8604a6e3cad Mon Sep 17 00:00:00 2001 From: Weijie Lin Date: Mon, 10 Jul 2023 10:51:52 -0700 Subject: [PATCH 08/10] made plugin handler a static class --- src/worknet/Node/PluginHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/worknet/Node/PluginHandler.cs b/src/worknet/Node/PluginHandler.cs index 3a9041b..ad68082 100644 --- a/src/worknet/Node/PluginHandler.cs +++ b/src/worknet/Node/PluginHandler.cs @@ -1,7 +1,7 @@ using System.Reflection; using Neo.Plugins; -class PluginHandler +static class PluginHandler { public static void LoadPlugins(string directory, TextWriter? writer = null) { From 681a50f0703db198d7314d232aef3b36bfe5d71e Mon Sep 17 00:00:00 2001 From: Weijie Lin Date: Mon, 10 Jul 2023 13:31:58 -0700 Subject: [PATCH 09/10] - updated comments and readme - use writer?.WriteLine pattern to avoid the null check in PluginHandler class --- README.md | 6 ++++-- src/worknet-ext/logger/WorkNetLogger.cs | 4 +++- src/worknet/Node/PluginHandler.cs | 12 +++--------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index aa2c4d6..449cf14 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,8 @@ Console.WriteLine(JsonConvert.SerializeObject(payload)); ### Extending NEO Worknet -Plugins/modules can be created to extend the functionality of Neo Worknet. [Neo Modules](https://github.com/neo-project/neo-modules/tree/master) contains a set of plugins that can be used with Neo. Many of these plugins can also be used with Neo Worknet. To use them, simply drop the dlls containing the plugins into the ~/.neo/plugins folder or /plugins folder in the worknet exe folder. Neo Worknet will automatically load and execute the plugins. +Neo Worknet's capabilities can be extended through the use of plugins or modules. The [Neo Modules](https://github.com/neo-project/neo-modules/tree/master) package offers a variety of plugins compatible with both Neo and Neo Worknet. To utilize these plugins, simply copy the DLL files containing the plugins into either the ~/.neo/plugins directory or the /plugins directory located within the worknet executable folder. Upon initiation, Neo Worknet will automatically load and activate these plugins. -A sample WorkNet plugin, WorkNetLogger, has been included in the /workenet-ext folder. The WorkNetLogger plugin serves as a simple example of a plugin. After building the plugin, a DLL file named "worknet-ext-filelogger.dll" will be generated. This DLL can be copied to the ~/.neo/plugins folder. Neo Worknet will automatically load and execute the plugin. Alternatively, you can create a /plugins directory in the same folder as the neo-worknet executable and copy the DLL to the /plugins folder. +As an illustrative example, we've included a sample Worknet plugin, WorkNetLogger, in the /workenet-ext directory. This plugin is designed to direct Worknet's logs to a specified file. It operates by reading the designated log file path from a custom config.json file, and then recording the logs into this file. + +After building the plugin, copy both the "worknet-ext-filelogger.dll" and config.json files to the ~/.neo/plugins directory. Upon startup, Worknet will automatically identify, load and execute the plugin. If preferred, you may also create a /plugins directory within the same directory as the neo-worknet executable, and relocate the DLL to this /plugins directory. diff --git a/src/worknet-ext/logger/WorkNetLogger.cs b/src/worknet-ext/logger/WorkNetLogger.cs index 782643b..92baa88 100644 --- a/src/worknet-ext/logger/WorkNetLogger.cs +++ b/src/worknet-ext/logger/WorkNetLogger.cs @@ -31,7 +31,9 @@ public override void Dispose() GC.SuppressFinalize(this); } - // Overwrite Config file method to find the config.json from the same directory as the plugin dll directory + // If Worknet plugins require custom configuration. The plugins are required to override the ConfigFile property so GetConfiguration() method can locate the config.json file. + // Without this override, the default ConfigFile value is read from the PluginsDirectory property, which is relative to the assembly location. + // However, WorkNet plugins are loaded from either ~/.neo/plugins folder or /plugins folder in the worknet exe directory. public override string ConfigFile => System.IO.Path.Combine(AppContext.BaseDirectory, "plugins", "config.json"); protected override void Configure() diff --git a/src/worknet/Node/PluginHandler.cs b/src/worknet/Node/PluginHandler.cs index ad68082..fc9e6db 100644 --- a/src/worknet/Node/PluginHandler.cs +++ b/src/worknet/Node/PluginHandler.cs @@ -13,7 +13,7 @@ public static void LoadPlugins(string directory, TextWriter? writer = null) try { assemblies.Add(Assembly.Load(File.ReadAllBytes(filename))); - Log(writer, $"Loaded plugin: {filename}"); + writer?.WriteLine($"Loaded plugin: {filename}"); } catch { } } @@ -38,15 +38,9 @@ public static void LoadPlugin(Assembly assembly, TextWriter? writer = null) } catch (Exception ex) { - Log(writer, $"Failed to load plugin: {type.FullName}"); - Log(writer, ex.Message); + writer?.WriteLine($"Failed to load plugin: {type.FullName}"); + writer?.WriteLine(ex.Message); } } } - - private static void Log(TextWriter? writer, string message) - { - if (writer is null) return; - writer.WriteLine(message); - } } \ No newline at end of file From faf26fbda138a045e27551281042190be922ffba Mon Sep 17 00:00:00 2001 From: Weijie Lin Date: Tue, 11 Jul 2023 10:12:55 -0700 Subject: [PATCH 10/10] updated readme to include configfile override --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 449cf14..d74edf5 100644 --- a/README.md +++ b/README.md @@ -166,4 +166,6 @@ Neo Worknet's capabilities can be extended through the use of plugins or modules As an illustrative example, we've included a sample Worknet plugin, WorkNetLogger, in the /workenet-ext directory. This plugin is designed to direct Worknet's logs to a specified file. It operates by reading the designated log file path from a custom config.json file, and then recording the logs into this file. +If your Worknet plugin requires custom configuration, it's essential to ensure that the plugin class overrides the ConfigFile property. This enables the GetConfiguration() method to locate the config.json file. Without the override, the default ConfigFile value will be sourced from the PluginsDirectory property, which is relative to the assembly location. + After building the plugin, copy both the "worknet-ext-filelogger.dll" and config.json files to the ~/.neo/plugins directory. Upon startup, Worknet will automatically identify, load and execute the plugin. If preferred, you may also create a /plugins directory within the same directory as the neo-worknet executable, and relocate the DLL to this /plugins directory.