From 1b9a6560aa95bdc2b5f2c53df937f14804d9b436 Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 19 Sep 2022 14:02:05 +0300 Subject: [PATCH 1/9] Fix node native runner for Mac --- controller/native/install.go | 17 +++++------------ controller/native/runner.go | 7 +++---- controller/native/utils_unix.go | 5 ++++- controller/native/utils_win32.go | 14 ++++++++++++++ myst/manager.go | 3 +-- utils/utils_darwin.go | 2 +- utils/utils_unix.go | 12 +++++++++++- 7 files changed, 39 insertions(+), 21 deletions(-) diff --git a/controller/native/install.go b/controller/native/install.go index 7c2171b..470c88f 100644 --- a/controller/native/install.go +++ b/controller/native/install.go @@ -8,12 +8,12 @@ import ( "sync" "github.com/codingsince1985/checksum" - wapi "github.com/iamacarpet/go-win64api" - _const "github.com/mysteriumnetwork/myst-launcher/const" "github.com/mysteriumnetwork/myst-launcher/model" "github.com/mysteriumnetwork/myst-launcher/updates" "github.com/mysteriumnetwork/myst-launcher/utils" + _const "github.com/mysteriumnetwork/myst-launcher/const" + ) const ( @@ -136,17 +136,10 @@ var once sync.Once func tryInstallFirewallRules(ui model.Gui_) { once.Do(func() { - // check firewall rules - needFirewallSetup := false - rule, err := wapi.FirewallRuleGet(fwRuleNameUDP) - if err != nil || rule.Name == "" { - needFirewallSetup = true - } - rule, err = wapi.FirewallRuleGet(fwRuleNameTCP) - if err != nil || rule.Name == "" { - needFirewallSetup = true - } + // check firewall rules + needFirewallSetup := checkFirewallRules() + if needFirewallSetup { ret := ui.YesNoModal("Installation", "Firewall rule missing, addition is required. Press Yes to approve.") if ret == model.IDYES { diff --git a/controller/native/runner.go b/controller/native/runner.go index c2f64c3..347f6bd 100644 --- a/controller/native/runner.go +++ b/controller/native/runner.go @@ -110,18 +110,17 @@ func (r *NodeRunner) startNode() error { dataDirArg := fmt.Sprintf("--data-dir=%s", r.configpath) userspaceArg := "--userspace" + args := []string{userspaceArg, versionArg, configDirArg, dataDirArg, "service", "--agreed-terms-and-conditions"} + switch runtime.GOOS { case "windows": - args := []string{userspaceArg, versionArg, configDirArg, dataDirArg, "service", "--agreed-terms-and-conditions"} if err := utils.CmdStart(fullExePath, args...); err != nil { log.Println("run node failed:", err) return err } case "darwin": - // cmd = exec.Command("open", "/Applications/Docker.app/") - r.cmd = exec.Command(fullExePath, versionArg, configDirArg, dataDirArg, "service", "--agreed-terms-and-conditions") - if err := r.cmd.Start(); err != nil { + if err := utils.CmdStart(fullExePath, args...); err != nil { log.Println("run node failed:", err) return err } diff --git a/controller/native/utils_unix.go b/controller/native/utils_unix.go index 7b15bc4..8d3af06 100644 --- a/controller/native/utils_unix.go +++ b/controller/native/utils_unix.go @@ -11,5 +11,8 @@ func extractNodeBinary(src, dest string) error { return extractor.NewTgz().Extract(src, dest) } -func CheckAndInstallFirewall() { +func CheckAndInstallFirewall() {} + +func checkFirewallRules() bool { + return false } \ No newline at end of file diff --git a/controller/native/utils_win32.go b/controller/native/utils_win32.go index f4a574a..28cc274 100644 --- a/controller/native/utils_win32.go +++ b/controller/native/utils_win32.go @@ -34,3 +34,17 @@ func CheckAndInstallFirewallRules() { log.Println(err) } } + +// returns true if some firewall rules to be setup +func checkFirewallRules() bool { + rule, err := wapi.FirewallRuleGet(fwRuleNameUDP) + if err != nil || rule.Name == "" { + return true + } + + rule, err = wapi.FirewallRuleGet(fwRuleNameTCP) + if err != nil || rule.Name == "" { + return = true + } + return false +} diff --git a/myst/manager.go b/myst/manager.go index 3ef8e63..7518afc 100644 --- a/myst/manager.go +++ b/myst/manager.go @@ -16,7 +16,6 @@ import ( "io/ioutil" "log" "os" - "runtime" "strconv" "strings" "time" @@ -179,7 +178,7 @@ func extractRepoDigests(repoDigests []string) []string { func (m *Manager) launcherVersionChanged(mystContainer *Container) bool { launcherVer := getVersionFromCommand(mystContainer.Command) - currentVersion := m.model.ProductVersion + "/" + runtime.GOOS + currentVersion := m.model.GetProductVersionString() return launcherVer != currentVersion && launcherVer != "" } diff --git a/utils/utils_darwin.go b/utils/utils_darwin.go index 8c871a4..e191a76 100644 --- a/utils/utils_darwin.go +++ b/utils/utils_darwin.go @@ -19,7 +19,7 @@ import ( func TerminateProcess(pid uint32, exitcode int) error { sig := C.int(2) //9-kill - ret := C.proc_terminate(17234, &sig) + ret := C.proc_terminate(C.int(pid), &sig) if ret != 0 { return errors.New("Process not found") } diff --git a/utils/utils_unix.go b/utils/utils_unix.go index 49163b3..870635b 100644 --- a/utils/utils_unix.go +++ b/utils/utils_unix.go @@ -45,11 +45,21 @@ func HasDocker() (bool, error) { return res == 0 || res == 1, nil } +var productVersion string + +func SetProductVersion(ver string) { + productVersion = ver +} + func GetProductVersion() (string, error) { - return "", nil + return productVersion, nil } // install exe if n/e func CheckAndInstallExe() error { return nil } + +func RunasWithArgsAndWait(cmdArgs string) error { + panic("not implemented") +} From bf0d3b58beb91abcf02f3236cf1fb0e9aaec93e4 Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 19 Sep 2022 19:19:15 +0300 Subject: [PATCH 2/9] Save config if on launcher version change --- model/state.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/model/state.go b/model/state.go index 90ce6d9..468353a 100644 --- a/model/state.go +++ b/model/state.go @@ -9,6 +9,7 @@ package model import ( "encoding/json" + "fmt" "log" "os" "time" @@ -108,17 +109,22 @@ func (c *Config) getDefaultValues(isNewFile bool) { c.PortRangeBegin = 42000 c.PortRangeEnd = 42100 - // if fresh file -> native - // if has version -> prev - // if no version -> docker + if c.Backend == "" { + // if fresh file -> native + // if has version -> prev + // if no version -> docker - c.Backend = "native" - if !isNewFile { - if c.LauncherVersion == "" { - c.Backend = "docker" + c.Backend = "native" + if !isNewFile { + if c.LauncherVersion == "" { + c.Backend = "docker" + } } } - c.LauncherVersion = prodVersion + if c.LauncherVersion != prodVersion { + c.LauncherVersion = prodVersion + c.Save() + } } func (c *Config) Read() { From 1d464715adabce49e5ae4ab62d9a3873a6f3727f Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 19 Sep 2022 19:25:49 +0300 Subject: [PATCH 3/9] Fix compile error --- controller/native/install.go | 3 ++- controller/native/utils_win32.go | 2 +- model/state.go | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/controller/native/install.go b/controller/native/install.go index 470c88f..756c246 100644 --- a/controller/native/install.go +++ b/controller/native/install.go @@ -63,6 +63,7 @@ func (c *Controller) CheckAndUpgradeNodeExe(forceUpgrade bool) bool { mdl.ImageInfo.VersionLatest = tagLatest mdl.ImageInfo.VersionCurrent = cfg.NodeExeVersion mdl.ImageInfo.HasUpdate = tagLatest != cfg.NodeExeVersion + defer func() { cfg.NodeLatestTag = tagLatest cfg.NodeExeVersion = tagLatest @@ -82,7 +83,7 @@ func (c *Controller) CheckAndUpgradeNodeExe(forceUpgrade bool) bool { utils.TerminateProcess(p, 0) } - if c.a.GetModel().Config.AutoUpgrade || sha256 == "" { + if cfg.AutoUpgrade || sha256 == "" { c.tryInstall() sha256, _ := checksum.SHA256sum(fullpath) diff --git a/controller/native/utils_win32.go b/controller/native/utils_win32.go index 28cc274..a064d68 100644 --- a/controller/native/utils_win32.go +++ b/controller/native/utils_win32.go @@ -44,7 +44,7 @@ func checkFirewallRules() bool { rule, err = wapi.FirewallRuleGet(fwRuleNameTCP) if err != nil || rule.Name == "" { - return = true + return true } return false } diff --git a/model/state.go b/model/state.go index 468353a..c3d7e3d 100644 --- a/model/state.go +++ b/model/state.go @@ -9,7 +9,6 @@ package model import ( "encoding/json" - "fmt" "log" "os" "time" From 20d846377fd5fd5c5256f7963018c140cb60a753 Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Mon, 31 Oct 2022 17:22:25 +0400 Subject: [PATCH 4/9] Stop node on launcher exit --- controller/docker/docker.go | 3 ++- controller/native/node.go | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/controller/docker/docker.go b/controller/docker/docker.go index e7569c8..01fc0bb 100644 --- a/controller/docker/docker.go +++ b/controller/docker/docker.go @@ -87,7 +87,6 @@ func (c *Controller) Start() { c.upgradeContainer(false) } - // c.lg.Println("wait action >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") select { case act := <-action: c.lg.Println("action:", act) @@ -121,6 +120,8 @@ func (c *Controller) Start() { case model_.ActionStop: c.lg.Println("[docker] stop") + mdl.SetStateContainer(model_.RunnableStateUnknown) + mystManager.Stop() return } diff --git a/controller/native/node.go b/controller/native/node.go index f11a7d5..a59307e 100644 --- a/controller/native/node.go +++ b/controller/native/node.go @@ -107,6 +107,8 @@ func (c *Controller) Start() { case model_.ActionStop: c.lg.Println("[native] stop") + model.SetStateContainer(model_.RunnableStateUnknown) + c.stop() return } From a8a44bb4e11e4bfcb38b81d3e01b958e93425506 Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Tue, 1 Nov 2022 01:38:26 +0400 Subject: [PATCH 5/9] Fix autostart action --- cmd/app/app.go | 4 +-- go.mod | 1 + gui-win32/menu.go | 2 +- platform/manager_win32.go | 53 ++++++++++++++++++++++++--------------- utils/utils_win32.go | 23 +++++++++++------ 5 files changed, 52 insertions(+), 31 deletions(-) diff --git a/cmd/app/app.go b/cmd/app/app.go index 3a087cd..1040668 100644 --- a/cmd/app/app.go +++ b/cmd/app/app.go @@ -59,8 +59,8 @@ func main() { return } } - utils.EnableAutorun(mod.Config.AutoStart) - + err := utils.EnableAutorun(mod.Config.AutoStart) + fmt.Println("utils.EnableAutorun", err) prodVersion, _ := utils.GetProductVersion() mod.SetProductVersion(prodVersion) diff --git a/go.mod b/go.mod index 57b6b66..e24b9c6 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pkg/errors v0.9.1 + github.com/scjalliance/comshim v0.0.0-20190308082608-cf06d2532c4e // indirect github.com/stretchr/testify v1.7.0 github.com/tc-hib/winres v0.1.5 github.com/tryor/gdiplus v0.0.0-20200830101413-c570de9579b3 diff --git a/gui-win32/menu.go b/gui-win32/menu.go index b326645..a4c772a 100644 --- a/gui-win32/menu.go +++ b/gui-win32/menu.go @@ -34,7 +34,7 @@ func (g *Gui) menu() []MenuItem { Separator{}, Action{ Checked: Bind("isAutostartEnabled"), - Text: "Autostart launcher", + Text: "Start with Windows", OnTriggered: func() { g.model.TriggerAutostartAction() }, diff --git a/platform/manager_win32.go b/platform/manager_win32.go index 8718801..7fddea4 100644 --- a/platform/manager_win32.go +++ b/platform/manager_win32.go @@ -6,12 +6,12 @@ package platform import ( "fmt" "log" - "runtime" "strings" "github.com/gabriel-samfira/go-wmi/wmi" "github.com/google/glazier/go/dism" "github.com/pkg/errors" + "github.com/scjalliance/comshim" "golang.org/x/sys/windows" ) @@ -29,29 +29,27 @@ var features = []string{ type Manager struct { hasDism bool - con *wmi.WMI ses dism.Session } func NewManager() (*Manager, error) { + m := &Manager{} + return m, nil +} - // once - runtime.LockOSThread() - - w, err := wmi.NewConnection(".", `root\cimv2`) - if err != nil { - return nil, err - } +func wmiAPIInit() (*wmi.WMI, error) { + comshim.Add(1) + return wmi.NewConnection(".", `root\cimv2`) +} - m := &Manager{ - con: w, - } - return m, nil +func wmiAPIRelease(w *wmi.WMI) { + w.Close() + comshim.Done() } -func (m *Manager) queryOptionalFeature(feature string) (error, bool) { +func (m *Manager) queryOptionalFeature(con *wmi.WMI, feature string) (error, bool) { log.Println("Query optional feature:", feature) - res, err := m.con.CallMethod("ExecQuery", fmt.Sprintf("SELECT * FROM Win32_OptionalFeature Where Name='%s'", feature)) + res, err := con.CallMethod("ExecQuery", fmt.Sprintf("SELECT * FROM Win32_OptionalFeature Where Name='%s'", feature)) if err != nil { return errors.Wrap(err, "ExecQuery"), false } @@ -71,8 +69,11 @@ func (m *Manager) queryOptionalFeature(feature string) (error, bool) { } func (m *Manager) Features() (bool, error) { + w, _ := wmiAPIInit() + defer wmiAPIRelease(w) + for _, f := range features { - err, installed := m.queryOptionalFeature(f) + err, installed := m.queryOptionalFeature(w, f) if err != nil { log.Println("Features >", err) return false, err @@ -86,7 +87,10 @@ func (m *Manager) Features() (bool, error) { } func (m *Manager) SystemUnderVm() (bool, error) { - res, err := m.con.CallMethod("ExecQuery", "SELECT * FROM Win32_ComputerSystem") + con,_ := wmiAPIInit() + defer wmiAPIRelease(con) + + res, err := con.CallMethod("ExecQuery", "SELECT * FROM Win32_ComputerSystem") if err != nil { return false, errors.Wrap(err, "ExecQuery") } @@ -116,7 +120,10 @@ func (m *Manager) SystemUnderVm() (bool, error) { */ func (m *Manager) IsVMcomputeRunning() (bool, error) { - res, err := m.con.CallMethod("ExecQuery", "SELECT * FROM Win32_Service Where Name='vmcompute'") + con,_ := wmiAPIInit() + defer wmiAPIRelease(con) + + res, err := con.CallMethod("ExecQuery", "SELECT * FROM Win32_Service Where Name='vmcompute'") if err != nil { return false, errors.Wrap(err, "ExecQuery") } @@ -133,7 +140,10 @@ func (m *Manager) IsVMcomputeRunning() (bool, error) { } func (m *Manager) StartVmcomputeIfNotRunning() (bool, error) { - res, err := m.con.CallMethod("ExecQuery", "SELECT * FROM Win32_Service Where Name='vmcompute'") + con,_ := wmiAPIInit() + defer wmiAPIRelease(con) + + res, err := con.CallMethod("ExecQuery", "SELECT * FROM Win32_Service Where Name='vmcompute'") if err != nil { return false, errors.Wrap(err, "ExecQuery") } @@ -166,7 +176,10 @@ func (m *Manager) StartVmcomputeIfNotRunning() (bool, error) { // We can not use the IsProcessorFeaturePresent approach, as it does not matter in self-virtualized environment // see https://devblogs.microsoft.com/oldnewthing/20201216-00/?p=104550 func (m *Manager) HasVTx() (bool, error) { - res, err := m.con.CallMethod("ExecQuery", "SELECT * FROM Win32_ComputerSystem") + con,_ := wmiAPIInit() + defer wmiAPIRelease(con) + + res, err := con.CallMethod("ExecQuery", "SELECT * FROM Win32_ComputerSystem") if err != nil { return false, errors.Wrap(err, "ExecQuery") } diff --git a/utils/utils_win32.go b/utils/utils_win32.go index b2a9ced..0a89cf8 100644 --- a/utils/utils_win32.go +++ b/utils/utils_win32.go @@ -22,7 +22,8 @@ import ( "time" "unsafe" - "github.com/blang/semver/v4" + "github.com/scjalliance/comshim" + "github.com/blang/semver/v4" "github.com/go-ole/go-ole" "github.com/go-ole/go-ole/oleutil" "github.com/gonutz/w32" @@ -50,6 +51,9 @@ func getSysProcAttrs() syscall.SysProcAttr { } func CreateShortcut(dst, target, args string) error { + comshim.Add(1) + defer comshim.Done() + oleShellObject, err := oleutil.CreateObject("WScript.Shell") if err != nil { return err @@ -155,7 +159,10 @@ func RunWithArgsNoWait(cmdArgs string) error { func EnableAutorun(en bool) error { // re-create - CreateAutostartShortcut("") + err := CreateAutostartShortcut("") + if err != nil { + return err + } k, _, err := registry.CreateKey(registry.CURRENT_USER, `SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\StartupFolder`, registry.ALL_ACCESS) if err != nil { @@ -220,21 +227,21 @@ func MystNodeLauncherExePath() string { return os.Getenv("ProgramFiles") + "\\MystNodeLauncher" + "\\" + launcherExe } -func CreateAutostartShortcut(args string) { +func CreateAutostartShortcut(args string) error { shcDst := path.Join(os.Getenv("APPDATA"), "Microsoft\\Windows\\Start Menu\\Programs\\Startup", launcherLnk) - CreateShortcut(shcDst, MystNodeLauncherExePath(), args) + return CreateShortcut(shcDst, MystNodeLauncherExePath(), args) } -func CreateDesktopShortcut(args string) { +func CreateDesktopShortcut(args string) error { shcDst := path.Join(os.Getenv("USERPROFILE"), "Desktop", launcherLnk) - CreateShortcut(shcDst, MystNodeLauncherExePath(), args) + return CreateShortcut(shcDst, MystNodeLauncherExePath(), args) } -func CreateStartMenuShortcut(args string) { +func CreateStartMenuShortcut(args string) error { dir := path.Join(os.Getenv("APPDATA"), "Microsoft\\Windows\\Start Menu\\Programs\\Mysterium Network") os.Mkdir(dir, os.ModePerm) shcDst := path.Join(dir, launcherLnk) - CreateShortcut(shcDst, MystNodeLauncherExePath(), args) + return CreateShortcut(shcDst, MystNodeLauncherExePath(), args) } func IsWindowsVersionCompatible() bool { From c9e5c6221d9f3676c59d7a44cf554f58a53f02a6 Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Wed, 2 Nov 2022 01:19:38 +0400 Subject: [PATCH 6/9] Use a flag for debug instead of special exe --- .github/workflows/release.yml | 2 -- cmd/app/app.go | 25 ++++++++++++++++++------ const/flags.go | 1 + go.mod | 2 +- utils/utils_win32.go | 36 +++++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 48d2d99..ba255b0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,6 @@ jobs: run: | go run cmd/resource/resource.go go build -v -trimpath -ldflags "-s -w -H windowsgui" -o bin/myst-launcher-amd64.exe github.com/mysteriumnetwork/myst-launcher/cmd/app - go build -v -trimpath -ldflags "-s -w -X 'main.debugMode=1'" -o bin/myst-launcher-dbg-amd64.exe github.com/mysteriumnetwork/myst-launcher/cmd/app env: GOARCH: amd64 GOOS: windows @@ -46,7 +45,6 @@ jobs: prerelease: true files: | bin/myst-launcher-amd64.exe - bin/myst-launcher-dbg-amd64.exe env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/cmd/app/app.go b/cmd/app/app.go index 1040668..6f44a27 100644 --- a/cmd/app/app.go +++ b/cmd/app/app.go @@ -25,14 +25,24 @@ import ( "github.com/mysteriumnetwork/myst-launcher/utils" ) -var debugMode = "" - func main() { ap := app.NewApp() ipc := ipc_.NewHandler() - if len(os.Args) > 1 { - switch os.Args[1] { + cmd := "" + debugMode := false + for _, v := range os.Args { + switch v { + case _const.FlagInstall, + _const.FlagUninstall, + _const.FlagInstallFirewall: + cmd = v + case _const.FlagDebug: + debugMode = true + } + } + if cmd != "" { + switch cmd { case _const.FlagInstall: utils.InstallExe() return @@ -47,6 +57,9 @@ func main() { return } } + if debugMode { + utils.AllocConsole() + } mod := model.NewUIModel() mod.SetApp(ap) @@ -64,7 +77,7 @@ func main() { prodVersion, _ := utils.GetProductVersion() mod.SetProductVersion(prodVersion) - if debugMode != "" { + if debugMode { log.Println("Product version:", prodVersion) } @@ -90,7 +103,7 @@ func main() { gui_win32.ShutdownGDIPlus() ap.StopAppController() - if debugMode != "" { + if debugMode { fmt.Println("Press 'Enter' to continue...") bufio.NewReader(os.Stdin).ReadBytes('\n') } diff --git a/const/flags.go b/const/flags.go index 0acbd72..aa4f66d 100644 --- a/const/flags.go +++ b/const/flags.go @@ -11,4 +11,5 @@ const ( FlagInstall = "-install-binary" FlagUninstall = "-uninstall" FlagInstallFirewall = "-install-fw" + FlagDebug = "-debug" ) diff --git a/go.mod b/go.mod index e24b9c6..a063b40 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pkg/errors v0.9.1 - github.com/scjalliance/comshim v0.0.0-20190308082608-cf06d2532c4e // indirect + github.com/scjalliance/comshim v0.0.0-20190308082608-cf06d2532c4e github.com/stretchr/testify v1.7.0 github.com/tc-hib/winres v0.1.5 github.com/tryor/gdiplus v0.0.0-20200830101413-c570de9579b3 diff --git a/utils/utils_win32.go b/utils/utils_win32.go index 0a89cf8..8c5e20b 100644 --- a/utils/utils_win32.go +++ b/utils/utils_win32.go @@ -535,3 +535,39 @@ func OpenUrlInBrowser(url string) { "", syscall.SW_NORMAL) } + +// win32 console utils. Borrowed from https://github.com/yuk7/wsldl/blob/main/src/lib/utils/utils.go + +// AllocConsole calls AllocConsole API in Windows kernel32 +func AllocConsole() { + kernel32, _ := syscall.LoadDLL("Kernel32.dll") + alloc, _ := kernel32.FindProc("AllocConsole") + alloc.Call() + + hout, _ := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE) + herr, _ := syscall.GetStdHandle(syscall.STD_ERROR_HANDLE) + hin, _ := syscall.GetStdHandle(syscall.STD_INPUT_HANDLE) + os.Stdout = os.NewFile(uintptr(hout), "/dev/stdout") + os.Stderr = os.NewFile(uintptr(herr), "/dev/stderr") + os.Stdin = os.NewFile(uintptr(hin), "/dev/stdin") +} + +// SetConsoleTitle calls SetConsoleTitleW API in Windows kernel32 +func SetConsoleTitle(title string) { + kernel32, _ := syscall.LoadDLL("Kernel32.dll") + proc, _ := kernel32.FindProc("SetConsoleTitleW") + pTitle, _ := syscall.UTF16PtrFromString(title) + syscall.Syscall(proc.Addr(), 1, uintptr(unsafe.Pointer(pTitle)), 0, 0) + return +} + +// FreeConsole calls FreeConsole API in Windows kernel32 +func FreeConsole() error { + kernel32, _ := syscall.LoadDLL("Kernel32.dll") + proc, err := kernel32.FindProc("FreeConsole") + if err != nil { + return err + } + proc.Call() + return nil +} From ecbc7556863b38a259f4061ac9f0f4a7dd931e3d Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Wed, 2 Nov 2022 20:20:17 +0400 Subject: [PATCH 7/9] Stop node on launcher exit --- app/state.go | 4 +--- controller/docker/docker.go | 24 +++++++++++++++--------- controller/native/node.go | 25 ++++++++++++++++--------- controller/native/runner.go | 15 +++++---------- model/app.go | 2 +- utils/utils.go | 6 +++--- utils/utils_win32.go | 4 ++++ 7 files changed, 45 insertions(+), 35 deletions(-) diff --git a/app/state.go b/app/state.go index 28f3e55..8f0efa1 100644 --- a/app/state.go +++ b/app/state.go @@ -32,9 +32,7 @@ func NewApp() *AppState { } func (s *AppState) StopAppController() { - if !s.ctrApp.GetFinished() { - s.TriggerAction(model.ActionStop) - } + s.ctrApp.Shutdown() } func (s *AppState) StartAppController() { diff --git a/controller/docker/docker.go b/controller/docker/docker.go index 01fc0bb..66695f7 100644 --- a/controller/docker/docker.go +++ b/controller/docker/docker.go @@ -9,6 +9,7 @@ package docker import ( "log" + "sync" "time" model_ "github.com/mysteriumnetwork/myst-launcher/model" @@ -20,7 +21,9 @@ import ( type Controller struct { a model_.AppState - finished bool + finished bool + wg sync.WaitGroup + mgr model_.PlatformManager mystManager *myst.Manager lg *log.Logger @@ -39,12 +42,16 @@ func (c *Controller) SetApp(a model_.AppState) { c.a = a } -func (c *Controller) GetFinished() bool { - return c.finished +func (c *Controller) setFinished() { + c.finished = true + c.wg.Done() } -func (c *Controller) SetFinished() { - c.finished = true +func (c *Controller) Shutdown() { + if !c.finished { + c.a.GetAction() <- model_.ActionStop + c.wg.Wait() + } } func (c *Controller) Start() { @@ -70,12 +77,13 @@ func (c *Controller) Start() { c.mystManager = mystManager docker := NewDockerRunner(mystManager.GetDockerClient()) - defer c.SetFinished() + c.wg.Add(1) + defer c.setFinished() t1 := time.NewTicker(15 * time.Second) for { if wantExit := c.tryStartOrInstallDocker(docker); wantExit { - c.SetFinished() + c.setFinished() ui.CloseUI() return } @@ -242,14 +250,12 @@ func (c *Controller) startContainer() { if !mdl.Config.Enabled { return } - containerAlreadyRunning, err := c.mystManager.Start() if err != nil { mdl.SetStateContainer(model_.RunnableStateUnknown) c.lg.Println("startContainer", err) return } - mdl.SetStateContainer(model_.RunnableStateRunning) if !containerAlreadyRunning && mdl.Config.InitialState == model_.InitialStateFirstRunAfterInstall { diff --git a/controller/native/node.go b/controller/native/node.go index a59307e..1352a17 100644 --- a/controller/native/node.go +++ b/controller/native/node.go @@ -8,7 +8,9 @@ package native import ( + "fmt" "log" + "sync" "time" model_ "github.com/mysteriumnetwork/myst-launcher/model" @@ -19,16 +21,15 @@ type Controller struct { a model_.AppState finished bool - runner *NodeRunner - lg *log.Logger -} + wg sync.WaitGroup -func (c *Controller) GetFinished() bool { - return c.finished + runner *NodeRunner + lg *log.Logger } -func (c *Controller) SetFinished() { +func (c *Controller) setFinished() { c.finished = true + c.wg.Done() } func NewController() *Controller { @@ -45,7 +46,12 @@ func (c *Controller) SetApp(a model_.AppState) { c.runner = NewRunner(a.GetModel()) } -func (c *Controller) Shutdown() {} +func (c *Controller) Shutdown() { + if !c.finished { + c.a.GetAction() <- model_.ActionStop + c.wg.Wait() + } +} // Supervise the node func (c *Controller) Start() { @@ -61,7 +67,8 @@ func (c *Controller) Start() { model.ImageInfo.VersionLatest = cfg.NodeLatestTag model.Update() - defer c.SetFinished() + c.wg.Add(1) + defer c.setFinished() t1 := time.NewTicker(15 * time.Second) for { @@ -153,7 +160,7 @@ func (c *Controller) startContainer() { ui := c.a.GetUI() tryInstallFirewallRules(ui) - + running := c.runner.IsRunningOrTryStart() if running { model.SetStateContainer(model_.RunnableStateRunning) diff --git a/controller/native/runner.go b/controller/native/runner.go index 347f6bd..a86a44f 100644 --- a/controller/native/runner.go +++ b/controller/native/runner.go @@ -80,8 +80,7 @@ func (r *NodeRunner) isRunning() uint32 { // return values: isRunning func (r *NodeRunner) IsRunningOrTryStart() bool { - p := r.isRunning() - if p == 0 { + if r.isRunning() == 0 { return r.startNode() == nil } @@ -113,17 +112,13 @@ func (r *NodeRunner) startNode() error { args := []string{userspaceArg, versionArg, configDirArg, dataDirArg, "service", "--agreed-terms-and-conditions"} switch runtime.GOOS { - case "windows": - if err := utils.CmdStart(fullExePath, args...); err != nil { - log.Println("run node failed:", err) - return err - } - - case "darwin": - if err := utils.CmdStart(fullExePath, args...); err != nil { + case "windows", "darwin": + cmd, err := utils.CmdStart(fullExePath, args...) + if err != nil { log.Println("run node failed:", err) return err } + r.cmd = cmd default: return errors.New("unsupported OS: " + runtime.GOOS) diff --git a/model/app.go b/model/app.go index 02b8a4e..7ef6bb3 100644 --- a/model/app.go +++ b/model/app.go @@ -15,8 +15,8 @@ type App interface { type Controller interface { SetApp(a AppState) Start() + Shutdown() GetCaps() int - GetFinished() bool } const ( diff --git a/utils/utils.go b/utils/utils.go index c6949f5..60d11d2 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -22,15 +22,15 @@ import ( var sysProcAttrs = getSysProcAttrs() -func CmdStart(name string, args ...string) error { +func CmdStart(name string, args ...string) (*exec.Cmd, error) { log.Print(fmt.Sprintf("Run: %v %v \r\n", name, strings.Join(args, " "))) cmd := exec.Command(name, args...) cmd.SysProcAttr = &sysProcAttrs if err := cmd.Start(); err != nil { - return err + return nil, err } - return nil + return cmd, nil } // returns: exit status, error diff --git a/utils/utils_win32.go b/utils/utils_win32.go index 8c5e20b..9b0750a 100644 --- a/utils/utils_win32.go +++ b/utils/utils_win32.go @@ -543,6 +543,10 @@ func AllocConsole() { kernel32, _ := syscall.LoadDLL("Kernel32.dll") alloc, _ := kernel32.FindProc("AllocConsole") alloc.Call() + +// attach, _ := kernel32.FindProc("AttachConsole") +// const ATTACH_PARENT_PROCESS = ^uintptr(0) +// attach.Call(ATTACH_PARENT_PROCESS) hout, _ := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE) herr, _ := syscall.GetStdHandle(syscall.STD_ERROR_HANDLE) From 9d9d805e0619701b1486afa86eec31589e2fb7db Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Thu, 3 Nov 2022 03:33:28 +0400 Subject: [PATCH 8/9] Show notification on finish of native node install --- controller/native/node.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/controller/native/node.go b/controller/native/node.go index 1352a17..0dbadc6 100644 --- a/controller/native/node.go +++ b/controller/native/node.go @@ -8,7 +8,6 @@ package native import ( - "fmt" "log" "sync" "time" @@ -80,7 +79,6 @@ func (c *Controller) Start() { // c.upgradeContainer(false) // } - // c.lg.Println("wait action >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") select { case act := <-action: c.lg.Println("action:", act) @@ -164,6 +162,14 @@ func (c *Controller) startContainer() { running := c.runner.IsRunningOrTryStart() if running { model.SetStateContainer(model_.RunnableStateRunning) + + cfg := &model.Config + switch cfg.InitialState { + case model_.InitialStateFirstRunAfterInstall, model_.InitialStateUndefined: + cfg.InitialState = model_.InitialStateNormalRun + cfg.Save() + ui.ShowNotificationInstalled() + } } } } From e004412eff01a059383b50e7bdab10375289a162 Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Thu, 3 Nov 2022 16:27:59 +0400 Subject: [PATCH 9/9] Remove mainnet migration UI elements --- cmd/app/app.go | 2 +- gui-win32/state_frame.go | 49 ---------------------------------------- utils/utils_unix.go | 13 ++++------- utils/utils_win32.go | 27 ++++++++++++---------- 4 files changed, 20 insertions(+), 71 deletions(-) diff --git a/cmd/app/app.go b/cmd/app/app.go index 6f44a27..1f90b28 100644 --- a/cmd/app/app.go +++ b/cmd/app/app.go @@ -58,7 +58,7 @@ func main() { } } if debugMode { - utils.AllocConsole() + utils.AllocConsole(false) } mod := model.NewUIModel() diff --git a/gui-win32/state_frame.go b/gui-win32/state_frame.go index 7b1fbd0..5e2ef65 100644 --- a/gui-win32/state_frame.go +++ b/gui-win32/state_frame.go @@ -37,9 +37,6 @@ type StateFrame struct { lbNetworkMode *walk.Label btnOpenNodeConfig *walk.PushButton - lbNetwork *walk.Label - btnMainNet *walk.PushButton - cmp *walk.Composite headerContainer *walk.Composite lbNodeUI *walk.LinkLabel @@ -139,50 +136,6 @@ func NewStateFrame(parent walk.Container, mdl *model.UIModel) *StateFrame { Text: "", }, - Label{ - Text: "Network", - }, - Composite{ - Alignment: AlignHNearVCenter, - Layout: HBox{ - MarginsZero: true, - Spacing: 0, - }, - - Children: []Widget{ - Label{ - Text: "-", - AssignTo: &f.lbNetwork, - Alignment: AlignHNearVCenter, - }, - PushButton{ - Alignment: AlignHNearVCenter, - Enabled: true, - AssignTo: &f.btnMainNet, - Text: "Update to MainNet..", - - OnSizeChanged: func() { - f.btnMainNet.SetWidthPixels(115) - }, - OnClicked: func() { - mdl.UIBus.Publish("btn-upgrade-network") - }, - }, - //HSpacer{StretchFactor: 0}, - }, - }, - Label{ - Text: "", - }, - LinkLabel{ - Text: "Information about MainNet", - OnLinkActivated: func(link *walk.LinkLabelLink) { - utils.OpenUrlInBrowser("https://mysterium.network/") - }, - Alignment: AlignHNearVNear, - }, - VSpacer{ColumnSpan: 2, Size: 10}, - Label{ Text: "Node package source", }, @@ -383,8 +336,6 @@ func (f *StateFrame) handlerState() { f.lbImageName.SetText(f.mdl.Config.GetFullImageName()) - f.lbNetwork.SetText(f.mdl.Config.GetNetworkCaption()) - f.btnMainNet.SetVisible(!f.mdl.CurrentNetIsMainNet()) f.lbUpdateLauncher.SetVisible(f.mdl.LauncherHasUpdate) } }) diff --git a/utils/utils_unix.go b/utils/utils_unix.go index 870635b..0e192d4 100644 --- a/utils/utils_unix.go +++ b/utils/utils_unix.go @@ -19,15 +19,6 @@ func getSysProcAttrs() syscall.SysProcAttr { return syscall.SysProcAttr{} } -// func IsProcessRunning(name string) bool { -// res, err := CmdRun(nil, "pgrep", "-xq", "--", `^`+name) -// if err == nil { -// return res == 0 -// } -// log.Println("IsProcessRunning error:", err) -// return false -// } - func LauncherUpgradeAvailable() bool { return false } @@ -63,3 +54,7 @@ func CheckAndInstallExe() error { func RunasWithArgsAndWait(cmdArgs string) error { panic("not implemented") } + +func EnableAutorun(en bool) error { + return nil +} \ No newline at end of file diff --git a/utils/utils_win32.go b/utils/utils_win32.go index 9b0750a..a5dbcb7 100644 --- a/utils/utils_win32.go +++ b/utils/utils_win32.go @@ -22,14 +22,14 @@ import ( "time" "unsafe" - "github.com/scjalliance/comshim" - "github.com/blang/semver/v4" + "github.com/blang/semver/v4" "github.com/go-ole/go-ole" "github.com/go-ole/go-ole/oleutil" "github.com/gonutz/w32" "github.com/lxn/walk" "github.com/mysteriumnetwork/go-fileversion" "github.com/pkg/errors" + "github.com/scjalliance/comshim" "github.com/winlabs/gowin32" "golang.org/x/sys/windows" "golang.org/x/sys/windows/registry" @@ -53,7 +53,7 @@ func getSysProcAttrs() syscall.SysProcAttr { func CreateShortcut(dst, target, args string) error { comshim.Add(1) defer comshim.Done() - + oleShellObject, err := oleutil.CreateObject("WScript.Shell") if err != nil { return err @@ -171,9 +171,9 @@ func EnableAutorun(en bool) error { defer k.Close() if en { - return k.SetBinaryValue(launcherLnk, []byte{2,0,0}) + return k.SetBinaryValue(launcherLnk, []byte{2, 0, 0}) } - return k.SetBinaryValue(launcherLnk, []byte{3,0,0}) + return k.SetBinaryValue(launcherLnk, []byte{3, 0, 0}) } // should be executed with admin's privileges @@ -539,14 +539,17 @@ func OpenUrlInBrowser(url string) { // win32 console utils. Borrowed from https://github.com/yuk7/wsldl/blob/main/src/lib/utils/utils.go // AllocConsole calls AllocConsole API in Windows kernel32 -func AllocConsole() { +func AllocConsole(attach bool) { kernel32, _ := syscall.LoadDLL("Kernel32.dll") - alloc, _ := kernel32.FindProc("AllocConsole") - alloc.Call() - -// attach, _ := kernel32.FindProc("AttachConsole") -// const ATTACH_PARENT_PROCESS = ^uintptr(0) -// attach.Call(ATTACH_PARENT_PROCESS) + + if attach { + attach, _ := kernel32.FindProc("AttachConsole") + const ATTACH_PARENT_PROCESS = ^uintptr(0) + attach.Call(ATTACH_PARENT_PROCESS) + } else { + alloc, _ := kernel32.FindProc("AllocConsole") + alloc.Call() + } hout, _ := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE) herr, _ := syscall.GetStdHandle(syscall.STD_ERROR_HANDLE)