diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eeeefd1..6a51baf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,31 +5,6 @@ on: - "*" jobs: - release-server: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Docker Compose - uses: docker/setup-buildx-action@v3 - - - name: Build And Tag Image - run: | - docker compose up --build --force-recreate --remove-orphans -d server - docker tag passeriformub/nukeship:latest passeriformub/nukeship:${{ github.ref_name }} - - - name: Publish Docker Image - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Push Docker Image to Docker Hub - run: | - docker push passeriformub/nukeship:${{ github.ref_name }} - docker push passeriformub/nukeship:latest - release-binaries: strategy: fail-fast: false @@ -61,7 +36,8 @@ jobs: - name: Generate code run: go generate ./... - - name: Create binary + - name: Release binary + id: release uses: passeriform/wails-build-action@main with: app-working-directory: pkg/client @@ -69,3 +45,36 @@ jobs: build-name: ${{ matrix.name }} build-platform: ${{ matrix.platform }} macos-artifact-name: "NukeShip" + + outputs: + release-id: ${{ steps.release.outputs.release-id }} + + release-notes: + runs-on: ubuntu-latest + needs: release-binaries + permissions: + contents: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Prepare release notes + id: prepare + working-directory: ${{ github.workspace }}/scripts + run: | + chmod +x * + echo "RELEASE_NOTES<> $GITHUB_OUTPUT + echo "$(./changelog_gen.sh ${{ github.ref_name }})" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Test Release Notes + run: echo ${{ steps.prepare.outputs.RELEASE_NOTES }} + + - name: Update release notes + uses: irongut/editrelease@v1.2.0 + with: + id: ${{ needs.release-binaries.outputs.release-id }} + token: ${{ github.token }} + replacebody: true + name: ${{ github.ref_name }} + body: ${{ steps.prepare.outputs.RELEASE_NOTES }} diff --git a/.golangci.yml b/.golangci.yml index 5b59b1e..bb4e45b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -61,10 +61,15 @@ linters-settings: - google\.golang\.org/grpc/keepalive\.ClientParameters - google\.golang\.org/grpc/keepalive\.EnforcementPolicy - google\.golang\.org/grpc/keepalive\.ServerParameters - - github\.com/wailsapp/wails/v2/pkg/options\.App - - github\.com/wailsapp/wails/v2/pkg/options/mac\.Options - - github\.com/wailsapp/wails/v2/pkg/options/linux\.Options - - github\.com/wailsapp/wails/v2/pkg/options/linux\.Options + - github\.com/wailsapp/wails/v3/pkg/application\.Options + - github\.com/wailsapp/wails/v3/pkg/application\.LinuxOptions + - github\.com/wailsapp/wails/v3/pkg/application\.MacOptions + - github\.com/wailsapp/wails/v3/pkg/application\.WindowsOptions + - github\.com/wailsapp/wails/v3/pkg/application\.AssetOptions + - github\.com/wailsapp/wails/v3/pkg/application\.WebviewWindowOptions + - github\.com/wailsapp/wails/v3/pkg/application\.LinuxWindow + - github\.com/wailsapp/wails/v3/pkg/application\.MacWindow + - github\.com/wailsapp/wails/v3/pkg/application\.WindowsWindow - github\.com/necmettindev/randomstring\.GenerationOptions gci: custom-order: true diff --git a/.vscode/settings.json b/.vscode/settings.json index 889be8d..42f7574 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,10 @@ "cSpell.words": [ "3dtransforms", "abice", + "appicon", + "appimage", + "APPL", + "archlinux", "asasalint", "asmv3", "assetdir", @@ -10,14 +14,19 @@ "AWAITINGREADY", "Bhardwaj", "bidichk", + "binaryname", + "buildvcs", "buildx", "bytebufferpool", "caarlos", + "Colour", "containedctx", "copyloopvar", "dbus", "decorder", "depguard", + "desktopfile", + "dotdesktop", "dylib", "errcheck", "errchkjson", @@ -29,6 +38,7 @@ "fieldalignment", "Frameless", "Fugaz", + "gcflags", "genproto", "GOARCH", "gochecknoglobals", @@ -47,6 +57,7 @@ "gosod", "govet", "Gurpartap", + "icns", "iface", "importas", "INGAME", @@ -59,19 +70,24 @@ "labstack", "ldflags", "leaanthony", - "lerp", + "libwebkit", + "macfilename", "mattn", "mcli", "mustparse", "necmettindev", "nestif", + "nfpm", "nilnil", "njsproj", "nlreturn", "nolint", + "nsis", "ntvs", "nukeship", "Orbitron", + "outputdir", + "outputfile", "outputfilename", "passeriform", "passeriformub", @@ -79,6 +95,12 @@ "permonitor", "permonitorv2", "predeclared", + "productcomments", + "productcompany", + "productcopyright", + "productdescription", + "productidentifier", + "productname", "protoc", "pyncz", "randomstring", @@ -96,12 +118,15 @@ "stdlib", "stylecheck", "tagalign", + "Taskfile", "tenv", "testifylint", "textshadow", "thisbeyond", "tkrajina", + "trimpath", "trivago", + "tubone", "tweenjs", "unconvert", "underef", @@ -111,8 +136,12 @@ "Utkarsh", "valyala", "varnamelen", + "VITE", "wailsapp", + "wailsio", "wailsjs", + "wailsroomservice", + "windowsfilename", "winloader", "wrapcheck" ], diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 3950ad0..dcc52ae 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -33,6 +33,20 @@ "cwd": "${workspaceFolder}" } }, + { + "label": "[Generation] Generate Wails Bindings", + "type": "shell", + "command": "wails3", + "args": [ + "generate", + "bindings", + "-ts", + ], + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + } + }, { "label": "[Sanity] Ping Hosted gRPC server", "type": "shell", diff --git a/README.md b/README.md index 24cbe1a..67bc646 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Ensure you have the following installed on your system: 2. Install Wails: ```bash - go install github.com/wailsapp/wails/v2/cmd/wails@latest + go install github.com/wailsapp/wails/v3/cmd/wails@latest ``` 3. Generate protobuf bindings: @@ -63,7 +63,7 @@ Ensure you have the following installed on your system: 4. Build the project: ```bash - wails build -clean + wails3 build ``` 5. Run the game: diff --git a/go.mod b/go.mod index a81aa7a..148ab3c 100644 --- a/go.mod +++ b/go.mod @@ -9,58 +9,73 @@ require ( github.com/abice/go-enum v0.6.0 github.com/caarlos0/env/v11 v11.3.1 github.com/jxskiss/mcli v0.9.5 + github.com/leaanthony/u v1.1.0 github.com/necmettindev/randomstring v0.1.0 - github.com/wailsapp/wails/v2 v2.9.2 - google.golang.org/grpc v1.67.1 - google.golang.org/protobuf v1.34.2 + github.com/wailsapp/wails/v3 v3.0.0-alpha.9 + google.golang.org/grpc v1.69.4 + google.golang.org/protobuf v1.36.3 ) require ( + dario.cat/mergo v1.0.1 // indirect github.com/MakeNowJust/heredoc/v2 v2.0.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.0 // indirect + github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v1.0.0 // indirect + github.com/adrg/xdg v0.5.0 // indirect github.com/bep/debounce v1.2.1 // indirect + github.com/cloudflare/circl v1.3.8 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect + github.com/cyphar/filepath-securejoin v0.2.5 // indirect + github.com/ebitengine/purego v0.4.0-alpha.4 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.6.0 // indirect + github.com/go-git/go-git/v5 v5.12.0 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/huandu/xstrings v1.3.3 // indirect - github.com/imdario/mergo v0.3.13 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect - github.com/labstack/echo/v4 v4.10.2 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/labstack/gommon v0.4.1 // indirect - github.com/leaanthony/go-ansi-parser v1.6.0 // indirect - github.com/leaanthony/gosod v1.0.3 // indirect - github.com/leaanthony/slicer v1.6.0 // indirect - github.com/leaanthony/u v1.1.0 // indirect + github.com/leaanthony/go-ansi-parser v1.6.1 // indirect + github.com/lmittmann/tint v1.0.4 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/goveralls v0.0.12 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/rivo/uniseg v0.4.4 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/samber/lo v1.38.1 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shopspring/decimal v1.2.0 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/tkrajina/go-reflector v0.5.6 // indirect + github.com/skeema/knownhosts v1.2.2 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/urfave/cli/v2 v2.26.0 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/wailsapp/go-webview2 v1.0.16 // indirect + github.com/wailsapp/go-webview2 v1.0.19 // indirect github.com/wailsapp/mimetype v1.4.1 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.19.0 // indirect + golang.org/x/tools v0.23.0 // indirect golang.org/x/tools/cmd/cover v0.1.0-deprecated // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index e24db1f..972a3a3 100644 --- a/go.sum +++ b/go.sum @@ -1,32 +1,78 @@ +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Gurpartap/statemachine-go v0.0.0-20190708030151-b27cddb816c4 h1:vXHfHPQWZJdbr5CeTdsL9SwQKH+tM9brrSdmGYQbMEc= github.com/Gurpartap/statemachine-go v0.0.0-20190708030151-b27cddb816c4/go.mod h1:EoZCl/DeoRmBl0pH6YGBXefkF71UX2jjdvFFnZvLgD4= github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZYIR/J6A= github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= +github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/abice/go-enum v0.6.0 h1:J6xiV+nyu/D5c5+/rQfgkMi9zJ1Hkap8clxCZf8KNsk= github.com/abice/go-enum v0.6.0/go.mod h1:istq/zbgIh0kwEdbwHb+t8OS5dsB7w4w4VygV6HcpLg= +github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY= +github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA= github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI= +github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= +github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/ebitengine/purego v0.4.0-alpha.4 h1:Y7yIV06Yo5M2BAdD7EVPhfp6LZ0tEcQo5770OhYUVes= +github.com/ebitengine/purego v0.4.0-alpha.4/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8= +github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -35,27 +81,31 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= github.com/jxskiss/mcli v0.9.5 h1:ucru5l3y2d0yWHTK/49tQHWcTWfIYqTQvputK2lmZtc= github.com/jxskiss/mcli v0.9.5/go.mod h1:F2DPy6IyQ9TUjPl0cnqIxVWH13wUeyxZGCWqQeKDCbA= -github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= -github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labstack/gommon v0.4.1 h1:gqEff0p/hTENGMABzezPoPSRtIh1Cvw0ueMOe0/dfOk= github.com/labstack/gommon v0.4.1/go.mod h1:TyTrpPqxR5KMk8LKVtLmfMjeQ5FEkBYdxLYPw/WfrOM= -github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= -github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= -github.com/leaanthony/go-ansi-parser v1.6.0 h1:T8TuMhFB6TUMIUm0oRrSbgJudTFw9csT3ZK09w0t4Pg= -github.com/leaanthony/go-ansi-parser v1.6.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= -github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ= -github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= -github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= -github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js= -github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= +github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A= +github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI= github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= +github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc= +github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -73,6 +123,10 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/necmettindev/randomstring v0.1.0 h1:HeU/mfLCd/5E9At7xznbTeEw5YldGW92fvK8lWtvPwE= github.com/necmettindev/randomstring v0.1.0/go.mod h1:h2nX9Jl0TLImuMt++XfLStVr8N76BmmP5D5EhLq0KEQ= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -80,125 +134,160 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -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/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE= -github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI= github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= -github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/wailsapp/go-webview2 v1.0.16 h1:wffnvnkkLvhRex/aOrA3R7FP7rkvOqL/bir1br7BekU= -github.com/wailsapp/go-webview2 v1.0.16/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= +github.com/wailsapp/go-webview2 v1.0.19 h1:7U3QcDj1PrBPaxJNCui2k1SkWml+Q5kvFUFyTImA6NU= +github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= -github.com/wailsapp/wails/v2 v2.9.2 h1:Xb5YRTos1w5N7DTMyYegWaGukCP2fIaX9WF21kPPF2k= -github.com/wailsapp/wails/v2 v2.9.2/go.mod h1:uehvlCwJSFcBq7rMCGfk4rxca67QQGsbg5Nm4m9UnBs= +github.com/wailsapp/wails/v3 v3.0.0-alpha.9 h1:b8CfRrhPno8Fra0xFp4Ifyj+ogmXBc35rsQWvcrHtsI= +github.com/wailsapp/wails/v3 v3.0.0-alpha.9/go.mod h1:dSv6s722nSWaUyUiapAM1DHc5HKggNGY1a79shO85/g= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/tools/cmd/cover v0.1.0-deprecated h1:Rwy+mWYz6loAF+LnG1jHG/JWMHRMMC2/1XX3Ejkx9lA= golang.org/x/tools/cmd/cover v0.1.0-deprecated/go.mod h1:hMDiIvlpN1NoVgmjLjUJE9tMHyxHjFX7RuQ+rW12mSA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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/client/.gitignore b/pkg/client/.gitignore index 22ee1a5..87d446b 100644 --- a/pkg/client/.gitignore +++ b/pkg/client/.gitignore @@ -1,2 +1,11 @@ -# Wails build -build/bin +# Wails build assets +.task +bin + +# Build artifacts +build/linux/appimage/build +build/windows/nsis/MicrosoftEdgeWebview2Setup.exe + +# Frontend bindings +frontend/bindings +wailsjs diff --git a/pkg/client/Taskfile.yml b/pkg/client/Taskfile.yml new file mode 100644 index 0000000..ca6e9fb --- /dev/null +++ b/pkg/client/Taskfile.yml @@ -0,0 +1,33 @@ +version: "3" + +includes: + common: ./build/Taskfile.yml + windows: ./build/windows/Taskfile.yml + darwin: ./build/darwin/Taskfile.yml + linux: ./build/linux/Taskfile.yml + +vars: + APP_NAME: "NukeShip" + BIN_DIR: "bin" + VITE_PORT: "{{.WAILS_VITE_PORT | default 9245}}" + +tasks: + build: + summary: Builds the application + cmds: + - task: "{{OS}}:build" + + package: + summary: Packages a production build of the application + cmds: + - task: "{{OS}}:package" + + run: + summary: Runs the application + cmds: + - task: "{{OS}}:run" + + dev: + summary: Runs the application in development mode + cmds: + - wails3 dev -config ./build/config.yml -port {{.VITE_PORT}} diff --git a/pkg/client/app.go b/pkg/client/app.go index 1f70520..342d973 100644 --- a/pkg/client/app.go +++ b/pkg/client/app.go @@ -15,23 +15,25 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" + "github.com/wailsapp/wails/v3/pkg/application" + + "github.com/Gurpartap/statemachine-go" + "passeriform.com/nukeship/internal/client" "passeriform.com/nukeship/internal/pb" ) -const ( - StateChangeEvent Event = "srv:stateChange" - ServerConnectionChangeEvent Event = "srv:serverConnectionChange" -) - +//go:generate go run github.com/abice/go-enum -f=$GOFILE --mustparse --values --output-suffix _generated type ( + // ENUM(srv:RoomStateChange, srv:ServerConnectionChange) Event string ) -type WailsApp struct { +type WailsRoomService struct { //nolint:containedctx // Wails enforces usage of contexts within structs for binding. grpcCtx context.Context Client pb.RoomServiceClient + emit func(name string, data ...any) stateMachine *client.RoomStateFSM connMachine *client.ConnectionFSM } @@ -55,6 +57,7 @@ func newClient(ctx context.Context) (pb.RoomServiceClient, error) { ) if err != nil { log.Printf("Could not connect: %v", err) + return nil, err } @@ -65,132 +68,170 @@ func newClient(ctx context.Context) (pb.RoomServiceClient, error) { // TODO: Add reconnection logic to recover streaming messages. -func (app *WailsApp) connect(ctx context.Context) { +func (srv *WailsRoomService) connect(ctx context.Context) { defer func() { - app.connMachine.Fire(client.ClientMessageDISCONNECTED.String()) + srv.connMachine.Fire(client.ClientMessageDISCONNECTED.String()) }() streamCtx, cancel := client.NewStreamContext(ctx) defer cancel() - streamClient, err := app.Client.SubscribeMessages(streamCtx, &pb.SubscribeMessagesRequest{}) + streamClient, err := srv.Client.SubscribeMessages(streamCtx, &pb.SubscribeMessagesRequest{}) if err != nil { log.Printf("Subscription to server messages failed: %v", err) + return } - app.connMachine.Fire(client.ClientMessageCONNECTED.String()) + srv.connMachine.Fire(client.ClientMessageCONNECTED.String()) for { update, err := streamClient.Recv() if errors.Is(err, io.EOF) { log.Println("Stopped receiving updates from server.") + return } if err != nil { log.Printf("Received error frame: %v", err) + return } - app.stateMachine.Fire(update.GetType().String()) + srv.stateMachine.Fire(update.GetType().String()) } } -func newWailsApp(grpcCtx context.Context) *WailsApp { - app := &WailsApp{ +func NewWailsRoomService(grpcCtx context.Context) *WailsRoomService { + return &WailsRoomService{ grpcCtx: grpcCtx, Client: nil, + emit: nil, stateMachine: nil, connMachine: nil, } +} + +func (srv *WailsRoomService) setEmitter(emit func(name string, data ...any)) { + srv.emit = emit +} + +func (srv *WailsRoomService) OnStartup(_ context.Context, _ application.ServiceOptions) error { + c, err := newClient(srv.grpcCtx) + if err != nil { + log.Panicf("Cannot create new grpc client: %v", err) + return err + } + + srv.Client = c + + srv.stateMachine = client.NewRoomStateFSM(func(t statemachine.Transition) { + srv.emit(EventSrvRoomStateChange.String(), client.MustParseRoomState(t.To())) + }) + + srv.connMachine = client.NewConnectionFSM(func(t statemachine.Transition) { + srv.emit(EventSrvServerConnectionChange.String(), t.To() == client.ConnectionStateCONNECTED.String()) + }) + + go srv.connect(srv.grpcCtx) + + return nil +} - return app +func (srv *WailsRoomService) GetAllEvents() []Event { + return EventValues() } -func (app *WailsApp) GetAppState() client.RoomState { - return client.MustParseRoomState(app.stateMachine.GetState()) +func (srv *WailsRoomService) GetRoomState() client.RoomState { + return client.MustParseRoomState(srv.stateMachine.GetState()) } -func (app *WailsApp) GetConnectionState() bool { - return app.connMachine.GetState() == client.ConnectionStateCONNECTED.String() +func (srv *WailsRoomService) GetConnectionState() bool { + return srv.connMachine.GetState() == client.ConnectionStateCONNECTED.String() } -func (app *WailsApp) UpdateReady(ready bool) (bool, error) { - unaryCtx, cancel := client.NewUnaryContext(app.grpcCtx) +func (srv *WailsRoomService) UpdateReady(ready bool) (bool, error) { + unaryCtx, cancel := client.NewUnaryContext(srv.grpcCtx) defer cancel() // TODO: Use error codes middleware to handle RPC errors properly. - resp, err := app.Client.UpdateReady(unaryCtx, &pb.UpdateReadyRequest{Ready: ready}) + resp, err := srv.Client.UpdateReady(unaryCtx, &pb.UpdateReadyRequest{Ready: ready}) if err != nil { log.Printf("Could not update ready state: %v", err) + return false, err } if resp.GetStatus() == pb.ResponseStatus_NO_ROOM_JOINED_YET { log.Printf("Unable to ready as the room is invalid") + return false, nil } log.Printf("Updated ready state: %t", ready) if !ready { - app.stateMachine.Fire(client.ClientMessageSELFREVERTEDREADY.String()) + srv.stateMachine.Fire(client.ClientMessageSELFREVERTEDREADY.String()) + return resp.GetStatus() == pb.ResponseStatus_OK, nil } - app.stateMachine.Fire(client.ClientMessageSELFREADY.String()) + srv.stateMachine.Fire(client.ClientMessageSELFREADY.String()) return resp.GetStatus() == pb.ResponseStatus_OK, nil } -func (app *WailsApp) CreateRoom() (string, error) { - unaryCtx, cancel := client.NewUnaryContext(app.grpcCtx) +func (srv *WailsRoomService) CreateRoom() (string, error) { + unaryCtx, cancel := client.NewUnaryContext(srv.grpcCtx) defer cancel() - resp, err := app.Client.CreateRoom(unaryCtx, &pb.CreateRoomRequest{}) + resp, err := srv.Client.CreateRoom(unaryCtx, &pb.CreateRoomRequest{}) if err != nil { log.Printf("Could not create room: %v", err) + return "", err } log.Printf("Room created: %s", resp.GetRoomId()) - app.stateMachine.Fire(client.ClientMessageSELFJOINED.String()) + srv.stateMachine.Fire(client.ClientMessageSELFJOINED.String()) return resp.GetRoomId(), nil } -func (app *WailsApp) JoinRoom(roomCode string) bool { - unaryCtx, cancel := client.NewUnaryContext(app.grpcCtx) +func (srv *WailsRoomService) JoinRoom(roomCode string) bool { + unaryCtx, cancel := client.NewUnaryContext(srv.grpcCtx) defer cancel() - resp, err := app.Client.JoinRoom(unaryCtx, &pb.JoinRoomRequest{RoomId: roomCode}) + resp, err := srv.Client.JoinRoom(unaryCtx, &pb.JoinRoomRequest{RoomId: roomCode}) if err != nil { log.Printf("Could not join room with id %v: %v", roomCode, err) + return false } log.Printf("Room joined status: %s", resp.GetStatus().String()) - app.stateMachine.Fire(client.ClientMessageSELFJOINED.String()) + srv.stateMachine.Fire(client.ClientMessageSELFJOINED.String()) return resp.GetStatus() == pb.ResponseStatus_OK } -func (app *WailsApp) LeaveRoom() bool { - unaryCtx, cancel := client.NewUnaryContext(app.grpcCtx) +func (srv *WailsRoomService) LeaveRoom() bool { + unaryCtx, cancel := client.NewUnaryContext(srv.grpcCtx) defer cancel() - resp, err := app.Client.LeaveRoom(unaryCtx, &pb.LeaveRoomRequest{}) + resp, err := srv.Client.LeaveRoom(unaryCtx, &pb.LeaveRoomRequest{}) if err != nil { log.Printf("Could not leave room: %v", err) + return false } log.Printf("Room left status: %s", resp.GetStatus().String()) - app.stateMachine.Fire(client.ClientMessageSELFLEFT.String()) + srv.stateMachine.Fire(client.ClientMessageSELFLEFT.String()) return resp.GetStatus() == pb.ResponseStatus_OK } diff --git a/pkg/client/build/Taskfile.yml b/pkg/client/build/Taskfile.yml new file mode 100644 index 0000000..6874731 --- /dev/null +++ b/pkg/client/build/Taskfile.yml @@ -0,0 +1,77 @@ +version: "3" + +tasks: + go:mod:tidy: + summary: Runs `go mod tidy` + internal: true + cmds: + - go mod tidy + + install:frontend:deps: + summary: Install frontend dependencies + dir: frontend + sources: + - package.json + - package-lock.json + generates: + - node_modules/* + preconditions: + - sh: npm version + msg: "Looks like npm isn't installed. Npm is part of the Node installer: https://nodejs.org/en/download/" + cmds: + - npm install + + build:frontend: + summary: Build the frontend project + dir: frontend + sources: + - "**/*" + generates: + - dist/* + deps: + - task: install:frontend:deps + - task: generate:bindings + cmds: + - npm run {{.BUILD_COMMAND}} -q + env: + PRODUCTION: '{{.PRODUCTION | default "false"}}' + vars: + BUILD_COMMAND: '{{if eq .PRODUCTION "true"}}build{{else}}build:dev{{end}}' + + generate:bindings: + summary: Generates bindings for the frontend + deps: + - task: go:mod:tidy + sources: + - "**/*.go" + - go.mod + - go.sum + generates: + - "frontend/bindings/**/*" + cmds: + - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true -ts + + generate:icons: + summary: Generates Windows `.ico` and Mac `.icns` files from an image + dir: build + sources: + - "appicon.png" + generates: + - "icons.icns" + - "icon.ico" + cmds: + - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico + + dev:frontend: + summary: Runs the frontend in development mode + dir: frontend + deps: + - task: install:frontend:deps + cmds: + - npm run dev -- --port {{.VITE_PORT}} --strictPort + + update:build-assets: + summary: Updates the build assets + dir: build + cmds: + - wails3 update build-assets -name "{{.APP_NAME}}" -binaryname "{{.APP_NAME}}" -config config.yml -dir . diff --git a/pkg/client/build/appicon.png b/pkg/client/build/appicon.png index 32a5890..5bdce7e 100644 Binary files a/pkg/client/build/appicon.png and b/pkg/client/build/appicon.png differ diff --git a/pkg/client/build/config.yml b/pkg/client/build/config.yml new file mode 100644 index 0000000..58784bc --- /dev/null +++ b/pkg/client/build/config.yml @@ -0,0 +1,62 @@ +# This file contains the configuration for this project. +# When you update `info` or `fileAssociations`, run `wails3 task common:update:build-assets` to update the assets. +# Note that this will overwrite any changes you have made to the assets. +version: "3" + +# This information is used to generate the build assets. +info: + companyName: "Passeriform" # The name of the company + productName: "NukeShip" # The name of the application + productIdentifier: "com.passeriform.nukeship" # The unique product identifier + description: "A cyberpunk twist on battleships." # The application description + copyright: "© 2025, Passeriform" # Copyright text + comments: "" # Comments + version: "v0.1.0" # The application version + +# Dev mode configuration +dev_mode: + root_path: . + log_level: warn + debounce: 1000 + ignore: + dir: + - .git + - node_modules + - frontend + - bin + file: + - .DS_Store + - .gitignore + - .gitkeep + watched_extension: + - "*.go" + git_ignore: true + executes: + - cmd: wails3 task common:install:frontend:deps + type: once + - cmd: wails3 task common:dev:frontend + type: background + - cmd: go mod tidy + type: blocking + - cmd: wails3 task build + type: blocking + - cmd: wails3 task run + type: primary + +# File Associations +# More information at: https://v3alpha.wails.io/noit/done/yet +fileAssociations: +# - ext: wails +# name: Wails +# description: Wails Application File +# iconName: wailsFileIcon +# role: Editor +# - ext: jpg +# name: JPEG +# description: Image File +# iconName: jpegFileIcon +# role: Editor + +# Other data +other: + - name: My Other Data diff --git a/pkg/client/build/darwin/Info.dev.plist b/pkg/client/build/darwin/Info.dev.plist new file mode 100644 index 0000000..6fea2cd --- /dev/null +++ b/pkg/client/build/darwin/Info.dev.plist @@ -0,0 +1,32 @@ + + + + CFBundlePackageType + APPL + CFBundleName + NukeShip + CFBundleExecutable + .exe + CFBundleIdentifier + com.passeriform. + CFBundleVersion + 0.1.0 + CFBundleGetInfoString + + CFBundleShortVersionString + 0.1.0 + CFBundleIconFile + icons + LSMinimumSystemVersion + 10.13.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + © 2025, Passeriform + NSAppTransportSecurity + + NSAllowsLocalNetworking + + + + \ No newline at end of file diff --git a/pkg/client/build/darwin/Info.plist b/pkg/client/build/darwin/Info.plist new file mode 100644 index 0000000..b8c21aa --- /dev/null +++ b/pkg/client/build/darwin/Info.plist @@ -0,0 +1,27 @@ + + + + CFBundlePackageType + APPL + CFBundleName + NukeShip + CFBundleExecutable + .exe + CFBundleIdentifier + com.passeriform. + CFBundleVersion + 0.1.0 + CFBundleGetInfoString + + CFBundleShortVersionString + 0.1.0 + CFBundleIconFile + icons + LSMinimumSystemVersion + 10.13.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + © 2025, Passeriform + + \ No newline at end of file diff --git a/pkg/client/build/darwin/Taskfile.yml b/pkg/client/build/darwin/Taskfile.yml new file mode 100644 index 0000000..7dae4c3 --- /dev/null +++ b/pkg/client/build/darwin/Taskfile.yml @@ -0,0 +1,69 @@ +version: "3" + +includes: + common: ../Taskfile.yml + +tasks: + build: + summary: Creates a production build of the application + deps: + - task: common:go:mod:tidy + - task: common:build:frontend + - task: common:generate:icons + cmds: + - go build {{.BUILD_FLAGS}} -o {{.OUTPUT}} + vars: + BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' + DEFAULT_OUTPUT: "{{.BIN_DIR}}/{{.APP_NAME}}" + OUTPUT: "{{ .OUTPUT | default .DEFAULT_OUTPUT }}" + env: + GOOS: darwin + CGO_ENABLED: 1 + GOARCH: "{{.ARCH | default ARCH}}" + CGO_CFLAGS: "-mmacosx-version-min=10.15" + CGO_LDFLAGS: "-mmacosx-version-min=10.15" + MACOSX_DEPLOYMENT_TARGET: "10.15" + PRODUCTION: '{{.PRODUCTION | default "false"}}' + + build:universal: + summary: Builds darwin universal binary (arm64 + amd64) + deps: + - task: build + vars: + ARCH: amd64 + OUTPUT: "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" + - task: build + vars: + ARCH: arm64 + OUTPUT: "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" + cmds: + - lipo -create -output "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" + - rm "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" + + package: + summary: Packages a production build of the application into a `.app` bundle + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: create:app:bundle + + package:universal: + summary: Packages darwin universal binary (arm64 + amd64) + deps: + - task: build:universal + cmds: + - task: create:app:bundle + + create:app:bundle: + summary: Creates an `.app` bundle + cmds: + - mkdir -p {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/{MacOS,Resources} + - cp build/darwin/icons.icns {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources + - cp {{.BIN_DIR}}/{{.APP_NAME}} {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/MacOS + - cp build/darwin/Info.plist {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents + + run: + cmds: + - "{{.BIN_DIR}}/{{.APP_NAME}}" diff --git a/pkg/client/build/darwin/icons.icns b/pkg/client/build/darwin/icons.icns new file mode 100644 index 0000000..e7de4f9 Binary files /dev/null and b/pkg/client/build/darwin/icons.icns differ diff --git a/pkg/client/build/linux/Taskfile.yml b/pkg/client/build/linux/Taskfile.yml new file mode 100644 index 0000000..40988df --- /dev/null +++ b/pkg/client/build/linux/Taskfile.yml @@ -0,0 +1,114 @@ +version: "3" + +includes: + common: ../Taskfile.yml + +tasks: + build: + summary: Builds the application for Linux + deps: + - task: common:go:mod:tidy + - task: common:build:frontend + - task: common:generate:icons + cmds: + - go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}} + vars: + BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' + env: + GOOS: linux + CGO_ENABLED: 1 + GOARCH: "{{.ARCH | default ARCH}}" + PRODUCTION: '{{.PRODUCTION | default "false"}}' + + package: + summary: Packages a production build of the application for Linux + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: create:appimage + - task: create:deb + - task: create:rpm + - task: create:aur + + create:appimage: + summary: Creates an AppImage + dir: build/linux/appimage + deps: + - task: build + vars: + PRODUCTION: "true" + - task: generate:dotdesktop + cmds: + - cp {{.APP_BINARY}} {{.APP_NAME}} + - cp ../../appicon.png appicon.png + - wails3 generate appimage -binary {{.APP_NAME}} -icon {{.ICON}} -desktopfile {{.DESKTOP_FILE}} -outputdir {{.OUTPUT_DIR}} -builddir {{.ROOT_DIR}}/build/linux/appimage/build + vars: + APP_NAME: "{{.APP_NAME}}" + APP_BINARY: "../../../bin/{{.APP_NAME}}" + ICON: "../../appicon.png" + DESKTOP_FILE: "../{{.APP_NAME}}.desktop" + OUTPUT_DIR: "../../../bin" + + create:deb: + summary: Creates a deb package + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: generate:dotdesktop + - task: generate:deb + + create:rpm: + summary: Creates a rpm package + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: generate:dotdesktop + - task: generate:rpm + + create:aur: + summary: Creates a arch linux packager package + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: generate:dotdesktop + - task: generate:aur + + generate:deb: + summary: Creates a deb package + cmds: + - wails3 tool package -name {{.APP_NAME}} -format deb -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin + + generate:rpm: + summary: Creates a rpm package + cmds: + - wails3 tool package -name {{.APP_NAME}} -format rpm -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin + + generate:aur: + summary: Creates a arch linux packager package + cmds: + - wails3 tool package -name {{.APP_NAME}} -format archlinux -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin + + generate:dotdesktop: + summary: Generates a `.desktop` file + dir: build + cmds: + - mkdir -p {{.ROOT_DIR}}/build/linux/appimage + - wails3 generate .desktop -name "{{.APP_NAME}}" -exec "{{.EXEC}}" -icon "{{.ICON}}" -outputfile {{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop -categories "{{.CATEGORIES}}" + vars: + APP_NAME: "{{.APP_NAME}}" + EXEC: "{{.APP_NAME}}" + ICON: "appicon" + CATEGORIES: "Development;" + OUTPUTFILE: "{{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop" + + run: + cmds: + - "{{.BIN_DIR}}/{{.APP_NAME}}" diff --git a/pkg/client/build/linux/appimage/build.sh b/pkg/client/build/linux/appimage/build.sh new file mode 100644 index 0000000..fcba535 --- /dev/null +++ b/pkg/client/build/linux/appimage/build.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright (c) 2018-Present Lea Anthony +# SPDX-License-Identifier: MIT + +# Fail script on any error +set -euxo pipefail + +# Define variables +APP_DIR="${APP_NAME}.AppDir" + +# Create AppDir structure +mkdir -p "${APP_DIR}/usr/bin" +cp -r "${APP_BINARY}" "${APP_DIR}/usr/bin/" +cp "${ICON_PATH}" "${APP_DIR}/" +cp "${DESKTOP_FILE}" "${APP_DIR}/" + +# Download linuxdeploy and make it executable +wget -q -4 -N https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage +chmod +x linuxdeploy-x86_64.AppImage + +# Run linuxdeploy to bundle the application +./linuxdeploy-x86_64.AppImage --appdir "${APP_DIR}" --output appimage + +# Rename the generated AppImage +mv "${APP_NAME}*.AppImage" "${APP_NAME}.AppImage" + diff --git a/pkg/client/build/linux/nfpm/nfpm.yaml b/pkg/client/build/linux/nfpm/nfpm.yaml new file mode 100644 index 0000000..2cab5b0 --- /dev/null +++ b/pkg/client/build/linux/nfpm/nfpm.yaml @@ -0,0 +1,49 @@ +# Feel free to remove those if you don't want/need to use them. +# Make sure to check the documentation at https://nfpm.goreleaser.com +# +# The lines below are called `modelines`. See `:help modeline` + +name: ".exe" +arch: ${GOARCH} +platform: "linux" +version: "0.1.0" +section: "default" +priority: "extra" +maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}> +description: "A cyberpunk twist on battleships." +vendor: "Passeriform" +homepage: "https://nukeship.passeriform.com" +license: "MIT" +release: "1" + +contents: + - src: "./bin/.exe" + dst: "/usr/local/bin/.exe" + - src: "./build/appicon.png" + dst: "/usr/share/icons/hicolor/128x128/apps/.exe.png" + - src: "./build/linux/.exe.desktop" + dst: "/usr/share/applications/.exe.desktop" + +depends: + - gtk3 + - libwebkit2gtk +# replaces: +# - foobar +# provides: +# - bar +# depends: +# - gtk3 +# - libwebkit2gtk +# recommends: +# - whatever +# suggests: +# - something-else +# conflicts: +# - not-foo +# - not-bar +# changelog: "changelog.yaml" +# scripts: +# preinstall: ./build/linux/nfpm/scripts/preinstall.sh +# postinstall: ./build/linux/nfpm/scripts/postinstall.sh +# preremove: ./build/linux/nfpm/scripts/preremove.sh +# postremove: ./build/linux/nfpm/scripts/postremove.sh diff --git a/pkg/client/build/linux/nfpm/scripts/postinstall.sh b/pkg/client/build/linux/nfpm/scripts/postinstall.sh new file mode 100644 index 0000000..a9bf588 --- /dev/null +++ b/pkg/client/build/linux/nfpm/scripts/postinstall.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/pkg/client/build/linux/nfpm/scripts/postremove.sh b/pkg/client/build/linux/nfpm/scripts/postremove.sh new file mode 100644 index 0000000..a9bf588 --- /dev/null +++ b/pkg/client/build/linux/nfpm/scripts/postremove.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/pkg/client/build/linux/nfpm/scripts/preinstall.sh b/pkg/client/build/linux/nfpm/scripts/preinstall.sh new file mode 100644 index 0000000..a9bf588 --- /dev/null +++ b/pkg/client/build/linux/nfpm/scripts/preinstall.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/pkg/client/build/linux/nfpm/scripts/preremove.sh b/pkg/client/build/linux/nfpm/scripts/preremove.sh new file mode 100644 index 0000000..a9bf588 --- /dev/null +++ b/pkg/client/build/linux/nfpm/scripts/preremove.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/pkg/client/build/windows/Taskfile.yml b/pkg/client/build/windows/Taskfile.yml new file mode 100644 index 0000000..2959c90 --- /dev/null +++ b/pkg/client/build/windows/Taskfile.yml @@ -0,0 +1,60 @@ +version: "3" + +includes: + common: ../Taskfile.yml + +tasks: + build: + summary: Builds the application for Windows + deps: + - task: common:go:mod:tidy + - task: common:build:frontend + vars: + PRODUCTION: "{{.PRODUCTION}}" + - task: common:generate:icons + cmds: + - task: generate:syso + - go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}.exe + - cmd: powershell Remove-item *.syso + platforms: [windows] + - cmd: rm -f *.syso + platforms: [linux, darwin] + vars: + BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' + env: + GOOS: windows + CGO_ENABLED: 0 + GOARCH: "{{.ARCH | default ARCH}}" + PRODUCTION: '{{.PRODUCTION | default "false"}}' + + package: + summary: Packages a production build of the application into a `.exe` bundle + cmds: + - task: create:nsis:installer + + generate:syso: + summary: Generates Windows `.syso` file + dir: build + cmds: + - wails3 generate syso -arch {{.ARCH}} -icon windows/icon.ico -manifest windows/wails.exe.manifest -info windows/info.json -out ../wails_windows_{{.ARCH}}.syso + vars: + ARCH: "{{.ARCH | default ARCH}}" + + create:nsis:installer: + summary: Creates an NSIS installer + dir: build/windows/nsis + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + # Create the Microsoft WebView2 bootstrapper if it doesn't exist + - wails3 generate webview2bootstrapper -dir "{{.ROOT_DIR}}\build\windows\nsis" + - makensis -DARG_WAILS_{{.ARG_FLAG}}_BINARY="{{.ROOT_DIR}}\{{.BIN_DIR}}\{{.APP_NAME}}.exe" project.nsi + vars: + ARCH: "{{.ARCH | default ARCH}}" + ARG_FLAG: '{{if eq .ARCH "amd64"}}AMD64{{else}}ARM64{{end}}' + + run: + cmds: + - '{{.BIN_DIR}}\\{{.APP_NAME}}.exe' diff --git a/pkg/client/build/windows/icon.ico b/pkg/client/build/windows/icon.ico index 97c5c7f..597da20 100644 Binary files a/pkg/client/build/windows/icon.ico and b/pkg/client/build/windows/icon.ico differ diff --git a/pkg/client/build/windows/icons.ico b/pkg/client/build/windows/icons.ico new file mode 100644 index 0000000..597da20 Binary files /dev/null and b/pkg/client/build/windows/icons.ico differ diff --git a/pkg/client/build/windows/info.json b/pkg/client/build/windows/info.json index 074e55e..61f68b0 100644 --- a/pkg/client/build/windows/info.json +++ b/pkg/client/build/windows/info.json @@ -1,15 +1,15 @@ { "fixed": { - "file_version": "{{.Info.ProductVersion}}" + "file_version": "0.1.0" }, "info": { "0000": { - "ProductVersion": "{{.Info.ProductVersion}}", - "CompanyName": "{{.Info.CompanyName}}", - "FileDescription": "{{.Info.ProductName}}", - "LegalCopyright": "{{.Info.Copyright}}", - "ProductName": "{{.Info.ProductName}}", - "Comments": "{{.Info.Comments}}" + "ProductVersion": "0.1.0", + "CompanyName": "Passeriform", + "FileDescription": "A cyberpunk twist on battleships.", + "LegalCopyright": "© 2025, Passeriform", + "ProductName": "NukeShip", + "Comments": "" } } } diff --git a/pkg/client/build/windows/nsis/project.nsi b/pkg/client/build/windows/nsis/project.nsi new file mode 100644 index 0000000..93d29cb --- /dev/null +++ b/pkg/client/build/windows/nsis/project.nsi @@ -0,0 +1,112 @@ +Unicode true + +#### +## Please note: Template replacements don't work in this file. They are provided with default defines like +## mentioned underneath. +## If the keyword is not defined, "wails_tools.nsh" will populate them. +## If they are defined here, "wails_tools.nsh" will not touch them. This allows you to use this project.nsi manually +## from outside of Wails for debugging and development of the installer. +## +## For development first make a wails nsis build to populate the "wails_tools.nsh": +## > wails build --target windows/amd64 --nsis +## Then you can call makensis on this file with specifying the path to your binary: +## For a AMD64 only installer: +## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe +## For a ARM64 only installer: +## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe +## For a installer with both architectures: +## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe +#### +## The following information is taken from the wails_tools.nsh file, but they can be overwritten here. +#### +## !define INFO_PROJECTNAME "my-project" # Default "" +## !define INFO_COMPANYNAME "My Company" # Default "My Company" +## !define INFO_PRODUCTNAME "My Product Name" # Default "My Product" +## !define INFO_PRODUCTVERSION "1.0.0" # Default "0.1.0" +## !define INFO_COPYRIGHT "(c) Now, My Company" # Default "© now, My Company" +### +## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe" +## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +#### +## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html +#### +## Include the wails tools +#### +!include "wails_tools.nsh" + +# The version information for this two must consist of 4 parts +VIProductVersion "${INFO_PRODUCTVERSION}.0" +VIFileVersion "${INFO_PRODUCTVERSION}.0" + +VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}" +VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer" +VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}" +VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}" +VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}" +VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}" + +# Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware +ManifestDPIAware true + +!include "MUI.nsh" + +!define MUI_ICON "..\icon.ico" +!define MUI_UNICON "..\icon.ico" +# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314 +!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps +!define MUI_ABORTWARNING # This will warn the user if they exit from the installer. + +!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page. +# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer +!insertmacro MUI_PAGE_DIRECTORY # In which folder install page. +!insertmacro MUI_PAGE_INSTFILES # Installing page. +!insertmacro MUI_PAGE_FINISH # Finished installation page. + +!insertmacro MUI_UNPAGE_INSTFILES # Uninstalling page + +!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer + +## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1 +#!uninstfinalize 'signtool --file "%1"' +#!finalize 'signtool --file "%1"' + +Name "${INFO_PRODUCTNAME}" +OutFile "..\..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file. +InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder). +ShowInstDetails show # This will always show the installation details. + +Function .onInit + !insertmacro wails.checkArchitecture +FunctionEnd + +Section + !insertmacro wails.setShellContext + + !insertmacro wails.webview2runtime + + SetOutPath $INSTDIR + + !insertmacro wails.files + + CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + + !insertmacro wails.associateFiles + + !insertmacro wails.writeUninstaller +SectionEnd + +Section "uninstall" + !insertmacro wails.setShellContext + + RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath + + RMDir /r $INSTDIR + + Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" + Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" + + !insertmacro wails.unassociateFiles + + !insertmacro wails.deleteUninstaller +SectionEnd diff --git a/pkg/client/build/windows/nsis/wails_tools.nsh b/pkg/client/build/windows/nsis/wails_tools.nsh new file mode 100644 index 0000000..7922c62 --- /dev/null +++ b/pkg/client/build/windows/nsis/wails_tools.nsh @@ -0,0 +1,212 @@ +# DO NOT EDIT - Generated automatically by `wails build` + +!include "x64.nsh" +!include "WinVer.nsh" +!include "FileFunc.nsh" + +!ifndef INFO_PROJECTNAME + !define INFO_PROJECTNAME "nukeship" +!endif +!ifndef INFO_COMPANYNAME + !define INFO_COMPANYNAME "Passeriform" +!endif +!ifndef INFO_PRODUCTNAME + !define INFO_PRODUCTNAME "NukeShip" +!endif +!ifndef INFO_PRODUCTVERSION + !define INFO_PRODUCTVERSION "0.1.0" +!endif +!ifndef INFO_COPYRIGHT + !define INFO_COPYRIGHT "© 2025, Passeriform" +!endif +!ifndef PRODUCT_EXECUTABLE + !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" +!endif +!ifndef UNINST_KEY_NAME + !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +!endif +!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" + +!ifndef REQUEST_EXECUTION_LEVEL + !define REQUEST_EXECUTION_LEVEL "admin" +!endif + +RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" + +!ifdef ARG_WAILS_AMD64_BINARY + !define SUPPORTS_AMD64 +!endif + +!ifdef ARG_WAILS_ARM64_BINARY + !define SUPPORTS_ARM64 +!endif + +!ifdef SUPPORTS_AMD64 + !ifdef SUPPORTS_ARM64 + !define ARCH "amd64_arm64" + !else + !define ARCH "amd64" + !endif +!else + !ifdef SUPPORTS_ARM64 + !define ARCH "arm64" + !else + !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY" + !endif +!endif + +!macro wails.checkArchitecture + !ifndef WAILS_WIN10_REQUIRED + !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later." + !endif + + !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED + !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}" + !endif + + ${If} ${AtLeastWin10} + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + Goto ok + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + Goto ok + ${EndIf} + !endif + + IfSilent silentArch notSilentArch + silentArch: + SetErrorLevel 65 + Abort + notSilentArch: + MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}" + Quit + ${else} + IfSilent silentWin notSilentWin + silentWin: + SetErrorLevel 64 + Abort + notSilentWin: + MessageBox MB_OK "${WAILS_WIN10_REQUIRED}" + Quit + ${EndIf} + + ok: +!macroend + +!macro wails.files + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}" + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}" + ${EndIf} + !endif +!macroend + +!macro wails.writeUninstaller + WriteUninstaller "$INSTDIR\uninstall.exe" + + SetRegView 64 + WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" + WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" + WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" + + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0" +!macroend + +!macro wails.deleteUninstaller + Delete "$INSTDIR\uninstall.exe" + + SetRegView 64 + DeleteRegKey HKLM "${UNINST_KEY}" +!macroend + +!macro wails.setShellContext + ${If} ${REQUEST_EXECUTION_LEVEL} == "admin" + SetShellVarContext all + ${else} + SetShellVarContext current + ${EndIf} +!macroend + +# Install webview2 by launching the bootstrapper +# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment +!macro wails.webview2runtime + !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT + !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime" + !endif + + SetRegView 64 + # If the admin key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + + ${If} ${REQUEST_EXECUTION_LEVEL} == "user" + # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + ${EndIf} + + SetDetailsPrint both + DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" + SetDetailsPrint listonly + + InitPluginsDir + CreateDirectory "$pluginsdir\webview2bootstrapper" + SetOutPath "$pluginsdir\webview2bootstrapper" + File "MicrosoftEdgeWebview2Setup.exe" + ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' + + SetDetailsPrint both + ok: +!macroend + +# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b +!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0" + + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}" + + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open" + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}` +!macroend + +!macro APP_UNASSOCIATE EXT FILECLASS + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup` + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0" + + DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}` +!macroend + +!macro wails.associateFiles + ; Create file associations + +!macroend + +!macro wails.unassociateFiles + ; Delete app associations + +!macroend \ No newline at end of file diff --git a/pkg/client/build/windows/wails.exe.manifest b/pkg/client/build/windows/wails.exe.manifest index 17e1a23..a023bb3 100644 --- a/pkg/client/build/windows/wails.exe.manifest +++ b/pkg/client/build/windows/wails.exe.manifest @@ -1,6 +1,6 @@ - + diff --git a/pkg/client/frontend/.gitignore b/pkg/client/frontend/.gitignore index 4f4a360..e5b44e2 100644 --- a/pkg/client/frontend/.gitignore +++ b/pkg/client/frontend/.gitignore @@ -13,9 +13,6 @@ dist dist-ssr *.local -# Wails -wailsjs - # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/pkg/client/frontend/.prettierrc b/pkg/client/frontend/.prettierrc index a71879d..18f8f8e 100644 --- a/pkg/client/frontend/.prettierrc +++ b/pkg/client/frontend/.prettierrc @@ -11,11 +11,7 @@ "bracketSameLine": false, "arrowParens": "always", "printWidth": 120, - "importOrder": [ - "", - "^@(animations|assets|components|constants|game|hooks|pages|wails).*$", - "^[./].*$" - ], + "importOrder": ["", "^@(animations|assets|bindings|components|constants|game|hooks|pages).*$", "^[./].*$"], "importOrderSortSpecifiers": true, "importOrderGroupNamespaceSpecifiers": true } diff --git a/pkg/client/frontend/package-lock.json b/pkg/client/frontend/package-lock.json index 9e4e5a1..747a667 100644 --- a/pkg/client/frontend/package-lock.json +++ b/pkg/client/frontend/package-lock.json @@ -21,6 +21,7 @@ "@pyncz/tailwind-mask-image": "^2.0.0", "@trivago/prettier-plugin-sort-imports": "^5.2.1", "@types/node": "^22.10.5", + "@wailsio/runtime": "3.0.0-alpha.36", "@types/three": "^0.172.0", "@xpd/tailwind-3dtransforms": "^1.0.3", "autoprefixer": "^10.4.20", @@ -1365,6 +1366,35 @@ "undici-types": "~6.20.0" } }, + "node_modules/@wailsio/runtime": { + "version": "3.0.0-alpha.36", + "resolved": "https://registry.npmjs.org/@wailsio/runtime/-/runtime-3.0.0-alpha.36.tgz", + "integrity": "sha512-IPxzYLxgX8tOWcB1x2RHzx3VwRFTLAUrdeMQL2wZyaV7Xvtybt1h1WYaEp0iZiiNB/KCuCKIrnhnrN5sNDoDYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "nanoid": "^5.0.7" + } + }, + "node_modules/@wailsio/runtime/node_modules/nanoid": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz", + "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, "node_modules/@types/stats.js": { "version": "0.17.3", "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", diff --git a/pkg/client/frontend/package.json b/pkg/client/frontend/package.json index aeff0cb..6e7bc14 100644 --- a/pkg/client/frontend/package.json +++ b/pkg/client/frontend/package.json @@ -8,6 +8,7 @@ "start": "vite", "dev": "vite", "build": "tsc -b && vite build", + "build:dev": "tsc -b && vite build --minify false --mode development", "preview": "vite preview", "lint": "prettier .", "lint:fix": "prettier --write ." @@ -37,6 +38,7 @@ "tailwindcss-textshadow": "^2.1.3", "typescript": "~5.6.2", "vite": "^6.0.1", - "vite-plugin-solid": "^2.11.0" + "vite-plugin-solid": "^2.11.0", + "@wailsio/runtime": "3.0.0-alpha.36" } } diff --git a/pkg/client/frontend/src/components/PlayPanel.tsx b/pkg/client/frontend/src/components/PlayPanel.tsx index bab0e8a..89bcd05 100644 --- a/pkg/client/frontend/src/components/PlayPanel.tsx +++ b/pkg/client/frontend/src/components/PlayPanel.tsx @@ -2,8 +2,8 @@ import { useNavigate } from "@solidjs/router" import { Select } from "@thisbeyond/solid-select" import { VoidComponent, createSignal } from "solid-js" import toast from "solid-toast" +import { CreateRoom, JoinRoom } from "@bindings/pkg/client/wailsroomservice" import Button from "@components/Button" -import { CreateRoom, JoinRoom } from "@wails/go/main/WailsApp" // TODO: Get GAME_TYPE and MAX_ROOM_CODE_LENGTH from go app instead diff --git a/pkg/client/frontend/src/components/Tips.tsx b/pkg/client/frontend/src/components/Tips.tsx index b6a3640..f316443 100644 --- a/pkg/client/frontend/src/components/Tips.tsx +++ b/pkg/client/frontend/src/components/Tips.tsx @@ -1,17 +1,17 @@ import { VoidComponent } from "solid-js" +import { RoomState } from "@bindings/internal/client/models" import useGameState from "@hooks/useGameState" -import { client } from "@wails/go/models" // TODO: Add random tips about the game in this component. const tipsMapping = { - [client.RoomState.AWAITING_OPPONENT]: "Share the above room code with an opponent.", - [client.RoomState.ROOM_FILLED]: "Click on ready to begin the game.", - [client.RoomState.AWAITING_READY]: "You're all set. We'll begin when your opponent is ready.", - [client.RoomState.AWAITING_GAME_START]: "Grab a coffee. Things are about to get interesting...", -} satisfies Partial> + [RoomState.RoomStateAWAITINGOPPONENT]: "Share the above room code with an opponent.", + [RoomState.RoomStateROOMFILLED]: "Click on ready to begin the game.", + [RoomState.RoomStateAWAITINGREADY]: "You're all set. We'll begin when your opponent is ready.", + [RoomState.RoomStateAWAITINGGAMESTART]: "Grab a coffee. Things are about to get interesting...", +} satisfies Partial> -const getTipString = (state: client.RoomState | undefined) => tipsMapping[state as keyof typeof tipsMapping] || "" +const getTipString = (state: RoomState | undefined) => tipsMapping[state as keyof typeof tipsMapping] || "" const Tips: VoidComponent = () => { const { gameState } = useGameState() diff --git a/pkg/client/frontend/src/hooks/useConnection.tsx b/pkg/client/frontend/src/hooks/useConnection.tsx index b070e6d..0820f80 100644 --- a/pkg/client/frontend/src/hooks/useConnection.tsx +++ b/pkg/client/frontend/src/hooks/useConnection.tsx @@ -1,7 +1,7 @@ +import { Events } from "@wailsio/runtime" import { createResource, onCleanup, onMount } from "solid-js" -import { GetConnectionState } from "@wails/go/main/WailsApp" -import { main } from "@wails/go/models" -import { EventsOff, EventsOn } from "@wails/runtime/runtime" +import { Event } from "@bindings/pkg/client/models" +import { GetConnectionState } from "@bindings/pkg/client/wailsroomservice" const useConnection = () => { const [connected, { refetch }] = createResource(GetConnectionState) @@ -11,7 +11,7 @@ const useConnection = () => { }) onCleanup(() => { - EventsOff(main.Event.SERVER_CONNECTION_CHANGE) + Events.Off(Event.EventSrvServerConnectionChange) }) return { connected } diff --git a/pkg/client/frontend/src/hooks/useGameState.tsx b/pkg/client/frontend/src/hooks/useGameState.tsx index 89ab03d..2b5993b 100644 --- a/pkg/client/frontend/src/hooks/useGameState.tsx +++ b/pkg/client/frontend/src/hooks/useGameState.tsx @@ -1,7 +1,8 @@ +import { Events } from "@wailsio/runtime" import { createResource, onCleanup, onMount } from "solid-js" -import { GetAppState } from "@wails/go/main/WailsApp" -import { main } from "@wails/go/models" -import { EventsOff, EventsOn } from "@wails/runtime/runtime" +import { RoomState } from "@bindings/internal/client" +import { Event } from "@bindings/pkg/client/models" +import { GetRoomState } from "@bindings/pkg/client/wailsroomservice" const useGameState = () => { const [gameState, { refetch }] = createResource(GetAppState) @@ -11,7 +12,7 @@ const useGameState = () => { }) onCleanup(() => { - EventsOff(main.Event.STATE_CHANGE) + Events.Off(Event.EventSrvRoomStateChange) }) return { gameState } diff --git a/pkg/client/frontend/src/pages/Landing.tsx b/pkg/client/frontend/src/pages/Landing.tsx index 8bb2c41..bba0144 100644 --- a/pkg/client/frontend/src/pages/Landing.tsx +++ b/pkg/client/frontend/src/pages/Landing.tsx @@ -1,15 +1,15 @@ +import { Application } from "@wailsio/runtime" import { VoidComponent } from "solid-js" import NavButton from "@components/NavButton" import NukeSignal from "@components/NukeSignal" import PlayPanel from "@components/PlayPanel" import Splash from "@components/Splash" -import { Quit } from "@wails/runtime/runtime" const Landing: VoidComponent = () => { return ( <>
- + diff --git a/pkg/client/frontend/src/pages/WaitingRoom.tsx b/pkg/client/frontend/src/pages/WaitingRoom.tsx index 9b37f3d..616f1a3 100644 --- a/pkg/client/frontend/src/pages/WaitingRoom.tsx +++ b/pkg/client/frontend/src/pages/WaitingRoom.tsx @@ -2,25 +2,24 @@ import { useNavigate, useParams } from "@solidjs/router" import { Show, VoidComponent, createEffect } from "solid-js" import { Grid } from "solid-spinner" import waitingRoomVideo from "@assets/waiting_room.mp4" +import { RoomState } from "@bindings/internal/client" +import { LeaveRoom, UpdateReady } from "@bindings/pkg/client/wailsroomservice" import Button from "@components/Button" import NavButton from "@components/NavButton" import Tips from "@components/Tips" import VideoBackground from "@components/VideoBackground" import useGameState from "@hooks/useGameState" -import { LeaveRoom, UpdateReady } from "@wails/go/main/WailsApp" -import { client } from "@wails/go/models" // TODO: Disable all controls when server is disconnected. const messageMapping = { - [client.RoomState.AWAITING_OPPONENT]: "Waiting for an opponent to join...", - [client.RoomState.ROOM_FILLED]: "The playground is set!", - [client.RoomState.AWAITING_READY]: "Waiting for your opponent to get ready...", - [client.RoomState.AWAITING_GAME_START]: "Let the show begin!", -} satisfies Partial> + [RoomState.RoomStateAWAITINGOPPONENT]: "Waiting for an opponent to join...", + [RoomState.RoomStateROOMFILLED]: "The playground is set!", + [RoomState.RoomStateAWAITINGREADY]: "Waiting for your opponent to get ready...", + [RoomState.RoomStateAWAITINGGAMESTART]: "Let the show begin!", +} satisfies Partial> -const getMessageString = (state: client.RoomState | undefined) => - messageMapping[state as keyof typeof messageMapping] || "" +const getMessageString = (state: RoomState | undefined) => messageMapping[state as keyof typeof messageMapping] || "" const WaitingRoom: VoidComponent = () => { const { code } = useParams() @@ -28,12 +27,12 @@ const WaitingRoom: VoidComponent = () => { const { gameState } = useGameState() const showLoader = () => - [client.RoomState.AWAITING_OPPONENT, client.RoomState.AWAITING_READY, client.RoomState].includes( - gameState() as client.RoomState, + [RoomState.RoomStateAWAITINGOPPONENT, RoomState.RoomStateAWAITINGREADY, RoomState].includes( + gameState() as RoomState, ) const showReadyButton = () => - [client.RoomState.ROOM_FILLED, client.RoomState.AWAITING_READY].includes(gameState() as client.RoomState) - const isReady = () => gameState() === client.RoomState.AWAITING_READY + [RoomState.RoomStateROOMFILLED, RoomState.RoomStateAWAITINGREADY].includes(gameState() as RoomState) + const isReady = () => gameState() === RoomState.RoomStateAWAITINGREADY const goBack = () => { LeaveRoom() @@ -41,7 +40,7 @@ const WaitingRoom: VoidComponent = () => { } createEffect(() => { - if (gameState() == client.RoomState.IN_GAME) { + if (gameState() == RoomState.RoomStateINGAME) { navigate(`/game/${code}`) } }) diff --git a/pkg/client/frontend/tsconfig.json b/pkg/client/frontend/tsconfig.json index d7457f3..41504df 100644 --- a/pkg/client/frontend/tsconfig.json +++ b/pkg/client/frontend/tsconfig.json @@ -4,12 +4,12 @@ "paths": { "@animations/*": ["./src/animations/*"], "@assets/*": ["./src/assets/*"], + "@bindings/*": ["./bindings/passeriform.com/nukeship/*"], "@components/*": ["./src/components/*"], "@constants/*": ["./src/constants/*"], "@game/*": ["./src/game/*"], "@hooks/*": ["./src/hooks/*"], - "@pages/*": ["./src/pages/*"], - "@wails/*": ["./wailsjs/*"] + "@pages/*": ["./src/pages/*"] }, "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "target": "ESNext", diff --git a/pkg/client/frontend/vite.config.ts b/pkg/client/frontend/vite.config.ts index 124b2fa..360b263 100644 --- a/pkg/client/frontend/vite.config.ts +++ b/pkg/client/frontend/vite.config.ts @@ -11,12 +11,12 @@ export default defineConfig({ alias: { "@animations": path.resolve(__dirname, "./src/animations"), "@assets": path.resolve(__dirname, "./src/assets"), + "@bindings": path.resolve(__dirname, "./bindings/passeriform.com/nukeship"), "@components": path.resolve(__dirname, "./src/components"), "@constants": path.resolve(__dirname, "./src/constants"), "@game": path.resolve(__dirname, "./src/game"), "@hooks": path.resolve(__dirname, "./src/hooks"), "@pages": path.resolve(__dirname, "./src/pages"), - "@wails": path.resolve(__dirname, "./wailsjs"), }, }, }) diff --git a/pkg/client/wails.go b/pkg/client/wails.go index 5f66165..173c741 100644 --- a/pkg/client/wails.go +++ b/pkg/client/wails.go @@ -7,93 +7,81 @@ import ( "embed" "log" - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/linux" - "github.com/wailsapp/wails/v2/pkg/options/mac" - "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" - "github.com/Gurpartap/statemachine-go" - - "passeriform.com/nukeship/internal/client" + "github.com/leaanthony/u" ) var ( - //go:embed frontend/dist + //go:embed all:frontend/dist assets embed.FS //go:embed frontend/src/assets/radioactive.svg icon []byte ) -var ( - appStatesMapping = []struct { - Value client.RoomState - TSName string - }{ - {client.RoomStateINIT, "INIT"}, - {client.RoomStateAWAITINGOPPONENT, "AWAITING_OPPONENT"}, - {client.RoomStateROOMFILLED, "ROOM_FILLED"}, - {client.RoomStateAWAITINGREADY, "AWAITING_READY"}, - {client.RoomStateAWAITINGGAMESTART, "AWAITING_GAME_START"}, - {client.RoomStateINGAME, "IN_GAME"}, - {client.RoomStateRECOVERY, "RECOVERY"}, - } - - eventsMapping = []struct { - Value Event - TSName string - }{ - {StateChangeEvent, "STATE_CHANGE"}, - {ServerConnectionChangeEvent, "SERVER_CONNECTION_CHANGE"}, - } -) - func RunApp(ctx context.Context) { - app := newWailsApp(ctx) - - err := wails.Run(&options.App{ - Title: "NukeShip", - DisableResize: true, - Fullscreen: true, - Frameless: true, - Assets: assets, - OnStartup: func(wCtx context.Context) { - c, err := newClient(ctx) - if err != nil { - log.Panicf("Cannot create new grpc client: %v", err) - } - - app.Client = c + roomService := NewWailsRoomService(ctx) - app.stateMachine = client.NewRoomStateFSM(func(t statemachine.Transition) { - runtime.EventsEmit(wCtx, string(StateChangeEvent), client.MustParseRoomState(t.To())) - }) - - app.connMachine = client.NewConnectionFSM(func(t statemachine.Transition) { - runtime.EventsEmit(wCtx, string(ServerConnectionChangeEvent), t.To() == client.ConnectionStateCONNECTED.String()) - }) - - go app.connect(ctx) + app := application.New(application.Options{ + Name: "NukeShip", + Description: "A cyberpunk twist on battleships.", + Icon: icon, + Mac: application.MacOptions{ + ApplicationShouldTerminateAfterLastWindowClosed: true, + }, + Services: []application.Service{ + application.NewService(roomService), }, - WindowStartState: options.Fullscreen, - Bind: []any{app}, - EnumBind: []any{appStatesMapping, eventsMapping}, - EnableDefaultContextMenu: false, - EnableFraudulentWebsiteDetection: false, - Mac: &mac.Options{ - About: &mac.AboutInfo{ - Title: "NukeShip", - Message: "© 2024 Passeriform", - Icon: icon, + Assets: application.AssetOptions{ + Handler: application.AssetFileServerFS(assets), + }, + // Flags: , + // PanicHandler: , + // OnShutdown: , + // ShouldQuit: , + // FileAssociations: [".skin"], + // SingleInstance: &application.SingleInstanceOptions{ + // UniqueID: "com.passeriform.nukeship", + // ExitCode: 0, + // }, + }) + + app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ + Name: "NukeShip", + Title: "NukeShip", + URL: "/", + BackgroundColour: application.NewRGB(27, 38, 54), + DisableResize: true, + Frameless: true, + StartState: application.WindowStateFullscreen, + BackgroundType: application.BackgroundTypeTranslucent, + Mac: application.MacWindow{ + Backdrop: application.MacBackdropTranslucent, + TitleBar: application.MacTitleBarHiddenInset, + InvisibleTitleBarHeight: 0, + EnableFraudulentWebsiteWarnings: true, + WebviewPreferences: application.MacWebviewPreferences{ + TabFocusesLinks: u.True, + TextInteractionEnabled: application.Enabled, + FullscreenEnabled: application.Enabled, }, }, - Linux: &linux.Options{ - Icon: icon, - ProgramName: "NukeShip", + Windows: application.WindowsWindow{ + BackdropType: application.Acrylic, + }, + Linux: application.LinuxWindow{ + Icon: icon, }, + DefaultContextMenuDisabled: true, + // DevToolsEnabled: , + // OpenInspectorOnStartup: , }) + + roomService.setEmitter(app.EmitEvent) + + err := app.Run() if err != nil { - log.Panicf("Error occurred while running GUI app: %v", err) + log.Panicf("Error occurred while running the app: %v", err) } } diff --git a/pkg/client/wails.json b/pkg/client/wails.json deleted file mode 100644 index 8a62e6d..0000000 --- a/pkg/client/wails.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "nukeship", - "outputfilename": "NukeShip", - "frontend:install": "npm install", - "frontend:build": "npm run build", - "frontend:dev:watcher": "npm run dev", - "frontend:dev:serverUrl": "auto", - "assetdir": "frontend/dist", - "author": { - "name": "Utkarsh Bhardwaj (Passeriform)", - "email": "bhardwajutkarsh.ub@gmail.com" - }, - "obfuscated": true -} diff --git a/scripts/changelog_gen.sh b/scripts/changelog_gen.sh new file mode 100644 index 0000000..c1c4caa --- /dev/null +++ b/scripts/changelog_gen.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +# Accept a tag as an argument +NEW_TAG=$1 + +echo "Released $NEW_TAG 🚀" + +echo "# Changelog 🗒" + +declare -A commits +declare -A special_commits + +# Get the latest tag before the provided one +if git rev-parse "$NEW_TAG" >/dev/null 2>&1; then + LATEST_TAG=$(git describe --tags --abbrev=0 --exclude="$NEW_TAG" 2>/dev/null) +else + NEW_TAG="HEAD" + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null) +fi + +# Determine log range +if [ -z "$LATEST_TAG" ]; then + LOG_RANGE="$NEW_TAG" +else + LOG_RANGE="$LATEST_TAG..$NEW_TAG" +fi + +# Get commit messages from the last tagged release or all commits if no tag exists +while IFS= read -r line; do + if [[ $line =~ ^\[([^]]+)\]\ (.*)$ ]]; then + category="${BASH_REMATCH[1]}" + message="${BASH_REMATCH[2]}" + + # Skip unwanted categories + case "$category" in + "Debug"|"Lint"|"Meta"|"CI/CD") + continue + ;; + esac + + # Separate special categories + case "$category" in + "Utility"|"Tool") + special_commits["$category"]+="- $message +" + ;; + *) + commits["$category"]+="- $message +" + ;; + esac + fi +done < <(git log $LOG_RANGE --pretty=format:"%s") + +# Output categorized commits +for category in "${!commits[@]}"; do + echo -e "\n## $category\n" + echo -e "${commits[$category]}" +done + +# Output special categories at the end +if [[ ${#special_commits[@]} -gt 0 ]]; then + echo -e "\n## Miscellaneous\n" + for category in "${!special_commits[@]}"; do + echo -e "\n### $category\n" + echo -e "${special_commits[$category]}" + done +fi