diff --git a/Taskfile.yml b/Taskfile.yml index e3dc52fd..8b767b8d 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -32,12 +32,12 @@ tasks: build:server: cmds: - - go build -o dist/bin/wavesrv cmd/server/main-server.go + - go build -o dist/bin/wavesrv{{exeExt}} cmd/server/main-server.go sources: - "cmd/server/*.go" - "pkg/**/*.go" generates: - - dist/bin/wavesrv + - dist/bin/wavesrv{{exeExt}} deps: - go:mod:tidy diff --git a/cmd/server/main-server.go b/cmd/server/main-server.go index 5b994469..34d777b3 100644 --- a/cmd/server/main-server.go +++ b/cmd/server/main-server.go @@ -9,6 +9,7 @@ import ( "log" "os" "os/signal" + "runtime" "strconv" "sync" @@ -80,6 +81,12 @@ func main() { log.Printf("error acquiring wave lock (another instance of Wave is likely running): %v\n", err) return } + defer func() { + err = waveLock.Unlock() + if err != nil { + log.Printf("error releasing wave lock: %v\n", err) + } + }() log.Printf("wave home dir: %s\n", wavebase.GetWaveHomeDir()) err = filestore.InitFilestore() @@ -105,9 +112,9 @@ func main() { time.Sleep(30 * time.Millisecond) pidStr := os.Getenv(ReadySignalPidVarName) if pidStr != "" { - pid, err := strconv.Atoi(pidStr) + _, err := strconv.Atoi(pidStr) if err == nil { - syscall.Kill(pid, syscall.SIGUSR1) + log.Printf("WAVESRV-ESTART\n") } } }() diff --git a/emain/emain.ts b/emain/emain.ts index 2152c81b..b2f83426 100644 --- a/emain/emain.ts +++ b/emain/emain.ts @@ -7,6 +7,8 @@ import * as path from "path"; import * as readline from "readline"; import { debounce } from "throttle-debounce"; import * as services from "../frontend/app/store/services"; +import os from "os"; +import fs from "fs"; const electronApp = electron.app; const isDev = process.env.WAVETERM_DEV; @@ -23,6 +25,7 @@ let waveSrvReadyResolve = (value: boolean) => {}; let waveSrvReady: Promise = new Promise((resolve, _) => { waveSrvReadyResolve = resolve; }); + let waveSrvProc: child_process.ChildProcessWithoutNullStreams | null = null; electronApp.setName(isDev ? "NextWave (Dev)" : "NextWave"); const unamePlatform = process.platform; @@ -40,7 +43,7 @@ function getBaseHostPort(): string { // must match golang function getWaveHomeDir() { - return path.join(process.env.HOME, ".w2"); + return path.join(os.homedir(), ".w2"); } function getElectronAppBasePath(): string { @@ -60,6 +63,11 @@ function getWaveSrvPath(): string { return path.join(getGoAppBasePath(), "bin", "wavesrv"); } +function getWaveSrvPathWin(): string { + const appPath = path.join(getGoAppBasePath(), "bin", "wavesrv.exe"); + return `& "${appPath}"` +} + function getWaveSrvCwd(): string { return getWaveHomeDir(); } @@ -77,7 +85,12 @@ function runWaveSrv(): Promise { envCopy[WaveDevVarName] = "1"; } envCopy[WaveSrvReadySignalPidVarName] = process.pid.toString(); - const waveSrvCmd = getWaveSrvPath(); + let waveSrvCmd: string; + if (process.platform === "win32") { + waveSrvCmd = getWaveSrvPathWin(); + } else { + waveSrvCmd = getWaveSrvPath(); + } console.log("trying to run local server", waveSrvCmd); const proc = child_process.spawn(getWaveSrvPath(), { cwd: getWaveSrvCwd(), @@ -108,6 +121,10 @@ function runWaveSrv(): Promise { terminal: false, }); rlStderr.on("line", (line) => { + if (line.includes("WAVESRV-ESTART")) { + waveSrvReadyResolve(true); + return; + } console.log(line); }); return rtnPromise; @@ -232,11 +249,6 @@ electron.ipcMain.on("isDevServer", () => { return isDevServer; }); -process.on("SIGUSR1", function () { - ``; - waveSrvReadyResolve(true); -}); - (async () => { const startTs = Date.now(); const instanceLock = electronApp.requestSingleInstanceLock(); @@ -245,16 +257,21 @@ process.on("SIGUSR1", function () { electronApp.quit(); return; } + const waveHomeDir = getWaveHomeDir(); + if (!fs.existsSync(waveHomeDir)) { + fs.mkdirSync(waveHomeDir); + } try { await runWaveSrv(); } catch (e) { console.log(e.toString()); } - console.log("waiting for wavesrv ready signal (SIGUSR1)"); const ready = await waveSrvReady; console.log("wavesrv ready signal received", ready, Date.now() - startTs, "ms"); - let clientData = await services.ClientService.GetClientData(); + console.log("get client data"); + let clientData = await services.ClientService.GetClientData().catch(e => console.log(e)) as Client; + console.log("client data ready"); let windowData: WaveWindow = (await services.ObjectService.GetObject( "window:" + clientData.mainwindowid )) as WaveWindow; diff --git a/go.mod b/go.mod index 990843d4..0f985907 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.22 toolchain go1.22.1 require ( + github.com/alexflint/go-filemutex v1.3.0 github.com/creack/pty v1.1.18 github.com/golang-migrate/migrate/v4 v4.17.1 github.com/google/uuid v1.4.0 @@ -17,7 +18,6 @@ require ( github.com/sawka/txwrap v0.2.0 github.com/spf13/cobra v1.8.0 github.com/wavetermdev/waveterm/wavesrv v0.0.0-20240508181017-d07068c09d94 - golang.org/x/sys v0.20.0 golang.org/x/term v0.17.0 ) @@ -29,4 +29,5 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.8.4 // indirect go.uber.org/atomic v1.7.0 // indirect + golang.org/x/sys v0.20.0 // indirect ) diff --git a/go.sum b/go.sum index 7f1f1f43..f496a489 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/alexflint/go-filemutex v1.3.0 h1:LgE+nTUWnQCyRKbpoceKZsPQbs84LivvgwUymZXdOcM= +github.com/alexflint/go-filemutex v1.3.0/go.mod h1:U0+VA/i30mGBlLCrFPGtTe9y6wGQfNAWPBTekHQ+c8A= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -46,16 +48,19 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/wavetermdev/waveterm/wavesrv v0.0.0-20240508181017-d07068c09d94 h1:/SPCxd4KHlS4eRTreYEXWFRr8WfRFBcChlV5cgkaO58= github.com/wavetermdev/waveterm/wavesrv v0.0.0-20240508181017-d07068c09d94/go.mod h1:ywoo7DXdYueQ0tTPhVoB+wzRTgERSE19EA3mR6KGRaI= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/filestore/blockstore_dbsetup.go b/pkg/filestore/blockstore_dbsetup.go index 63bcf88d..3580ebd6 100644 --- a/pkg/filestore/blockstore_dbsetup.go +++ b/pkg/filestore/blockstore_dbsetup.go @@ -10,7 +10,7 @@ import ( "context" "fmt" "log" - "path" + "path/filepath" "time" "github.com/wavetermdev/thenextwave/pkg/util/migrateutil" @@ -51,7 +51,7 @@ func InitFilestore() error { func GetDBName() string { waveHome := wavebase.GetWaveHomeDir() - return path.Join(waveHome, FilestoreDBName) + return filepath.Join(waveHome, FilestoreDBName) } func MakeDB(ctx context.Context) (*sqlx.DB, error) { diff --git a/pkg/wavebase/wavebase.go b/pkg/wavebase/wavebase.go index 5e5bcac2..423ead07 100644 --- a/pkg/wavebase/wavebase.go +++ b/pkg/wavebase/wavebase.go @@ -11,21 +11,19 @@ import ( "log" "os" "os/exec" - "path" "path/filepath" "runtime" "strings" "sync" "time" - "golang.org/x/sys/unix" + "github.com/alexflint/go-filemutex" ) const WaveVersion = "v0.1.0" const DefaultWaveHome = "~/.w2" const WaveHomeVarName = "WAVETERM_HOME" const WaveDevVarName = "WAVETERM_DEV" -const HomeVarName = "HOME" const WaveLockFile = "waveterm.lock" var baseLock = &sync.Mutex{} @@ -37,8 +35,8 @@ func IsDevMode() bool { } func GetHomeDir() string { - homeVar := os.Getenv(HomeVarName) - if homeVar == "" { + homeVar, err := os.UserHomeDir() + if err != nil { return "/" } return homeVar @@ -52,7 +50,7 @@ func ExpandHomeDir(pathStr string) string { if pathStr == "~" { return homeDir } - return path.Join(homeDir, pathStr[2:]) + return filepath.Join(homeDir, pathStr[2:]) } func ReplaceHomeDir(pathStr string) string { @@ -142,18 +140,16 @@ func DetermineLang() string { return osLang } -func AcquireWaveLock() (*os.File, error) { +func AcquireWaveLock() (*filemutex.FileMutex, error) { homeDir := GetWaveHomeDir() lockFileName := filepath.Join(homeDir, WaveLockFile) log.Printf("[base] acquiring lock on %s\n", lockFileName) - fd, err := os.OpenFile(lockFileName, os.O_RDWR|os.O_CREATE, 0600) + m, err := filemutex.New(lockFileName) if err != nil { return nil, err } - err = unix.Flock(int(fd.Fd()), unix.LOCK_EX|unix.LOCK_NB) - if err != nil { - fd.Close() - return nil, err - } - return fd, nil + + err = m.TryLock() + return m, err + } diff --git a/pkg/wstore/wstore_dbsetup.go b/pkg/wstore/wstore_dbsetup.go index f79e2cea..fafdade3 100644 --- a/pkg/wstore/wstore_dbsetup.go +++ b/pkg/wstore/wstore_dbsetup.go @@ -7,7 +7,7 @@ import ( "context" "fmt" "log" - "path" + "path/filepath" "time" "github.com/jmoiron/sqlx" @@ -42,7 +42,7 @@ func InitWStore() error { func GetDBName() string { waveHome := wavebase.GetWaveHomeDir() - return path.Join(waveHome, WStoreDBName) + return filepath.Join(waveHome, WStoreDBName) } func MakeDB(ctx context.Context) (*sqlx.DB, error) {