diff --git a/.gitignore b/.gitignore index cf10bc33..7cbb52ac 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,3 @@ node_modules/ __pycache__ web/dev-dist/ venv/ -cmd/key-file.yaml diff --git a/.goreleaser.yml b/.goreleaser.yml index fa423a86..b193a18a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -52,10 +52,11 @@ builds: id: ntfy_windows_amd64 binary: ntfy env: - - CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3 - tags: [noserver] # don't include server files + - CGO_ENABLED=1 # required for go-sqlite3 + - CC=x86_64-w64-mingw32-gcc # apt install gcc-mingw-w64-x86-64 + tags: [sqlite_omit_load_extension,osusergo,netgo] ldflags: - - "-X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}" + - "-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}" goos: [windows] goarch: [amd64] - diff --git a/Makefile b/Makefile index 4355423e..5d3293fe 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ help: @echo "Build server & client (without GoReleaser):" @echo " make cli-linux-server - Build client & server (no GoReleaser, current arch, Linux)" @echo " make cli-darwin-server - Build client & server (no GoReleaser, current arch, macOS)" + @echo " make cli-windows-server - Build client & server (no GoReleaser, amd64 only, Windows)" @echo " make cli-client - Build client only (no GoReleaser, current arch, Linux/macOS/Windows)" @echo @echo "Build dev Docker:" @@ -201,6 +202,16 @@ cli-darwin-server: cli-deps-static-sites -ldflags \ "-linkmode=external -s -w -X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.date=$(shell date +%s)" +cli-windows-server: cli-deps-static-sites + # This is a target to build the CLI (including the server) for Windows. + # Use this for Windows development, if you really don't want to install GoReleaser ... + mkdir -p dist/ntfy_windows_server server/docs + CC=x86_64-w64-mingw32-gcc GOOS=windows GOARCH=amd64 CGO_ENABLED=1 go build \ + -o dist/ntfy_windows_server/ntfy.exe \ + -tags sqlite_omit_load_extension,osusergo,netgo \ + -ldflags \ + "-s -w -X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.date=$(shell date +%s)" + cli-client: cli-deps-static-sites # This is a target to build the CLI (excluding the server) manually. This should work on Linux/macOS/Windows. # Use this for development, if you really don't want to install GoReleaser ... @@ -213,7 +224,7 @@ cli-client: cli-deps-static-sites cli-deps: cli-deps-static-sites cli-deps-all cli-deps-gcc -cli-deps-gcc: cli-deps-gcc-armv6-armv7 cli-deps-gcc-arm64 +cli-deps-gcc: cli-deps-gcc-armv6-armv7 cli-deps-gcc-arm64 cli-deps-gcc-windows cli-deps-static-sites: mkdir -p server/docs server/site @@ -228,6 +239,9 @@ cli-deps-gcc-armv6-armv7: cli-deps-gcc-arm64: which aarch64-linux-gnu-gcc || { echo "ERROR: ARM64 cross compiler not installed. On Ubuntu, run: apt install gcc-aarch64-linux-gnu"; exit 1; } +cli-deps-gcc-windows: + which x86_64-w64-mingw32-gcc || { echo "ERROR: Windows cross compiler not installed. On Ubuntu, run: apt install gcc-mingw-w64-x86-64"; exit 1; } + cli-deps-update: go get -u go install honnef.co/go/tools/cmd/staticcheck@latest diff --git a/cmd/serve_windows.go b/cmd/serve_windows.go new file mode 100644 index 00000000..201e5c25 --- /dev/null +++ b/cmd/serve_windows.go @@ -0,0 +1,70 @@ +// Copyright 2015 Daniel Theophanes. +// Use of this source code is governed by a zlib-style +// license that can be found at: https://github.com/kardianos/minwinsvc + +//go:build windows && !noserver + +package cmd + +import ( + "os" + "sync" + + "golang.org/x/sys/windows/svc" +) + +var ( + onExit func() + guard sync.Mutex +) + +func init() { + isService, err := svc.IsWindowsService() + if err != nil { + panic(err) + } + if !isService { + return + } + go func() { + _ = svc.Run("", runner{}) + + guard.Lock() + f := onExit + guard.Unlock() + + // Don't hold this lock in user code. + if f != nil { + f() + } + // Make sure we exit. + os.Exit(0) + }() +} + +func setOnExit(f func()) { + guard.Lock() + onExit = f + guard.Unlock() +} + +type runner struct{} + +func (runner) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) { + const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown + changes <- svc.Status{State: svc.StartPending} + + changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} + for { + c := <-r + switch c.Cmd { + case svc.Interrogate: + changes <- c.CurrentStatus + case svc.Stop, svc.Shutdown: + changes <- svc.Status{State: svc.StopPending} + return false, 0 + } + } + + return false, 0 +}