From ef354ccf70b6c6c1248c7b4b99eeaf959b607e29 Mon Sep 17 00:00:00 2001 From: "nieznany.sprawiciel" Date: Fri, 13 Sep 2024 19:36:54 +0200 Subject: [PATCH 1/7] Move ExampleRunner to example directory --- .gitignore | 5 +++-- GolemLib.sln | 2 +- .../ExampleRunner}/ExampleRunner.csproj | 2 +- {ExampleRunner => example/ExampleRunner}/Program.cs | 0 4 files changed, 5 insertions(+), 4 deletions(-) rename {ExampleRunner => example/ExampleRunner}/ExampleRunner.csproj (82%) rename {ExampleRunner => example/ExampleRunner}/Program.cs (100%) diff --git a/.gitignore b/.gitignore index 00228771..f8f70328 100644 --- a/.gitignore +++ b/.gitignore @@ -34,8 +34,8 @@ Mock/obj/ /Golem.Package/tests/ /Golem.Package/package/ -/ExampleRunner/bin/ -/ExampleRunner/obj/ +/example/ExampleRunner/bin/ +/example/ExampleRunner/obj/ /MockGUI/bin/ /MockGUI/obj/ @@ -48,6 +48,7 @@ Mock/obj/ /example/ai-requestor/.venv/ /example/ai-requestor/dist +example/ai-requestor/outputs/ output.png /example/DummyAiHttpServer/__pycache__/ diff --git a/GolemLib.sln b/GolemLib.sln index 52f3de7f..5b7c520c 100644 --- a/GolemLib.sln +++ b/GolemLib.sln @@ -17,7 +17,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Golem.Tools", "Golem.Tools\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Golem.Package", "Golem.Package\Golem.Package.csproj", "{299443D2-91EB-4C12-B654-3B9852E14120}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleRunner", "ExampleRunner\ExampleRunner.csproj", "{35C7BEC1-FA91-4B29-9C6C-48ABA08388D2}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleRunner", "example\ExampleRunner\ExampleRunner.csproj", "{35C7BEC1-FA91-4B29-9C6C-48ABA08388D2}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GolemLib.Tests", "GolemLib.Tests\GolemLib.Tests.csproj", "{840D9798-C88E-4120-B19C-FFE1B62CCBF3}" EndProject diff --git a/ExampleRunner/ExampleRunner.csproj b/example/ExampleRunner/ExampleRunner.csproj similarity index 82% rename from ExampleRunner/ExampleRunner.csproj rename to example/ExampleRunner/ExampleRunner.csproj index d7362193..fb557aba 100644 --- a/ExampleRunner/ExampleRunner.csproj +++ b/example/ExampleRunner/ExampleRunner.csproj @@ -1,7 +1,7 @@ - + diff --git a/ExampleRunner/Program.cs b/example/ExampleRunner/Program.cs similarity index 100% rename from ExampleRunner/Program.cs rename to example/ExampleRunner/Program.cs From 34618b5ce25ba18dc8ec73062c0ee7eacc32cda9 Mon Sep 17 00:00:00 2001 From: "nieznany.sprawiciel" Date: Fri, 13 Sep 2024 19:37:30 +0200 Subject: [PATCH 2/7] run-inference.sh script to simplify usage --- example/ai-requestor/run-inference.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 example/ai-requestor/run-inference.sh diff --git a/example/ai-requestor/run-inference.sh b/example/ai-requestor/run-inference.sh new file mode 100755 index 00000000..e95b3d16 --- /dev/null +++ b/example/ai-requestor/run-inference.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +BASE_URL="https://f48cc2fe53a0.app.modelserve.dev-test.golem.network" +SEQ_NUM=1 +#PROMPT="Beatifull girl riding an unicorn flying above a rainbow." +PROMPT="close up portrait, Amidst the interplay of light and shadows in a photography studio,a soft spotlight traces the contours of a face,highlighting a figure clad in a sleek black turtleneck. The garment,hugging the skin with subtle luxury,complements the Caucasian model's understated makeup,embodying minimalist elegance. Behind,a pale gray backdrop extends,its fine texture shimmering subtly in the dim light,artfully balancing the composition and focusing attention on the subject. In a palette of black,gray,and skin tones,simplicity intertwines with profundity,as every detail whispers untold stories." + +mkdir -p outputs + +curl -X POST -H "Content-Type: application/json" \ + -d '{"prompt": "Beatifull girl riding an unicorn flying above a rainbow.", "num_inference_steps": 24, "guidance_scale": 3.5}' \ + ${BASE_URL}/sdapi/v1/txt2img \ + | jq -r ".images[0]" \ + | base64 --decode > outputs/output-${SEQ_NUM}.png \ + && xdg-open outputs/output-${SEQ_NUM}.png + From 4452bd1152b164e5ec72ba613c38a6592cf3db93 Mon Sep 17 00:00:00 2001 From: "nieznany.sprawiciel" Date: Fri, 13 Sep 2024 20:36:50 +0200 Subject: [PATCH 3/7] Rewrite FacadeHeadlessApp to use GolemViewModel to unify code with MockGUI --- .gitignore | 4 +- FacadeApp/Program.cs | 127 ------------------ FacadeHeadlessApp/Facade.cs | 118 ++++++++++++++++ .../FacadeHeadlessApp.csproj | 1 + .../Properties/launchSettings.json | 0 .../GolemViewModel.cs | 12 +- GolemLib.sln | 2 +- MockGUI/App.axaml.cs | 2 +- 8 files changed, 125 insertions(+), 141 deletions(-) delete mode 100644 FacadeApp/Program.cs create mode 100644 FacadeHeadlessApp/Facade.cs rename FacadeApp/FacadeApp.csproj => FacadeHeadlessApp/FacadeHeadlessApp.csproj (88%) rename {FacadeApp => FacadeHeadlessApp}/Properties/launchSettings.json (100%) rename MockGUI/GolemModel.cs => Golem.Tools/GolemViewModel.cs (96%) diff --git a/.gitignore b/.gitignore index f8f70328..001d306a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,8 @@ GolemLib/bin/ GolemLib/obj/ Mock/bin/ Mock/obj/ -/FacadeApp/bin/ -/FacadeApp/obj/ +/FacadeHeadlessApp/bin/ +/FacadeHeadlessApp/obj/ /Golem/bin/ /Golem/obj/ /Golem.Tests/bin/ diff --git a/FacadeApp/Program.cs b/FacadeApp/Program.cs deleted file mode 100644 index d43bd917..00000000 --- a/FacadeApp/Program.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System.ComponentModel; -using System.Diagnostics; - -using CommandLine; - -using Golem; - -using GolemLib; - -using Microsoft.Extensions.Logging; - -namespace FacadeApp -{ - public class FacadeAppArguments - { - [Option('g', "golem", Required = true, HelpText = "Path to a folder with golem executables")] - public string? GolemPath { get; set; } - [Option('d', "data_dir", Required = false, HelpText = "Path to the provider's data directory")] - public string? DataDir { get; set; } - [Option('m', "mainnet", Default = false, Required = false, HelpText = "Enables usage of mainnet")] - public required bool Mainnet { get; set; } - } - - - internal class Program - { - static async Task Main(string[] args) - { - ILoggerFactory loggerFactory = LoggerFactory.Create(builder => - builder.AddSimpleConsole() - ); - - var logger = loggerFactory.CreateLogger(); - - string golemPath = ""; - string? dataDir = null; - bool mainnet = false; - - Parser.Default.ParseArguments(args) - .WithParsed(o => - { - golemPath = o.GolemPath ?? ""; - dataDir = o.DataDir; - mainnet = o.Mainnet; - }); - - logger.LogInformation("Path: " + golemPath); - logger.LogInformation("DataDir: " + (dataDir ?? "")); - - var binaries = Path.Combine(golemPath, "golem"); - dataDir = Path.Combine(golemPath, "golem-data"); - - await using (var golem = (Golem.Golem)await new Factory().Create(golemPath, loggerFactory, mainnet)) - { - golem.PropertyChanged += new PropertyChangedHandler(logger).For(nameof(IGolem.Status)); - - bool end = false; - - do - { - Console.WriteLine("Start/Stop/End?"); - var line = Console.ReadLine(); - - switch (line) - { - case "Start": - await golem.Start(); - break; - case "Stop": - await golem.Stop(); - break; - case "End": - end = true; - break; - - case "Wallet": - var walletAddress = golem.WalletAddress; - golem.WalletAddress = walletAddress; - Console.WriteLine($"Wallet: {walletAddress}"); - break; - - default: Console.WriteLine($"Didn't understand: {line}"); break; - } - } while (!end); - } - - Console.WriteLine("Done"); - } - } - - public class PropertyChangedHandler - { - - public PropertyChangedHandler(ILogger logger) - { - this.logger = logger; - } - - readonly ILogger logger; - public PropertyChangedEventHandler For(string name) - { - switch (name) - { - case "Status": return Status_PropertyChangedHandler; - case "Activities": return Activities_PropertyChangedHandler; - default: return Empty_PropertyChangedHandler; - } - } - - private void Status_PropertyChangedHandler(object? sender, PropertyChangedEventArgs e) - { - if (sender is Golem.Golem golem && e.PropertyName != "Status") - logger.LogInformation($"Status property has changed: {e.PropertyName} to {golem.Status}"); - } - - private void Activities_PropertyChangedHandler(object? sender, PropertyChangedEventArgs e) - { - if (sender is Golem.Golem golem && e.PropertyName != "Activities") - logger.LogInformation($"Activities property has changed: {e.PropertyName}. Current job: {golem.CurrentJob}"); - } - - private void Empty_PropertyChangedHandler(object? sender, PropertyChangedEventArgs e) - { - logger.LogInformation($"Property {e} is not supported in this context"); - } - } -} diff --git a/FacadeHeadlessApp/Facade.cs b/FacadeHeadlessApp/Facade.cs new file mode 100644 index 00000000..f99f2c4f --- /dev/null +++ b/FacadeHeadlessApp/Facade.cs @@ -0,0 +1,118 @@ +using System.ComponentModel; +using System.Diagnostics; + +using CommandLine; + +using Golem; +using GolemLib; +using Golem.Tools.ViewModels; + +using Microsoft.Extensions.Logging; + +namespace FacadeHeadlessApp; + +public class FacadeAppArguments +{ + [Option('g', "golem", Required = true, HelpText = "Path to a folder with golem executables (modules)")] + public string? GolemPath { get; set; } + [Option('d', "use-dll", Required = false, HelpText = "Load Golem object from dll found in binaries directory. (Simulates how GamerHash will use it. Otherwise project dependency will be used.)")] + public bool UseDll { get; set; } + [Option('r', "relay", Default = RelayType.Central, Required = false, HelpText = "Change relay to devnet yacn2a or setup local")] + public required RelayType Relay { get; set; } + [Option('m', "mainnet", Default = false, Required = false, HelpText = "Enables usage of mainnet")] + public bool Mainnet { get; set; } +} + + +internal class Facade +{ + static async Task Main(string[] argsArray) + { + ILoggerFactory loggerFactory = LoggerFactory.Create(builder => + builder.AddSimpleConsole() + ); + + var logger = loggerFactory.CreateLogger(); + + var args = Parser.Default.ParseArguments(argsArray).Value; + string golemPath = args.GolemPath ?? ""; + + logger.LogInformation("Path: " + golemPath); + + await using GolemViewModel view = args.UseDll ? + await GolemViewModel.Load(golemPath, args.Relay, args.Mainnet) : + await GolemViewModel.CreateStatic(golemPath, args.Relay, args.Mainnet); + + var golem = view.Golem; + golem.PropertyChanged += new PropertyChangedHandler(logger).For(nameof(IGolem.Status)); + + bool end = false; + + do + { + Console.WriteLine("Start/Stop/End?"); + var line = Console.ReadLine(); + + switch (line) + { + case "Start": + await golem.Start(); + break; + case "Stop": + await golem.Stop(); + break; + case "End": + end = true; + break; + + case "Wallet": + var walletAddress = golem.WalletAddress; + golem.WalletAddress = walletAddress; + Console.WriteLine($"Wallet: {walletAddress}"); + break; + + default: Console.WriteLine($"Didn't understand: {line}"); break; + } + } while (!end); + + + Console.WriteLine("Done"); + } +} + +public class PropertyChangedHandler +{ + + public PropertyChangedHandler(ILogger logger) + { + this.logger = logger; + } + + readonly ILogger logger; + public PropertyChangedEventHandler For(string name) + { + switch (name) + { + case "Status": return Status_PropertyChangedHandler; + case "Activities": return Activities_PropertyChangedHandler; + default: return Empty_PropertyChangedHandler; + } + } + + private void Status_PropertyChangedHandler(object? sender, PropertyChangedEventArgs e) + { + if (sender is Golem.Golem golem && e.PropertyName != "Status") + logger.LogInformation($"Status property has changed: {e.PropertyName} to {golem.Status}"); + } + + private void Activities_PropertyChangedHandler(object? sender, PropertyChangedEventArgs e) + { + if (sender is Golem.Golem golem && e.PropertyName != "Activities") + logger.LogInformation($"Activities property has changed: {e.PropertyName}. Current job: {golem.CurrentJob}"); + } + + private void Empty_PropertyChangedHandler(object? sender, PropertyChangedEventArgs e) + { + logger.LogInformation($"Property {e} is not supported in this context"); + } +} diff --git a/FacadeApp/FacadeApp.csproj b/FacadeHeadlessApp/FacadeHeadlessApp.csproj similarity index 88% rename from FacadeApp/FacadeApp.csproj rename to FacadeHeadlessApp/FacadeHeadlessApp.csproj index 60c2b473..54302a85 100644 --- a/FacadeApp/FacadeApp.csproj +++ b/FacadeHeadlessApp/FacadeHeadlessApp.csproj @@ -14,6 +14,7 @@ + diff --git a/FacadeApp/Properties/launchSettings.json b/FacadeHeadlessApp/Properties/launchSettings.json similarity index 100% rename from FacadeApp/Properties/launchSettings.json rename to FacadeHeadlessApp/Properties/launchSettings.json diff --git a/MockGUI/GolemModel.cs b/Golem.Tools/GolemViewModel.cs similarity index 96% rename from MockGUI/GolemModel.cs rename to Golem.Tools/GolemViewModel.cs index 45c8cf19..885df9dc 100644 --- a/MockGUI/GolemModel.cs +++ b/Golem.Tools/GolemViewModel.cs @@ -1,23 +1,15 @@ -using System; using System.Collections.ObjectModel; using System.ComponentModel; -using System.IO; using System.Runtime.CompilerServices; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; using GolemLib; using App; using System.Reflection; -using Microsoft.Extensions.Logging.Abstractions; -using Golem.Tools; -using Golem; -using System.Collections.Generic; -using Golem.Yagna.Types; using GolemLib.Types; -namespace MockGUI.ViewModels +namespace Golem.Tools.ViewModels { public class GolemViewModel : INotifyPropertyChanged, IAsyncDisposable { @@ -100,7 +92,7 @@ static async Task Create(string modulesDir, Func Date: Mon, 16 Sep 2024 11:58:38 +0200 Subject: [PATCH 4/7] Add non-interactive mode; Ability to set wallet --- FacadeHeadlessApp/Facade.cs | 91 +++++++++++++++++++------------- Golem.Tools/Console.cs | 20 +++++++ example/ExampleRunner/Program.cs | 17 ++---- 3 files changed, 76 insertions(+), 52 deletions(-) create mode 100644 Golem.Tools/Console.cs diff --git a/FacadeHeadlessApp/Facade.cs b/FacadeHeadlessApp/Facade.cs index f99f2c4f..fdcc123b 100644 --- a/FacadeHeadlessApp/Facade.cs +++ b/FacadeHeadlessApp/Facade.cs @@ -8,6 +8,7 @@ using Golem.Tools.ViewModels; using Microsoft.Extensions.Logging; +using Golem.Tools; namespace FacadeHeadlessApp; @@ -21,6 +22,10 @@ public class FacadeAppArguments public required RelayType Relay { get; set; } [Option('m', "mainnet", Default = false, Required = false, HelpText = "Enables usage of mainnet")] public bool Mainnet { get; set; } + [Option('w', "wallet", Required = false, HelpText = "Wallet address to receive funds")] + public string? Wallet { get; set; } + [Option('i', "interactive", Default = false, HelpText = "Enable interactive console mode")] + public bool Interactive { get; set; } } @@ -44,39 +49,49 @@ await GolemViewModel.Load(golemPath, args.Relay, args.Mainnet) : await GolemViewModel.CreateStatic(golemPath, args.Relay, args.Mainnet); var golem = view.Golem; + if (args.Wallet != null) + golem.WalletAddress = args.Wallet; golem.PropertyChanged += new PropertyChangedHandler(logger).For(nameof(IGolem.Status)); - bool end = false; - do + if (args.Interactive) { - Console.WriteLine("Start/Stop/End?"); - var line = Console.ReadLine(); + bool end = false; - switch (line) + do { - case "Start": - await golem.Start(); - break; - case "Stop": - await golem.Stop(); - break; - case "End": - end = true; - break; - - case "Wallet": - var walletAddress = golem.WalletAddress; - golem.WalletAddress = walletAddress; - Console.WriteLine($"Wallet: {walletAddress}"); - break; - - default: Console.WriteLine($"Didn't understand: {line}"); break; - } - } while (!end); - - - Console.WriteLine("Done"); + Console.WriteLine("Start/Stop/End?"); + var line = Console.ReadLine(); + + switch (line) + { + case "Start": + await golem.Start(); + break; + case "Stop": + await golem.Stop(); + break; + case "End": + end = true; + break; + case "Wallet": + var walletAddress = golem.WalletAddress; + golem.WalletAddress = walletAddress; + Console.WriteLine($"Wallet: {walletAddress}"); + break; + + default: Console.WriteLine($"Didn't understand: {line}"); break; + } + } while (!end); + + + Console.WriteLine("Done"); + } + else + { + await golem.Start(); + ConsoleHelper.WaitForCtrlC(); + } } } @@ -85,34 +100,34 @@ public class PropertyChangedHandler public PropertyChangedHandler(ILogger logger) { - this.logger = logger; + this._logger = logger; } - readonly ILogger logger; + readonly ILogger _logger; public PropertyChangedEventHandler For(string name) { - switch (name) + return name switch { - case "Status": return Status_PropertyChangedHandler; - case "Activities": return Activities_PropertyChangedHandler; - default: return Empty_PropertyChangedHandler; - } + "Status" => Status_PropertyChangedHandler, + "Activities" => Activities_PropertyChangedHandler, + _ => Empty_PropertyChangedHandler, + }; } private void Status_PropertyChangedHandler(object? sender, PropertyChangedEventArgs e) { - if (sender is Golem.Golem golem && e.PropertyName != "Status") - logger.LogInformation($"Status property has changed: {e.PropertyName} to {golem.Status}"); + if (sender is Golem.Golem golem && e.PropertyName == "Status") + _logger.LogInformation($"Status property has changed: {e.PropertyName} to {golem.Status}"); } private void Activities_PropertyChangedHandler(object? sender, PropertyChangedEventArgs e) { if (sender is Golem.Golem golem && e.PropertyName != "Activities") - logger.LogInformation($"Activities property has changed: {e.PropertyName}. Current job: {golem.CurrentJob}"); + _logger.LogInformation($"Activities property has changed: {e.PropertyName}. Current job: {golem.CurrentJob}"); } private void Empty_PropertyChangedHandler(object? sender, PropertyChangedEventArgs e) { - logger.LogInformation($"Property {e} is not supported in this context"); + _logger.LogInformation($"Property {e} is not supported in this context"); } } diff --git a/Golem.Tools/Console.cs b/Golem.Tools/Console.cs new file mode 100644 index 00000000..918fbf7d --- /dev/null +++ b/Golem.Tools/Console.cs @@ -0,0 +1,20 @@ + +namespace Golem.Tools; + + +public class ConsoleHelper +{ + public static void WaitForCtrlC() + { + Console.TreatControlCAsInput = true; + + ConsoleKeyInfo cki; + do + { + cki = Console.ReadKey(); + } while (!(((cki.Modifiers & ConsoleModifiers.Control) != 0) && (cki.Key == ConsoleKey.C))); + } +} + + + diff --git a/example/ExampleRunner/Program.cs b/example/ExampleRunner/Program.cs index 13287a80..5e552246 100644 --- a/example/ExampleRunner/Program.cs +++ b/example/ExampleRunner/Program.cs @@ -4,7 +4,7 @@ using Golem; -using GolemLib; +using Golem.Tools; using Microsoft.Extensions.Logging; @@ -63,7 +63,7 @@ static void Main(string[] args) logger.LogInformation("Press Ctrl+C To Terminate"); - waitForCtrlC(); + ConsoleHelper.WaitForCtrlC(); Task[] tasks = new Task[2]; tasks[0] = Task.Run(() => @@ -75,7 +75,7 @@ static void Main(string[] args) tasks[1] = Task.Run(() => { - waitForCtrlC(); + ConsoleHelper.WaitForCtrlC(); logger.LogInformation("Captured second Ctrl-C. Killing..."); App.Kill().Wait(100); @@ -84,15 +84,4 @@ static void Main(string[] args) Task.WaitAny(tasks); } - - static void waitForCtrlC() - { - Console.TreatControlCAsInput = true; - - ConsoleKeyInfo cki; - do - { - cki = Console.ReadKey(); - } while (!(((cki.Modifiers & ConsoleModifiers.Control) != 0) && (cki.Key == ConsoleKey.C))); - } } From d63860bf34e22bcd6374b5e04bbbf8504bfa9722 Mon Sep 17 00:00:00 2001 From: "nieznany.sprawiciel" Date: Mon, 16 Sep 2024 13:16:08 +0200 Subject: [PATCH 5/7] Fix FacadeHeadlessApp help --- FacadeHeadlessApp/Facade.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/FacadeHeadlessApp/Facade.cs b/FacadeHeadlessApp/Facade.cs index fdcc123b..af2f4840 100644 --- a/FacadeHeadlessApp/Facade.cs +++ b/FacadeHeadlessApp/Facade.cs @@ -40,6 +40,9 @@ static async Task Main(string[] argsArray) var logger = loggerFactory.CreateLogger(); var args = Parser.Default.ParseArguments(argsArray).Value; + if (args == null) + return; + string golemPath = args.GolemPath ?? ""; logger.LogInformation("Path: " + golemPath); From cc298e26357faf29636d288aa6500da5c6f6ba65 Mon Sep 17 00:00:00 2001 From: "nieznany.sprawiciel" Date: Mon, 16 Sep 2024 13:47:16 +0200 Subject: [PATCH 6/7] Build docker containing all necessary applications --- Dockerfile | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..f605dfb0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build + +# Install python, because Golem.Tools require it +RUN apt-get update && apt-get install -y python3 python3-venv python3-pip +RUN ln -s /usr/bin/python3 /usr/bin/python +RUN pip3 install pyinstaller + +RUN git clone https://github.com/golemfactory/gamerhash-facade.git +WORKDIR /gamerhash-facade +RUN git checkout headless-facade + +# Build necessary application +RUN dotnet build FacadeHeadlessApp +RUN dotnet build Golem.Package + +RUN dotnet publish FacadeHeadlessApp --no-restore -o /apps +RUN dotnet publish Golem.Package --no-restore -o /apps + + +FROM mcr.microsoft.com/dotnet/runtime:7.0-jammy + +WORKDIR /apps +COPY --from=build /apps . + +RUN ./Golem.Package download --target modules --version v5.1.0 +ENTRYPOINT ./FacadeHeadlessApp --golem modules --wallet 0x82a630d2447ffd282657978f9f76c02da8be9819 From 89b63673d6a1a4be6c79625a18e4b041f61d7fd9 Mon Sep 17 00:00:00 2001 From: "nieznany.sprawiciel" Date: Mon, 16 Sep 2024 14:35:37 +0200 Subject: [PATCH 7/7] Fix waiting for shutdown --- Dockerfile | 6 ++++-- FacadeHeadlessApp/Facade.cs | 2 +- Golem.Tools/Console.cs | 30 +++++++++++++++++++++++++++++- Golem/ActivityLoop.cs | 4 ++-- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index f605dfb0..af87f962 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build -# Install python, because Golem.Tools require it +# Install python, because Golem.Tools need it to build App and it is dependency +# of `FacadeHeadlessApp` so we have no choice. RUN apt-get update && apt-get install -y python3 python3-venv python3-pip RUN ln -s /usr/bin/python3 /usr/bin/python RUN pip3 install pyinstaller @@ -23,4 +24,5 @@ WORKDIR /apps COPY --from=build /apps . RUN ./Golem.Package download --target modules --version v5.1.0 -ENTRYPOINT ./FacadeHeadlessApp --golem modules --wallet 0x82a630d2447ffd282657978f9f76c02da8be9819 +ENTRYPOINT ["./FacadeHeadlessApp", "--golem", "modules"] +CMD ["--wallet", "0x82a630d2447ffd282657978f9f76c02da8be9819"] diff --git a/FacadeHeadlessApp/Facade.cs b/FacadeHeadlessApp/Facade.cs index af2f4840..d1ee7663 100644 --- a/FacadeHeadlessApp/Facade.cs +++ b/FacadeHeadlessApp/Facade.cs @@ -93,7 +93,7 @@ await GolemViewModel.Load(golemPath, args.Relay, args.Mainnet) : else { await golem.Start(); - ConsoleHelper.WaitForCtrlC(); + await ConsoleHelper.WaitForCancellation(); } } } diff --git a/Golem.Tools/Console.cs b/Golem.Tools/Console.cs index 918fbf7d..90d02ef6 100644 --- a/Golem.Tools/Console.cs +++ b/Golem.Tools/Console.cs @@ -14,7 +14,35 @@ public static void WaitForCtrlC() cki = Console.ReadKey(); } while (!(((cki.Modifiers & ConsoleModifiers.Control) != 0) && (cki.Key == ConsoleKey.C))); } -} + // Based on: https://www.meziantou.net/handling-cancelkeypress-using-a-cancellationtoken.htm + public static async Task WaitForCancellation() + { + using var cts = new CancellationTokenSource(); + Console.CancelKeyPress += (sender, e) => + { + // We'll stop the process manually by using the CancellationToken + e.Cancel = true; + + // Change the state of the CancellationToken to "Canceled" + // - Set the IsCancellationRequested property to true + // - Call the registered callbacks + cts.Cancel(); + }; + while (true) + { + try + { + // We can't pass TimeSpan.MaxValue because it will throw an exception. + await Task.Delay(TimeSpan.FromHours(1), cts.Token); + } + catch (Exception e) when (e.IsCancelled()) + { + Console.WriteLine("Application received cancellation signal. Exiting..."); + return; + } + } + } +} diff --git a/Golem/ActivityLoop.cs b/Golem/ActivityLoop.cs index 956aa355..8f602ad5 100644 --- a/Golem/ActivityLoop.cs +++ b/Golem/ActivityLoop.cs @@ -51,10 +51,10 @@ public async Task ActivitiesLoop() _logger.LogDebug("Monitoring activities"); newReconnect = await ReconnectDelay(newReconnect, _token); - _token.ThrowIfCancellationRequested(); - try { + _token.ThrowIfCancellationRequested(); + await foreach (var trackingEvent in _yagnaApi.ActivityMonitorStream(_token)) { var activities = trackingEvent?.Activities ?? new List();