From 4699e9e3d44dddff406a4507664f772bc7206b7e Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Mon, 23 Dec 2024 08:45:43 +0800 Subject: [PATCH] New config format and rebrand (#124) * Move to new TOML config file * Fix defaults and add mode checks * Update service readers to use new config * Rename platform folders * Rename TapTo references * Rename TapTo reference in GH action * Rename binary in build script * Refactor directory handling and cleanup platform APIs * Rename LiveModeEnabled to CartModeEnabled and add wildcard checks * Update config handling to use platform-specific directories * Update socket file name to core.sock in configuration * Remove any old tapto startup entries on mister * Migrate old config DB and refactor platform setup order * Log config values on service start * Initial ini migrate function * Add migration from INI to TOML configuration files * Enable logging for config loading * Fix config file env loading path * Split platform start methods * Make legacy mappings file error clearer * Hide useless mister socket error * Move audio feedback setting * Cart mode -> hold mode * Add new config values and restructure file * Update settings api endpoint to match config * Introduce api versioning and move endpoint * Upgrade go version, mister image and switch to go-toml * Check schema version on load * Rename launcher module to zapscript * Move data files to assets dir * Allow specifying custom log outputs per platform * Output certain config arrays as multiline --- .github/workflows/mister_repo.yml | 8 +- Taskfile.dist.yml | 92 +++--- cmd/batocera/main.go | 51 +-- cmd/mac/main.go | 51 +-- cmd/mister/gui.go | 43 ++- cmd/mister/main.go | 50 ++- cmd/mistex/main.go | 62 ++-- cmd/steamos/main.go | 29 +- cmd/windows/main.go | 60 ++-- docs/developers.md | 2 +- go.mod | 5 +- go.sum | 5 + pkg/api/client/client.go | 7 +- pkg/api/methods/games.go | 4 +- pkg/api/methods/settings.go | 96 +++--- pkg/api/methods/status.go | 4 +- pkg/api/models/params.go | 16 +- pkg/api/models/requests/requests.go | 2 +- pkg/api/models/responses.go | 16 +- pkg/api/server.go | 25 +- pkg/cli/cli.go | 22 +- pkg/config/app.go | 26 ++ pkg/config/config.go | 348 +++++++++++++++++++++ pkg/config/{ => migrate/iniconfig}/user.go | 15 +- pkg/config/migrate/migrate.go | 130 ++++++++ pkg/config/tapto.go | 27 -- pkg/database/database.go | 2 +- pkg/database/gamesdb/gamesdb.go | 10 +- pkg/database/gamesdb/indexing.go | 4 +- pkg/database/gamesdb/systems.go | 4 +- pkg/platforms/batocera/platform.go | 48 +-- pkg/platforms/mac/platform.go | 45 ++- pkg/platforms/mister/commands.go | 2 +- pkg/platforms/mister/config.go | 50 ++- pkg/platforms/mister/csvmappings.go | 28 +- pkg/platforms/mister/launchers.go | 22 +- pkg/platforms/mister/methods.go | 54 ++-- pkg/platforms/mister/platform.go | 93 ++++-- pkg/platforms/mister/socket.go | 5 +- pkg/platforms/mistex/platform.go | 60 ++-- pkg/platforms/platforms.go | 57 ++-- pkg/platforms/steamos/platform.go | 41 ++- pkg/platforms/windows/platform.go | 59 ++-- pkg/readers/acr122_pcsc/acr122_pcsc.go | 6 +- pkg/readers/acr122_pcsc/ndef.go | 10 +- pkg/readers/file/file.go | 6 +- pkg/readers/libnfc/libnfc.go | 8 +- pkg/readers/libnfc/tags/mifare.go | 10 +- pkg/readers/libnfc/tags/ndef.go | 10 +- pkg/readers/libnfc/tags/ndef_test.go | 10 +- pkg/readers/libnfc/tags/ntag.go | 10 +- pkg/readers/libnfc/tags/tags.go | 10 +- pkg/readers/optical_drive/optical_drive.go | 4 +- pkg/readers/pn532_uart/ndef.go | 10 +- pkg/readers/pn532_uart/pn532_uart.go | 6 +- pkg/readers/simple_serial/simple_serial.go | 6 +- pkg/service/mappings.go | 10 +- pkg/service/readers.go | 25 +- pkg/service/service.go | 90 +++--- pkg/utils/logging.go | 26 +- pkg/utils/paths.go | 8 +- pkg/utils/service.go | 23 +- pkg/utils/utils.go | 10 +- pkg/{launcher => zapscript}/commands.go | 29 +- pkg/{launcher => zapscript}/http.go | 2 +- pkg/{launcher => zapscript}/input.go | 2 +- pkg/{launcher => zapscript}/launch.go | 2 +- pkg/{launcher => zapscript}/utils.go | 2 +- scripts/mister/build/Dockerfile | 5 +- scripts/mister/build/build.sh | 2 +- scripts/mister/repo/generate.py | 8 +- 71 files changed, 1373 insertions(+), 757 deletions(-) create mode 100644 pkg/config/app.go create mode 100644 pkg/config/config.go rename pkg/config/{ => migrate/iniconfig}/user.go (94%) create mode 100644 pkg/config/migrate/migrate.go delete mode 100644 pkg/config/tapto.go rename pkg/{launcher => zapscript}/commands.go (90%) rename pkg/{launcher => zapscript}/http.go (98%) rename pkg/{launcher => zapscript}/input.go (99%) rename pkg/{launcher => zapscript}/launch.go (99%) rename pkg/{launcher => zapscript}/utils.go (96%) diff --git a/.github/workflows/mister_repo.yml b/.github/workflows/mister_repo.yml index df35657a..b90b944b 100644 --- a/.github/workflows/mister_repo.yml +++ b/.github/workflows/mister_repo.yml @@ -10,15 +10,15 @@ jobs: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} steps: - uses: actions/checkout@v2 - - name: Get latest TapTo release - id: taptoreleaseinfo + - name: Get latest Zaparoo release + id: zaparooreleaseinfo uses: cardinalby/git-get-release-action@v1 with: latest: true - repo: wizzomafizzo/tapto + repo: ZaparooProject/zaparoo-core - name: Create repo database run: | - python3 scripts/mister/repo/generate.py ${{ steps.taptoreleaseinfo.outputs.tag_name }} + python3 scripts/mister/repo/generate.py ${{ steps.zaparooreleaseinfo.outputs.tag_name }} - name: Commit repo database uses: EndBug/add-and-commit@v9 with: diff --git a/Taskfile.dist.yml b/Taskfile.dist.yml index 61e679f3..6d75bf54 100644 --- a/Taskfile.dist.yml +++ b/Taskfile.dist.yml @@ -11,32 +11,32 @@ dotenv: [".env"] tasks: build: cmds: - - go build --ldflags "-linkmode external -extldflags -static -s -w" -o _build/${PLATFORM}_{{ARCH}}/${TAPTO_BIN} ./cmd/$PLATFORM + - go build --ldflags "-linkmode external -extldflags -static -s -w" -o _build/${PLATFORM}_{{ARCH}}/${APP_BIN} ./cmd/$PLATFORM build-image-mister: vars: - IMAGE_NAME: tapto/mister-build + IMAGE_NAME: zaparoo/mister-build DOCKERFILE: "./scripts/mister/build" cmds: - docker build --platform linux/arm/v7 -t {{.IMAGE_NAME}} {{.DOCKERFILE}} build-image-mistex: vars: - IMAGE_NAME: tapto/mistex-build + IMAGE_NAME: zaparoo/mistex-build DOCKERFILE: "./scripts/linux_arm64/build" cmds: - docker build --platform linux/arm/v8 -t {{.IMAGE_NAME}} {{.DOCKERFILE}} build-image-batocera-arm64: vars: - IMAGE_NAME: tapto/batocera-arm64-build + IMAGE_NAME: zaparoo/batocera-arm64-build DOCKERFILE: "./scripts/linux_arm64/build" cmds: - docker build --platform linux/arm/v8 -t {{.IMAGE_NAME}} {{.DOCKERFILE}} build-image-batocera-amd64: vars: - IMAGE_NAME: tapto/batocera-amd64-build + IMAGE_NAME: zaparoo/batocera-amd64-build DOCKERFILE: "./scripts/linux_amd64/build" cmds: - docker build --platform linux/amd64 -t {{.IMAGE_NAME}} {{.DOCKERFILE}} @@ -52,77 +52,77 @@ tasks: vars: BUILD_DIR: "./_build/mister_arm" BUILDCACHE: "{{.BUILD_DIR}}/.go-buildcache" - MODCACHE: "{{.BUILD_DIR}}/.go-modcache" - IMAGE_NAME: tapto/mister-build + GOCACHE: "{{.BUILD_DIR}}/.go-cache" + IMAGE_NAME: zaparoo/mister-build IMG_BUILDCACHE: /home/build/.cache/go-build - IMG_MODCACHE: /home/build/go/pkg/mod + IMG_GOCACHE: /home/build/go cmds: - - docker run --rm --platform linux/arm/v7 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.MODCACHE}}:{{.IMG_MODCACHE}} -v ${PWD}:/build --user 1000:1000 {{.IMAGE_NAME}} build.sh - - rm -f {{.BUILD_DIR}}/tapto-mister_arm.zip - - zip -j {{.BUILD_DIR}}/tapto-mister_arm.zip {{.BUILD_DIR}}/tapto.sh + - docker run --rm --platform linux/arm/v7 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.GOCACHE}}:{{.IMG_GOCACHE}} -v ${PWD}:/build --user 1000:1000 {{.IMAGE_NAME}} build.sh + - rm -f {{.BUILD_DIR}}/zaparoo-mister_arm.zip + - zip -j {{.BUILD_DIR}}/zaparoo-mister_arm.zip {{.BUILD_DIR}}/zaparoo.sh build-mister-shell: vars: BUILD_DIR: "./_build/mister_arm" BUILDCACHE: "{{.BUILD_DIR}}/.go-buildcache" - MODCACHE: "{{.BUILD_DIR}}/.go-modcache" - IMAGE_NAME: tapto/mister-build + GOCACHE: "{{.BUILD_DIR}}/.go-cache" + IMAGE_NAME: zaparoo/mister-build IMG_BUILDCACHE: /home/build/.cache/go-build - IMG_MODCACHE: /home/build/go/pkg/mod + IMG_GOCACHE: /home/build/go cmds: - - docker run --rm --platform linux/arm/v7 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.MODCACHE}}:{{.IMG_MODCACHE}} -v ${PWD}:/build --user 1000:1000 -ti {{.IMAGE_NAME}} /bin/bash + - docker run --rm --platform linux/arm/v7 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.GOCACHE}}:{{.IMG_GOCACHE}} -v ${PWD}:/build --user 1000:1000 -ti {{.IMAGE_NAME}} /bin/bash build-mistex: vars: BUILD_DIR: "./_build/mistex_arm64" BUILDCACHE: "{{.BUILD_DIR}}/.go-buildcache" - MODCACHE: "{{.BUILD_DIR}}/.go-modcache" - IMAGE_NAME: tapto/mistex-build + GOCACHE: "{{.BUILD_DIR}}/.go-cache" + IMAGE_NAME: zaparoo/mistex-build IMG_BUILDCACHE: /home/build/.cache/go-build - IMG_MODCACHE: /home/build/go/pkg/mod + IMG_GOCACHE: /home/build/go cmds: - - docker run --rm --platform linux/arm/v8 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.MODCACHE}}:{{.IMG_MODCACHE}} -v ${PWD}:/build --user 1000:1000 {{.IMAGE_NAME}} bash -c "PLATFORM=mistex TAPTO_BIN=tapto.sh task build" - - rm -f {{.BUILD_DIR}}/tapto-mistex_arm64.zip - - zip -j {{.BUILD_DIR}}/tapto-mistex_arm64.zip {{.BUILD_DIR}}/tapto.sh + - docker run --rm --platform linux/arm/v8 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.GOCACHE}}:{{.IMG_GOCACHE}} -v ${PWD}:/build --user 1000:1000 {{.IMAGE_NAME}} bash -c "PLATFORM=mistex APP_BIN=zaparoo.sh task build" + - rm -f {{.BUILD_DIR}}/zaparoo-mistex_arm64.zip + - zip -j {{.BUILD_DIR}}/zaparoo-mistex_arm64.zip {{.BUILD_DIR}}/zaparoo.sh build-batocera-arm64: vars: BUILD_DIR: "./_build/batocera_arm64" BUILDCACHE: "{{.BUILD_DIR}}/.go-buildcache" - MODCACHE: "{{.BUILD_DIR}}/.go-modcache" - IMAGE_NAME: tapto/batocera-arm64-build + GOCACHE: "{{.BUILD_DIR}}/.go-cache" + IMAGE_NAME: zaparoo/batocera-arm64-build IMG_BUILDCACHE: /home/build/.cache/go-build - IMG_MODCACHE: /home/build/go/pkg/mod + IMG_GOCACHE: /home/build/go cmds: - - docker run --rm --platform linux/arm/v8 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.MODCACHE}}:{{.IMG_MODCACHE}} -v ${PWD}:/build --user 1000:1000 {{.IMAGE_NAME}} bash -c "PLATFORM=batocera TAPTO_BIN=tapto task build" - - rm -f {{.BUILD_DIR}}/tapto-batocera_arm64.zip - - zip -j {{.BUILD_DIR}}/tapto-batocera_arm64.zip {{.BUILD_DIR}}/tapto + - docker run --rm --platform linux/arm/v8 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.GOCACHE}}:{{.IMG_GOCACHE}} -v ${PWD}:/build --user 1000:1000 {{.IMAGE_NAME}} bash -c "PLATFORM=batocera APP_BIN=zaparoo task build" + - rm -f {{.BUILD_DIR}}/zaparoo-batocera_arm64.zip + - zip -j {{.BUILD_DIR}}/zaparoo-batocera_arm64.zip {{.BUILD_DIR}}/zaparoo build-batocera-amd64: vars: BUILD_DIR: "./_build/batocera_amd64" BUILDCACHE: "{{.BUILD_DIR}}/.go-buildcache" - MODCACHE: "{{.BUILD_DIR}}/.go-modcache" - IMAGE_NAME: tapto/batocera-amd64-build + GOCACHE: "{{.BUILD_DIR}}/.go-cache" + IMAGE_NAME: zaparoo/batocera-amd64-build IMG_BUILDCACHE: /home/build/.cache/go-build - IMG_MODCACHE: /home/build/go/pkg/mod + IMG_GOCACHE: /home/build/go cmds: - - docker run --rm --platform linux/amd64 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.MODCACHE}}:{{.IMG_MODCACHE}} -v ${PWD}:/build --user 1000:1000 {{.IMAGE_NAME}} bash -c "PLATFORM=batocera TAPTO_BIN=tapto task build" - - rm -f {{.BUILD_DIR}}/tapto-batocera_amd64.zip - - zip -j {{.BUILD_DIR}}/tapto-batocera_amd64.zip {{.BUILD_DIR}}/tapto + - docker run --rm --platform linux/amd64 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.GOCACHE}}:{{.IMG_GOCACHE}} -v ${PWD}:/build --user 1000:1000 {{.IMAGE_NAME}} bash -c "PLATFORM=batocera APP_BIN=zaparoo task build" + - rm -f {{.BUILD_DIR}}/zaparoo-batocera_amd64.zip + - zip -j {{.BUILD_DIR}}/zaparoo-batocera_amd64.zip {{.BUILD_DIR}}/zaparoo build-steamos-amd64: vars: BUILD_DIR: "./_build/steamos_amd64" BUILDCACHE: "{{.BUILD_DIR}}/.go-buildcache" - MODCACHE: "{{.BUILD_DIR}}/.go-modcache" + GOCACHE: "{{.BUILD_DIR}}/.go-cache" IMAGE_NAME: zaparoo/steamos-amd64-build IMG_BUILDCACHE: /home/build/.cache/go-build - IMG_MODCACHE: /home/build/go/pkg/mod + IMG_GOCACHE: /home/build/go cmds: - - docker run --rm --platform linux/amd64 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.MODCACHE}}:{{.IMG_MODCACHE}} -v ${PWD}:/build --user 1000:1000 {{.IMAGE_NAME}} bash -c "PLATFORM=steamos TAPTO_BIN=tapto task build" + - docker run --rm --platform linux/amd64 -v {{.BUILDCACHE}}:{{.IMG_BUILDCACHE}} -v {{.GOCACHE}}:{{.IMG_GOCACHE}} -v ${PWD}:/build --user 1000:1000 {{.IMAGE_NAME}} bash -c "PLATFORM=steamos APP_BIN=zaparoo task build" - rm -f {{.BUILD_DIR}}/zaparoo-steamos_amd64.zip - - zip -j {{.BUILD_DIR}}/zaparoo-steamos_amd64.zip {{.BUILD_DIR}}/tapto + - zip -j {{.BUILD_DIR}}/zaparoo-steamos_amd64.zip {{.BUILD_DIR}}/zaparoo build-windows: vars: @@ -130,10 +130,10 @@ tasks: env: GOOS: windows PLATFORM: windows - TAPTO_BIN: TapTo.exe + APP_BIN: Zaparoo.exe CGO_ENABLED: 0 cmds: - - go build -o _build/${PLATFORM}_{{ARCH}}/${TAPTO_BIN} ./cmd/$PLATFORM + - go build -o _build/${PLATFORM}_{{ARCH}}/${APP_BIN} ./cmd/$PLATFORM build-mac: vars: @@ -141,27 +141,27 @@ tasks: env: GOOS: darwin PLATFORM: mac - TAPTO_BIN: tapto + APP_BIN: zaparoo CGO_ENABLED: 0 cmds: - - go build -o _build/${PLATFORM}_{{ARCH}}/${TAPTO_BIN} ./cmd/$PLATFORM + - go build -o _build/${PLATFORM}_{{ARCH}}/${APP_BIN} ./cmd/$PLATFORM deploy-mister: cmds: - task: build-mister - - scp _build/mister_arm/tapto.sh root@${MISTER_IP}:/media/fat/Scripts/tapto.sh - - ssh root@${MISTER_IP} /media/fat/Scripts/tapto.sh -service restart + - scp _build/mister_arm/zaparoo.sh root@${MISTER_IP}:/media/fat/Scripts/zaparoo.sh + - ssh root@${MISTER_IP} /media/fat/Scripts/zaparoo.sh -service restart deploy-mistex: cmds: - task: build-mistex - - scp _build/mistex_arm64/tapto.sh root@${MISTEX_IP}:/media/fat/Scripts/tapto.sh - - ssh root@${MISTEX_IP} /media/fat/Scripts/tapto.sh -service restart + - scp _build/mistex_arm64/zaparoo.sh root@${MISTEX_IP}:/media/fat/Scripts/zaparoo.sh + - ssh root@${MISTEX_IP} /media/fat/Scripts/zaparoo.sh -service restart deploy-steamos: cmds: - task: build-steamos-amd64 - - scp _build/steamos_amd64/tapto deck@${STEAMOS_IP}:/home/deck/zaparoo/tapto + - scp _build/steamos_amd64/zaparoo deck@${STEAMOS_IP}:/home/deck/zaparoo/zaparoo clean: rm -rf _build diff --git a/cmd/batocera/main.go b/cmd/batocera/main.go index 99f92ce7..2c32927a 100755 --- a/cmd/batocera/main.go +++ b/cmd/batocera/main.go @@ -1,24 +1,22 @@ -//go:build linux - /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package main @@ -26,9 +24,11 @@ package main import ( "flag" "fmt" + "github.com/ZaparooProject/zaparoo-core/pkg/cli" + "github.com/rs/zerolog" + "io" "os" - "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/ZaparooProject/zaparoo-core/pkg/platforms/batocera" @@ -38,45 +38,26 @@ import ( "github.com/ZaparooProject/zaparoo-core/pkg/service" ) -const appName = "tapto" +const appName = config.AppName func main() { versionOpt := flag.Bool("version", false, "print version and exit") flag.Parse() if *versionOpt { - fmt.Println("TapTo v" + config.Version + " (mistex)") + fmt.Println("Zaparoo Core v" + config.AppVersion + " (batocera)") os.Exit(0) } pl := &batocera.Platform{} - err := utils.InitLogging(pl) - if err != nil { - fmt.Println("Error initializing logging:", err) - os.Exit(1) - } - cfg, err := config.NewUserConfig(appName, &config.UserConfig{ - TapTo: config.TapToConfig{ - ProbeDevice: true, - }, - Api: config.ApiConfig{ - Port: config.DefaultApiPort, - }, - }) - if err != nil { - log.Error().Msgf("error loading user config: %s", err) - fmt.Println("Error loading config:", err) - os.Exit(1) - } - - if cfg.GetDebug() { - zerolog.SetGlobalLevel(zerolog.DebugLevel) - } else { - zerolog.SetGlobalLevel(zerolog.InfoLevel) - } + cfg := cli.Setup( + pl, + config.BaseDefaults, + []io.Writer{zerolog.ConsoleWriter{Out: os.Stderr}}, + ) - fmt.Println("TapTo v" + config.Version) + fmt.Println("Zaparoo Core v" + config.AppVersion) stopSvc, err := service.Start(pl, cfg) if err != nil { diff --git a/cmd/mac/main.go b/cmd/mac/main.go index c744b7b2..b066b3af 100755 --- a/cmd/mac/main.go +++ b/cmd/mac/main.go @@ -1,24 +1,22 @@ -//go:build darwin - /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package main @@ -26,9 +24,11 @@ package main import ( "flag" "fmt" + "github.com/ZaparooProject/zaparoo-core/pkg/cli" + "github.com/rs/zerolog" + "io" "os" - "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/ZaparooProject/zaparoo-core/pkg/platforms/mac" @@ -38,45 +38,24 @@ import ( "github.com/ZaparooProject/zaparoo-core/pkg/service" ) -const appName = "tapto" - func main() { versionOpt := flag.Bool("version", false, "print version and exit") flag.Parse() if *versionOpt { - fmt.Println("TapTo v" + config.Version + " (mac)") + fmt.Println("Zaparoo Core v" + config.AppVersion + " (mac)") os.Exit(0) } - cfg, err := config.NewUserConfig(&config.UserConfig{ - TapTo: config.TapToConfig{ - ProbeDevice: true, - }, - Api: config.ApiConfig{ - Port: config.DefaultApiPort, - }, - }) - if err != nil { - log.Error().Msgf("error loading user config: %s", err) - fmt.Println("Error loading config:", err) - os.Exit(1) - } - pl := &mac.Platform{} - err = utils.InitLogging(cfg, pl) - if err != nil { - fmt.Println("Error initializing logging:", err) - os.Exit(1) - } - if cfg.GetDebug() { - zerolog.SetGlobalLevel(zerolog.DebugLevel) - } else { - zerolog.SetGlobalLevel(zerolog.InfoLevel) - } + cfg := cli.Setup( + pl, + config.BaseDefaults, + []io.Writer{zerolog.ConsoleWriter{Out: os.Stderr}}, + ) - fmt.Println("TapTo v" + config.Version) + fmt.Println("Zaparoo v" + config.AppVersion) stopSvc, err := service.Start(pl, cfg) if err != nil { diff --git a/cmd/mister/gui.go b/cmd/mister/gui.go index 5f0d05a9..09a35c9f 100644 --- a/cmd/mister/gui.go +++ b/cmd/mister/gui.go @@ -1,26 +1,27 @@ /* -TapTo +Zaparoo Core Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package main import ( + "github.com/ZaparooProject/zaparoo-core/pkg/platforms/mister" "os/exec" "path" "strings" @@ -42,6 +43,19 @@ func tryAddStartup(stdscr *goncurses.Window) error { log.Error().Msgf("failed to load startup file: %s", err) } + // migration from tapto name + if startup.Exists("mrext/tapto") { + err = startup.Remove("mrext/tapto") + if err != nil { + return err + } + + err = startup.Save() + if err != nil { + return err + } + } + if !startup.Exists("mrext/" + config.AppName) { win, err := curses.NewWindow(stdscr, 6, 43, "", -1) if err != nil { @@ -58,7 +72,7 @@ func tryAddStartup(stdscr *goncurses.Window) error { selected := 0 for { - win.MovePrint(1, 3, "Add TapTo service to MiSTer startup?") + win.MovePrint(1, 3, "Add Zaparoo service to MiSTer startup?") win.MovePrint(2, 2, "This won't impact MiSTer's performance.") curses.DrawActionButtons(win, []string{"Yes", "No"}, selected, 10) @@ -119,8 +133,8 @@ func copyLogToSd(pl platforms.Platform, stdscr *goncurses.Window) error { } }(win) - logPath := path.Join(pl.LogFolder(), config.LogFilename) - newPath := path.Join("/media/fat", config.LogFilename) + logPath := path.Join(pl.LogDir(), config.LogFile) + newPath := path.Join(mister.DataDir, config.LogFile) err = utils.CopyFile(logPath, newPath) printCenter := func(y int, text string) { @@ -131,7 +145,7 @@ func copyLogToSd(pl platforms.Platform, stdscr *goncurses.Window) error { printCenter(1, "Unable to copy log file to SD card.") log.Error().Err(err).Msgf("error copying log file") } else { - printCenter(1, "Copied tapto.log to root of SD card.") + printCenter(1, "Copied "+config.LogFile+" to SD card.") } win.NoutRefresh() @@ -160,7 +174,7 @@ func uploadLog(pl platforms.Platform, stdscr *goncurses.Window) error { } }(win) - logPath := path.Join(pl.LogFolder(), config.LogFilename) + logPath := path.Join(pl.LogDir(), config.LogFile) printCenter := func(y int, text string) { win.MovePrint(y, (width-len(text))/2, text) @@ -307,7 +321,7 @@ func exportLog(pl platforms.Platform, stdscr *goncurses.Window) error { return nil } -func displayServiceInfo(pl platforms.Platform, cfg *config.UserConfig, stdscr *goncurses.Window, service *utils.Service) error { +func displayServiceInfo(pl platforms.Platform, cfg *config.Instance, stdscr *goncurses.Window, service *utils.Service) error { width := 50 height := 8 @@ -348,10 +362,10 @@ func displayServiceInfo(pl platforms.Platform, cfg *config.UserConfig, stdscr *g statusText = "Service: NOT RUNNING" } - printCenter(0, "TapTo v"+config.Version+" ("+pl.Id()+")") + printCenter(0, "Zaparoo Core v"+config.AppVersion+" ("+pl.Id()+")") clearLine(1) - printCenter(1, "Visit tapto.wiki for guides and help!") + printCenter(1, "Visit zaparoo.org for guides and help!") win.HLine(2, 1, goncurses.ACS_HLINE, width-2) win.MoveAddChar(2, 0, goncurses.ACS_LTEE) @@ -366,9 +380,6 @@ func displayServiceInfo(pl platforms.Platform, cfg *config.UserConfig, stdscr *g ipDisplay = "Unknown" } else { ipDisplay = ip.String() - if cfg.Api.Port != config.DefaultApiPort { - ipDisplay += ":" + cfg.Api.Port - } } clearLine(4) diff --git a/cmd/mister/main.go b/cmd/mister/main.go index d987a681..39b8345e 100755 --- a/cmd/mister/main.go +++ b/cmd/mister/main.go @@ -1,22 +1,22 @@ /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package main @@ -25,9 +25,11 @@ import ( "flag" "fmt" "github.com/ZaparooProject/zaparoo-core/pkg/cli" + "github.com/ZaparooProject/zaparoo-core/pkg/config/migrate" "github.com/ZaparooProject/zaparoo-core/pkg/utils" "github.com/rs/zerolog/log" "os" + "path/filepath" "github.com/ZaparooProject/zaparoo-core/pkg/platforms/mister" gc "github.com/rthornton128/goncurses" @@ -47,6 +49,19 @@ func addToStartup() error { return err } + // migration from tapto name + if startup.Exists("mrext/tapto") { + err = startup.Remove("mrext/tapto") + if err != nil { + return err + } + + err = startup.Save() + if err != nil { + return err + } + } + if !startup.Exists("mrext/" + config.AppName) { err = startup.AddService("mrext/" + config.AppName) if err != nil { @@ -67,12 +82,12 @@ func main() { serviceFlag := flag.String( "service", "", - "manage TapTo service (start|stop|restart|status)", + "manage Zaparoo service (start|stop|restart|status)", ) addStartupFlag := flag.Bool( "add-startup", false, - "add TapTo service to MiSTer startup if not already added", + "add Zaparoo service to MiSTer startup if not already added", ) pl := &mister.Platform{} @@ -87,14 +102,19 @@ func main() { os.Exit(0) } - cfg := cli.Setup(pl, &config.UserConfig{ - TapTo: config.TapToConfig{ - ProbeDevice: true, - }, - Api: config.ApiConfig{ - Port: config.DefaultApiPort, - }, - }) + defaults := config.BaseDefaults + iniPath := "/media/fat/Scripts/tapto.ini" + if migrate.Required(iniPath, filepath.Join(pl.ConfigDir(), config.CfgFile)) { + migrated, err := migrate.IniToToml(iniPath) + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "Error migrating config: %v\n", err) + os.Exit(1) + } else { + defaults = migrated + } + } + + cfg := cli.Setup(pl, defaults, nil) svc, err := utils.NewService(utils.ServiceArgs{ Entry: func() (func() error, error) { diff --git a/cmd/mistex/main.go b/cmd/mistex/main.go index b912ff24..41df72bc 100755 --- a/cmd/mistex/main.go +++ b/cmd/mistex/main.go @@ -1,24 +1,24 @@ ///go:build linux && cgo /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package main @@ -27,10 +27,13 @@ import ( "flag" "fmt" "github.com/ZaparooProject/zaparoo-core/pkg/cli" + "github.com/ZaparooProject/zaparoo-core/pkg/config/migrate" "github.com/ZaparooProject/zaparoo-core/pkg/platforms/mistex" "github.com/ZaparooProject/zaparoo-core/pkg/utils" + "io" "os" "os/exec" + "path/filepath" "github.com/rs/zerolog/log" @@ -39,14 +42,14 @@ import ( ) func tryAddToStartup() (bool, error) { - unitPath := "/etc/systemd/system/tapto.service" + unitPath := "/etc/systemd/system/zaparoo.service" unitFile := `[Unit] -Description=TapTo service +Description=Zaparoo Core service [Service] Type=forking Restart=no -ExecStart=/media/fat/Scripts/tapto.sh -service start +ExecStart=/media/fat/Scripts/zaparoo.sh -service start [Install] WantedBy=multi-user.target @@ -68,7 +71,7 @@ WantedBy=multi-user.target return false, err } - cmd = exec.Command("systemctl", "enable", "tapto.service") + cmd = exec.Command("systemctl", "enable", "zaparoo.service") err = cmd.Run() if err != nil { return false, err @@ -82,12 +85,12 @@ func main() { serviceFlag := flag.String( "service", "", - "manage TapTo service (start|stop|restart|status)", + "manage Zaparoo service (start|stop|restart|status)", ) addStartupFlag := flag.Bool( "add-startup", false, - "add TapTo service to MiSTer startup if not already added", + "add Zaparoo service to MiSTer startup if not already added", ) pl := &mistex.Platform{} @@ -102,14 +105,23 @@ func main() { os.Exit(0) } - cfg := cli.Setup(pl, &config.UserConfig{ - TapTo: config.TapToConfig{ - ProbeDevice: true, - }, - Api: config.ApiConfig{ - Port: config.DefaultApiPort, - }, - }) + defaults := config.BaseDefaults + iniPath := "/media/fat/Scripts/tapto.ini" + if migrate.Required(iniPath, filepath.Join(pl.ConfigDir(), config.CfgFile)) { + migrated, err := migrate.IniToToml(iniPath) + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "Error migrating config: %v\n", err) + os.Exit(1) + } else { + defaults = migrated + } + } + + cfg := cli.Setup( + pl, + defaults, + []io.Writer{os.Stderr}, + ) svc, err := utils.NewService(utils.ServiceArgs{ Entry: func() (func() error, error) { @@ -126,7 +138,7 @@ func main() { flags.Post(cfg) - fmt.Println("TapTo v" + config.Version) + fmt.Println("Zaparoo v" + config.AppVersion) added, err := tryAddToStartup() if err != nil { @@ -135,21 +147,21 @@ func main() { os.Exit(1) } else if added { log.Info().Msg("added to startup") - fmt.Println("Added TapTo to MiSTeX startup.") + fmt.Println("Added Zaparoo to MiSTeX startup.") } if !svc.Running() { err := svc.Start() - fmt.Println("TapTo service not running, starting...") + fmt.Println("Zaparoo service not running, starting...") if err != nil { log.Error().Msgf("error starting service: %s", err) - fmt.Println("Error starting TapTo service:", err) + fmt.Println("Error starting Zaparoo service:", err) } else { log.Info().Msg("service started manually") - fmt.Println("TapTo service started.") + fmt.Println("Zaparoo service started.") } } else { - fmt.Println("TapTo service is running.") + fmt.Println("Zaparoo service is running.") } ip, err := utils.GetLocalIp() diff --git a/cmd/steamos/main.go b/cmd/steamos/main.go index 87a4e349..9b15be9c 100755 --- a/cmd/steamos/main.go +++ b/cmd/steamos/main.go @@ -26,10 +26,13 @@ import ( "fmt" "github.com/ZaparooProject/zaparoo-core/pkg/cli" "github.com/ZaparooProject/zaparoo-core/pkg/config" + "github.com/ZaparooProject/zaparoo-core/pkg/config/migrate" "github.com/ZaparooProject/zaparoo-core/pkg/platforms/steamos" "github.com/ZaparooProject/zaparoo-core/pkg/service" + "github.com/ZaparooProject/zaparoo-core/pkg/utils" "github.com/adrg/xdg" "github.com/rs/zerolog/log" + "io" "os" "os/signal" "path/filepath" @@ -89,15 +92,23 @@ func main() { os.Exit(1) } - cfg := cli.Setup(pl, &config.UserConfig{ - TapTo: config.TapToConfig{ - ProbeDevice: true, - ConsoleLogging: true, - }, - Api: config.ApiConfig{ - Port: config.DefaultApiPort, - }, - }) + defaults := config.BaseDefaults + iniPath := filepath.Join(utils.ExeDir(), "tapto.ini") + if migrate.Required(iniPath, filepath.Join(pl.ConfigDir(), config.CfgFile)) { + migrated, err := migrate.IniToToml(iniPath) + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "Error migrating config: %v\n", err) + os.Exit(1) + } else { + defaults = migrated + } + } + + cfg := cli.Setup( + pl, + defaults, + []io.Writer{os.Stderr}, + ) flags.Post(cfg) diff --git a/cmd/windows/main.go b/cmd/windows/main.go index 1911bc8d..6817f7e3 100755 --- a/cmd/windows/main.go +++ b/cmd/windows/main.go @@ -1,24 +1,22 @@ -//go:build windows - /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package main @@ -26,9 +24,13 @@ package main import ( "flag" "fmt" + "github.com/ZaparooProject/zaparoo-core/pkg/cli" + "github.com/ZaparooProject/zaparoo-core/pkg/config/migrate" + "github.com/rs/zerolog" + "io" "os" + "path/filepath" - "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/ZaparooProject/zaparoo-core/pkg/platforms/windows" @@ -43,38 +45,30 @@ func main() { flag.Parse() if *versionOpt { - fmt.Println("TapTo v" + config.Version + " (windows)") + fmt.Println("Zaparoo Core v" + config.AppVersion + " (windows)") os.Exit(0) } - cfg, err := config.NewUserConfig(&config.UserConfig{ - TapTo: config.TapToConfig{ - ProbeDevice: true, - ConsoleLogging: true, - }, - Api: config.ApiConfig{ - Port: config.DefaultApiPort, - }, - }) - if err != nil { - fmt.Println("Error loading config:", err) - os.Exit(1) - } - pl := &windows.Platform{} - err = utils.InitLogging(cfg, pl) - if err != nil { - fmt.Println("Error initializing logging:", err) - os.Exit(1) - } - if cfg.GetDebug() { - zerolog.SetGlobalLevel(zerolog.DebugLevel) - } else { - zerolog.SetGlobalLevel(zerolog.InfoLevel) + defaults := config.BaseDefaults + iniPath := filepath.Join(utils.ExeDir(), "tapto.ini") + if migrate.Required(iniPath, filepath.Join(pl.ConfigDir(), config.CfgFile)) { + migrated, err := migrate.IniToToml(iniPath) + if err != nil { + log.Warn().Err(err).Msg("error migrating ini to toml") + } else { + defaults = migrated + } } - fmt.Println("TapTo v" + config.Version) + cfg := cli.Setup( + pl, + defaults, + []io.Writer{zerolog.ConsoleWriter{Out: os.Stderr}}, + ) + + fmt.Println("Zaparoo v" + config.AppVersion) stopSvc, err := service.Start(pl, cfg) if err != nil { diff --git a/docs/developers.md b/docs/developers.md index 88feeb23..1d2bfb39 100644 --- a/docs/developers.md +++ b/docs/developers.md @@ -46,7 +46,7 @@ These are the important commands: - `task build-mister` - Builds a MiSTer binary of TapTo and copies TapTUI to the build directory. + Builds a MiSTer binary of Zaparoo and copies TapTUI to the build directory. - `task deploy-mister` diff --git a/go.mod b/go.mod index 01e1da3b..e4fb1f68 100755 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/ZaparooProject/zaparoo-core -go 1.19 +go 1.21.0 + +toolchain go1.23.4 require github.com/rthornton128/goncurses v0.0.0-20220628231859-fd57939296e5 @@ -44,6 +46,7 @@ require ( github.com/hsanjuan/go-ndef v0.0.1 github.com/mdp/qrterminal/v3 v3.2.0 github.com/olahol/melody v1.2.1 + github.com/pelletier/go-toml/v2 v2.2.3 github.com/rs/zerolog v1.31.0 github.com/wizzomafizzo/mrext v0.0.0-20240804073054-39dcc9bccc81 go.bug.st/serial v1.6.2 diff --git a/go.sum b/go.sum index cd581498..f7c9357b 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78= github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ= github.com/andygrunwald/vdf v1.1.0 h1:gmstp0R7DOepIZvWoSJY97ix7QOrsxpGPU6KusKXqvw= @@ -47,6 +48,8 @@ github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/olahol/melody v1.2.1 h1:xdwRkzHxf+B0w4TKbGpUSSkV516ZucQZJIWLztOWICQ= github.com/olahol/melody v1.2.1/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -60,6 +63,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 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/txn2/txeh v1.4.0 h1:0tdvpA4HGJrj8X3kmrU6o/JFStI009nKxwDpMK5CnRU= github.com/txn2/txeh v1.4.0/go.mod h1:Mgq0hY184zCrDBLgvkIp+9NYGHoYbJcu4xKqUcx1shc= github.com/wizzomafizzo/mrext v0.0.0-20240804073054-39dcc9bccc81 h1:j9tZjWiwt0JeKHYIxbJ9a+25K7v+bks696i4Cx5Thbk= @@ -105,6 +109,7 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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/api/client/client.go b/pkg/api/client/client.go index a4096939..b564d5dd 100644 --- a/pkg/api/client/client.go +++ b/pkg/api/client/client.go @@ -10,6 +10,7 @@ import ( "github.com/gorilla/websocket" "github.com/rs/zerolog/log" "net/url" + "strconv" "time" ) @@ -21,14 +22,14 @@ var ( // LocalClient sends a single unauthenticated method with params to the local // running API service, waits for a response until timeout then disconnects. func LocalClient( - cfg *config.UserConfig, + cfg *config.Instance, method string, params string, ) (string, error) { u := url.URL{ Scheme: "ws", - Host: "localhost:" + cfg.Api.Port, - Path: "/", + Host: "localhost:" + strconv.Itoa(cfg.ApiPort()), + Path: "/api/v1.0", } id, err := uuid.NewUUID() diff --git a/pkg/api/methods/games.go b/pkg/api/methods/games.go index e0e39c2d..69f71625 100644 --- a/pkg/api/methods/games.go +++ b/pkg/api/methods/games.go @@ -5,10 +5,10 @@ import ( "errors" "github.com/ZaparooProject/zaparoo-core/pkg/api/models" "github.com/ZaparooProject/zaparoo-core/pkg/api/models/requests" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "sync" "github.com/ZaparooProject/zaparoo-core/pkg/assets" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/database/gamesdb" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" "github.com/rs/zerolog/log" @@ -31,7 +31,7 @@ func (s *Index) Exists(platform platforms.Platform) bool { func (s *Index) GenerateIndex( pl platforms.Platform, - cfg *config.UserConfig, + cfg *config.Instance, ns chan<- models.Notification, systems []gamesdb.System, ) { diff --git a/pkg/api/methods/settings.go b/pkg/api/methods/settings.go index 3fbd5aab..d2563b85 100644 --- a/pkg/api/methods/settings.go +++ b/pkg/api/methods/settings.go @@ -4,6 +4,7 @@ import ( "encoding/json" "github.com/ZaparooProject/zaparoo-core/pkg/api/models" "github.com/ZaparooProject/zaparoo-core/pkg/api/models/requests" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/rs/zerolog/log" ) @@ -11,22 +12,21 @@ func HandleSettings(env requests.RequestEnv) (any, error) { log.Info().Msg("received settings request") resp := models.SettingsResponse{ - // TODO: this is very out of date - ConnectionString: env.Config.GetConnectionString(), - AllowCommands: env.Config.GetAllowCommands(), - DisableSounds: env.Config.GetDisableSounds(), - ProbeDevice: env.Config.GetProbeDevice(), - ExitGame: env.Config.GetExitGame(), - ExitGameDelay: env.Config.GetExitGameDelay(), - ExitGameBlocklist: make([]string, 0), - Debug: env.Config.GetDebug(), - Launching: !env.State.IsLauncherDisabled(), + LaunchingActive: !env.State.IsLauncherDisabled(), + DebugLogging: env.Config.DebugLogging(), + AudioScanFeedback: env.Config.AudioFeedback(), + ReadersAutoDetect: env.Config.Readers().AutoDetect, + ReadersScanMode: env.Config.ReadersScan().Mode, + ReadersScanExitDelay: env.Config.ReadersScan().ExitDelay, + ReadersScanIgnoreSystem: make([]string, 0), } - resp.ExitGameBlocklist = append( - resp.ExitGameBlocklist, - env.Config.GetExitGameBlocklist()..., - ) + for _, s := range env.Config.ReadersScan().IgnoreSystem { + resp.ReadersScanIgnoreSystem = append( + resp.ReadersScanIgnoreSystem, + s, + ) + } return resp, nil } @@ -44,58 +44,50 @@ func HandleSettingsUpdate(env requests.RequestEnv) (any, error) { return nil, ErrInvalidParams } - if params.ConnectionString != nil { - log.Info().Str("connectionString", *params.ConnectionString).Msg("updating connection string") - env.Config.SetConnectionString(*params.ConnectionString) - } - - if params.AllowCommands != nil { - if !env.IsLocal { - return nil, ErrNotAllowed + if params.LaunchingActive != nil { + log.Info().Bool("launchingActive", *params.LaunchingActive).Msg("update") + if *params.LaunchingActive { + env.State.EnableLauncher() } else { - log.Info().Bool("allowCommands", *params.AllowCommands).Msg("updating allow commands") - env.Config.SetAllowCommands(*params.AllowCommands) + env.State.DisableLauncher() } } - if params.DisableSounds != nil { - log.Info().Bool("disableSounds", *params.DisableSounds).Msg("updating disable sounds") - env.Config.SetDisableSounds(*params.DisableSounds) - } - - if params.ProbeDevice != nil { - log.Info().Bool("probeDevice", *params.ProbeDevice).Msg("updating probe device") - env.Config.SetProbeDevice(*params.ProbeDevice) + if params.DebugLogging != nil { + log.Info().Bool("debugLogging", *params.DebugLogging).Msg("update") + env.Config.SetDebugLogging(*params.DebugLogging) } - if params.ExitGameDelay != nil { - log.Info().Int("exitGameDelay", *params.ExitGameDelay).Msg("updating exit game delay") - env.Config.SetExitGameDelay(*params.ExitGameDelay) + if params.AudioScanFeedback != nil { + log.Info().Bool("audioScanFeedback", *params.AudioScanFeedback).Msg("update") + env.Config.SetAudioFeedback(*params.AudioScanFeedback) } - if params.ExitGame != nil { - log.Info().Bool("exitGame", *params.ExitGame).Msg("updating exit game") - env.Config.SetExitGame(*params.ExitGame) + if params.ReadersAutoDetect != nil { + log.Info().Bool("readersAutoDetect", *params.ReadersAutoDetect).Msg("update") + env.Config.SetAutoConnect(*params.ReadersAutoDetect) } - if params.ExitGameBlocklist != nil { - log.Info().Strs("exitGameBlocklist", *params.ExitGameBlocklist).Msg("updating exit game blocklist") - env.Config.SetExitGameBlocklist(*params.ExitGameBlocklist) + if params.ReadersScanMode != nil { + log.Info().Str("readersScanMode", *params.ReadersScanMode).Msg("update") + if *params.ReadersScanMode == "" { + env.Config.SetScanMode(config.ScanModeTap) + } else if *params.ReadersScanMode == config.ScanModeTap || *params.ReadersScanMode == config.ScanModeHold { + env.Config.SetScanMode(*params.ReadersScanMode) + } else { + return nil, ErrInvalidParams + } } - if params.Debug != nil { - log.Info().Bool("debug", *params.Debug).Msg("updating debug") - env.Config.SetDebug(*params.Debug) + if params.ReadersScanExitDelay != nil { + log.Info().Float32("readersScanExitDelay", *params.ReadersScanExitDelay).Msg("update") + env.Config.SetScanExitDelay(*params.ReadersScanExitDelay) } - if params.Launching != nil { - log.Info().Bool("launching", *params.Launching).Msg("updating launching") - if *params.Launching { - env.State.EnableLauncher() - } else { - env.State.DisableLauncher() - } + if params.ReadersScanIgnoreSystem != nil { + log.Info().Strs("readsScanIgnoreSystem", *params.ReadersScanIgnoreSystem).Msg("update") + env.Config.SetScanIgnoreSystem(*params.ReadersScanIgnoreSystem) } - return nil, env.Config.SaveConfig() + return nil, env.Config.Save() } diff --git a/pkg/api/methods/status.go b/pkg/api/methods/status.go index f5ae1c45..c19cd30a 100644 --- a/pkg/api/methods/status.go +++ b/pkg/api/methods/status.go @@ -11,7 +11,7 @@ import ( func newStatus( pl platforms.Platform, - cfg *config.UserConfig, + cfg *config.Instance, st *state.State, ) models.StatusResponse { active := st.GetActiveCard() @@ -91,7 +91,7 @@ func HandleStatus(env requests.RequestEnv) (any, error) { func HandleVersion(env requests.RequestEnv) (any, error) { log.Info().Msg("received version request") return models.VersionResponse{ - Version: config.Version, + Version: config.AppVersion, Platform: env.Platform.Id(), }, nil } diff --git a/pkg/api/models/params.go b/pkg/api/models/params.go index 52486985..527c0e77 100644 --- a/pkg/api/models/params.go +++ b/pkg/api/models/params.go @@ -45,15 +45,13 @@ type ReaderWriteParams struct { } type UpdateSettingsParams struct { - ConnectionString *string `json:"connectionString"` - AllowCommands *bool `json:"allowCommands"` - DisableSounds *bool `json:"disableSounds"` - ProbeDevice *bool `json:"probeDevice"` - ExitGame *bool `json:"exitGame"` - ExitGameDelay *int `json:"exitGameDelay"` - ExitGameBlocklist *[]string `json:"exitGameBlocklist"` - Debug *bool `json:"debug"` - Launching *bool `json:"launching"` + LaunchingActive *bool `json:"launchingActive"` + DebugLogging *bool `json:"debugLogging"` + AudioScanFeedback *bool `json:"audioScanFeedback"` + ReadersAutoDetect *bool `json:"readersAutoDetect"` + ReadersScanMode *string `json:"readersScanMode"` + ReadersScanExitDelay *float32 `json:"readersScanExitDelay"` + ReadersScanIgnoreSystem *[]string `json:"readersScanIgnoreSystems"` } type NewClientParams struct { diff --git a/pkg/api/models/requests/requests.go b/pkg/api/models/requests/requests.go index 46eb54de..0ce2d914 100644 --- a/pkg/api/models/requests/requests.go +++ b/pkg/api/models/requests/requests.go @@ -11,7 +11,7 @@ import ( type RequestEnv struct { Platform platforms.Platform - Config *config.UserConfig + Config *config.Instance State *state.State Database *database.Database TokenQueue chan<- tokens.Token diff --git a/pkg/api/models/responses.go b/pkg/api/models/responses.go index 14fcdaed..b017689d 100644 --- a/pkg/api/models/responses.go +++ b/pkg/api/models/responses.go @@ -25,15 +25,13 @@ type IndexStatusResponse struct { } type SettingsResponse struct { - ConnectionString string `json:"connectionString"` - AllowCommands bool `json:"allowCommands"` - DisableSounds bool `json:"disableSounds"` - ProbeDevice bool `json:"probeDevice"` - ExitGame bool `json:"exitGame"` - ExitGameDelay int `json:"exitGameDelay"` - ExitGameBlocklist []string `json:"exitGameBlocklist"` - Debug bool `json:"debug"` - Launching bool `json:"launching"` + LaunchingActive bool `json:"launchingActive"` + DebugLogging bool `json:"debugLogging"` + AudioScanFeedback bool `json:"audioScanFeedback"` + ReadersAutoDetect bool `json:"readersAutoDetect"` + ReadersScanMode string `json:"readersScanMode"` + ReadersScanExitDelay float32 `json:"readersScanExitDelay"` + ReadersScanIgnoreSystem []string `json:"readersScanIgnoreSystems"` } type System struct { diff --git a/pkg/api/server.go b/pkg/api/server.go index 3f7d0f95..407e0894 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -7,13 +7,14 @@ import ( "github.com/ZaparooProject/zaparoo-core/pkg/api/methods" "github.com/ZaparooProject/zaparoo-core/pkg/api/models" "github.com/ZaparooProject/zaparoo-core/pkg/api/models/requests" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "net" "net/http" + "strconv" "strings" "time" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/database" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" "github.com/ZaparooProject/zaparoo-core/pkg/service/state" @@ -130,7 +131,7 @@ func handleResponse(resp models.ResponseObject) error { func Start( pl platforms.Platform, - cfg *config.UserConfig, + cfg *config.Instance, st *state.State, itq chan<- tokens.Token, db *database.Database, @@ -180,10 +181,24 @@ func Start( } }(ns) - r.Get("/", func(w http.ResponseWriter, r *http.Request) { + r.Get("/api", func(w http.ResponseWriter, r *http.Request) { + err := m.HandleRequest(w, r) + if err != nil { + log.Error().Err(err).Msg("handling websocket request: latest") + } + }) + + r.Get("/api/v1", func(w http.ResponseWriter, r *http.Request) { + err := m.HandleRequest(w, r) + if err != nil { + log.Error().Err(err).Msg("handling websocket request: v1") + } + }) + + r.Get("/api/v1.0", func(w http.ResponseWriter, r *http.Request) { err := m.HandleRequest(w, r) if err != nil { - log.Error().Err(err).Msg("handling websocket request") + log.Error().Err(err).Msg("handling websocket request: v1.0") } }) @@ -264,7 +279,7 @@ func Start( // TODO: use allow list r.Get("/l/*", methods.HandleLaunchBasic(st, itq)) - err := http.ListenAndServe(":"+cfg.Api.Port, r) + err := http.ListenAndServe(":"+strconv.Itoa(cfg.ApiPort()), r) if err != nil { log.Error().Err(err).Msg("error starting http server") } diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index cedfb5f8..467647eb 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -11,7 +11,9 @@ import ( "github.com/ZaparooProject/zaparoo-core/pkg/utils" "github.com/google/uuid" "github.com/mdp/qrterminal/v3" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" + "io" "os" "strings" ) @@ -79,7 +81,7 @@ func (f *Flags) Pre(pl platforms.Platform) { flag.Parse() if *f.Version { - fmt.Printf("Zaparoo v%s (%s)\n", config.Version, pl.Id()) + fmt.Printf("Zaparoo v%s (%s)\n", config.AppVersion, pl.Id()) os.Exit(0) } } @@ -92,7 +94,7 @@ type ConnQr struct { // Post actions all remaining common flags that require the environment to be // set up. Logging is allowed. -func (f *Flags) Post(cfg *config.UserConfig) { +func (f *Flags) Post(cfg *config.Instance) { if *f.Write != "" { data, err := json.Marshal(&models.ReaderWriteParams{ Text: *f.Write, @@ -283,18 +285,24 @@ func (f *Flags) Post(cfg *config.UserConfig) { } // Setup initializes the user config and logging. Returns a user config object. -func Setup(pl platforms.Platform, defaultConfig *config.UserConfig) *config.UserConfig { - cfg, err := config.NewUserConfig(defaultConfig) +func Setup(pl platforms.Platform, defaultConfig config.Values, writers []io.Writer) *config.Instance { + err := utils.InitLogging(pl, writers) if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Error loading config: %v\n", err) + _, _ = fmt.Fprintf(os.Stderr, "Error initializing logging: %v\n", err) os.Exit(1) } - err = utils.InitLogging(cfg, pl) + cfg, err := config.NewConfig(pl.ConfigDir(), defaultConfig) if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Error initializing logging: %v\n", err) + _, _ = fmt.Fprintf(os.Stderr, "Error loading config: %v\n", err) os.Exit(1) } + if cfg.DebugLogging() { + zerolog.SetGlobalLevel(zerolog.DebugLevel) + } else { + zerolog.SetGlobalLevel(zerolog.InfoLevel) + } + return cfg } diff --git a/pkg/config/app.go b/pkg/config/app.go new file mode 100644 index 00000000..93a8d390 --- /dev/null +++ b/pkg/config/app.go @@ -0,0 +1,26 @@ +package config + +import ( + "github.com/rs/zerolog/log" + "os" + "path/filepath" +) + +const ( + AppVersion = "2.1.0" + AppName = "zaparoo" + GamesDbFile = "games.db" + TapToDbFile = "tapto.db" + LogFile = "core.log" + PidFile = "core.pid" + CfgFile = "config.toml" +) + +func MkTempDir() string { + path := filepath.Join(os.TempDir(), AppName) + err := os.MkdirAll(path, 0755) + if err != nil { + log.Error().Err(err).Msg("error creating temp folder") + } + return path +} diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 00000000..15c4d68e --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,348 @@ +package config + +import ( + "errors" + "github.com/google/uuid" + "github.com/pelletier/go-toml/v2" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "os" + "path/filepath" + "runtime" + "strings" + "sync" +) + +const ( + SchemaVersion = 1 + CfgEnv = "ZAPAROO_CFG" + AppEnv = "ZAPAROO_APP" + ScanModeTap = "tap" + ScanModeHold = "hold" +) + +type Values struct { + ConfigSchema int `toml:"config_schema"` + DebugLogging bool `toml:"debug_logging"` + Audio Audio `toml:"audio,omitempty"` + Readers Readers `toml:"readers,omitempty"` + Systems Systems `toml:"systems,omitempty"` + Launchers Launchers `toml:"launchers,omitempty"` + ZapScript ZapScript `toml:"zapscript,omitempty"` + Service Service `toml:"service,omitempty"` +} + +type Audio struct { + ScanFeedback bool `toml:"scan_feedback,omitempty"` +} + +type Readers struct { + AutoDetect bool `toml:"auto_detect"` + Scan ReadersScan `toml:"scan,omitempty"` + Connect []ReadersConnect `toml:"connect,omitempty"` +} + +type ReadersScan struct { + Mode string `toml:"mode"` + ExitDelay float32 `toml:"exit_delay,omitempty"` + IgnoreSystem []string `toml:"ignore_system,omitempty"` +} + +type ReadersConnect struct { + Driver string `toml:"driver"` + Path string `toml:"path,omitempty"` +} + +type Systems struct { + Default []SystemsDefault `toml:"default,omitempty"` +} + +type SystemsDefault struct { + System string `toml:"system"` + Launcher string `toml:"launcher,omitempty"` +} + +type Launchers struct { + IndexRoot []string `toml:"index_root,omitempty,multiline"` + AllowFile []string `toml:"allow_file,omitempty,multiline"` +} + +type ZapScript struct { + AllowShell []string `toml:"allow_shell,omitempty,multiline"` +} + +type Service struct { + ApiPort int `toml:"api_port"` + DeviceId string `toml:"device_id"` + AllowLaunch []string `toml:"allow_launch,omitempty,multiline"` +} + +var BaseDefaults = Values{ + ConfigSchema: SchemaVersion, + Audio: Audio{ + ScanFeedback: true, + }, + Readers: Readers{ + AutoDetect: true, + Scan: ReadersScan{ + Mode: ScanModeTap, + }, + }, + Service: Service{ + ApiPort: 7497, + }, +} + +type Instance struct { + mu sync.RWMutex + appPath string + cfgPath string + vals Values +} + +func NewConfig(configDir string, defaults Values) (*Instance, error) { + cfgPath := os.Getenv(CfgEnv) + log.Info().Msgf("env config path: %s", cfgPath) + + if cfgPath == "" { + cfgPath = filepath.Join(configDir, CfgFile) + } + + cfg := Instance{ + mu: sync.RWMutex{}, + appPath: os.Getenv(AppEnv), + cfgPath: cfgPath, + vals: defaults, + } + + if _, err := os.Stat(cfgPath); os.IsNotExist(err) { + log.Info().Msg("saving new default config to disk") + + err := os.MkdirAll(filepath.Dir(cfgPath), 0755) + if err != nil { + return nil, err + } + + err = cfg.Save() + if err != nil { + return nil, err + } + } + + err := cfg.Load() + if err != nil { + return nil, err + } + + return &cfg, nil +} + +func (c *Instance) Load() error { + c.mu.Lock() + defer c.mu.Unlock() + + if c.cfgPath == "" { + return errors.New("config path not set") + } + + if _, err := os.Stat(c.cfgPath); err != nil { + return err + } + + data, err := os.ReadFile(c.cfgPath) + if err != nil { + return err + } + + var newVals Values + err = toml.Unmarshal(data, &newVals) + if err != nil { + return err + } + + if newVals.ConfigSchema != SchemaVersion { + log.Error().Msgf( + "schema version mismatch: got %d, expecting %d", + newVals.ConfigSchema, + SchemaVersion, + ) + return errors.New("schema version mismatch") + } + + c.vals = newVals + + log.Info().Any("config", c.vals).Msg("loaded config") + + return nil +} + +func (c *Instance) Save() error { + c.mu.Lock() + defer c.mu.Unlock() + + if c.cfgPath == "" { + return errors.New("config path not set") + } + + // set current schema version + c.vals.ConfigSchema = SchemaVersion + + // generate a device id if one doesn't exist + if c.vals.Service.DeviceId == "" { + newId := uuid.New().String() + c.vals.Service.DeviceId = newId + log.Info().Msgf("generated new device id: %s", newId) + } + + data, err := toml.Marshal(&c.vals) + if err != nil { + return err + } + + return os.WriteFile(c.cfgPath, data, 0644) +} + +func (c *Instance) AudioFeedback() bool { + c.mu.RLock() + defer c.mu.RUnlock() + return c.vals.Audio.ScanFeedback +} + +func (c *Instance) SetAudioFeedback(enabled bool) { + c.mu.Lock() + defer c.mu.Unlock() + c.vals.Audio.ScanFeedback = enabled +} + +func (c *Instance) DebugLogging() bool { + c.mu.RLock() + defer c.mu.RUnlock() + return c.vals.DebugLogging +} + +func (c *Instance) SetDebugLogging(enabled bool) { + c.mu.Lock() + defer c.mu.Unlock() + c.vals.DebugLogging = enabled + if enabled { + zerolog.SetGlobalLevel(zerolog.DebugLevel) + } else { + zerolog.SetGlobalLevel(zerolog.InfoLevel) + } +} + +func (c *Instance) ReadersScan() ReadersScan { + c.mu.RLock() + defer c.mu.RUnlock() + return c.vals.Readers.Scan +} + +func (c *Instance) TapModeEnabled() bool { + c.mu.RLock() + defer c.mu.RUnlock() + if c.vals.Readers.Scan.Mode == ScanModeTap { + return true + } else if c.vals.Readers.Scan.Mode == "" { + return true + } else { + return false + } +} + +func (c *Instance) HoldModeEnabled() bool { + c.mu.RLock() + defer c.mu.RUnlock() + return c.vals.Readers.Scan.Mode == ScanModeHold +} + +func (c *Instance) SetScanMode(mode string) { + c.mu.Lock() + defer c.mu.Unlock() + c.vals.Readers.Scan.Mode = mode +} + +func (c *Instance) SetScanExitDelay(exitDelay float32) { + c.mu.Lock() + defer c.mu.Unlock() + c.vals.Readers.Scan.ExitDelay = exitDelay +} + +func (c *Instance) SetScanIgnoreSystem(ignoreSystem []string) { + c.mu.Lock() + defer c.mu.Unlock() + c.vals.Readers.Scan.IgnoreSystem = ignoreSystem +} + +func (c *Instance) Readers() Readers { + c.mu.RLock() + defer c.mu.RUnlock() + return c.vals.Readers +} + +func (c *Instance) SetAutoConnect(enabled bool) { + c.mu.Lock() + defer c.mu.Unlock() + c.vals.Readers.AutoDetect = enabled +} + +func (c *Instance) SetReaderConnections(rcs []ReadersConnect) { + c.mu.Lock() + defer c.mu.Unlock() + c.vals.Readers.Connect = rcs +} + +func (c *Instance) SystemDefaults() []SystemsDefault { + c.mu.RLock() + defer c.mu.RUnlock() + return c.vals.Systems.Default +} + +func (c *Instance) IndexRoots() []string { + c.mu.RLock() + defer c.mu.RUnlock() + return c.vals.Launchers.IndexRoot +} + +func (c *Instance) IsLauncherFileAllowed(path string) bool { + c.mu.RLock() + defer c.mu.RUnlock() + for _, allowed := range c.vals.Launchers.AllowFile { + if allowed == "*" { + return true + } + + // TODO: case insensitive on mister? platform option? + if runtime.GOOS == "windows" { + // do a case-insensitive comparison on windows + allowed = strings.ToLower(allowed) + path = strings.ToLower(path) + } + + // convert all slashes to OS preferred + if filepath.FromSlash(allowed) == filepath.FromSlash(path) { + return true + } + } + return false +} + +func (c *Instance) ApiPort() int { + c.mu.RLock() + defer c.mu.RUnlock() + return c.vals.Service.ApiPort +} + +func (c *Instance) IsShellCmdAllowed(cmd string) bool { + c.mu.RLock() + defer c.mu.RUnlock() + for _, allowed := range c.vals.ZapScript.AllowShell { + if allowed == "*" { + return true + } + + if allowed == cmd { + return true + } + } + return false +} diff --git a/pkg/config/user.go b/pkg/config/migrate/iniconfig/user.go similarity index 94% rename from pkg/config/user.go rename to pkg/config/migrate/iniconfig/user.go index efdd842b..01d0af1e 100644 --- a/pkg/config/user.go +++ b/pkg/config/migrate/iniconfig/user.go @@ -1,27 +1,28 @@ /* -TapTo +Zaparoo Core Copyright (C) 2023, 2024 Callan Barrett Copyright (C) 2023 Gareth Jones -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ -package config +package iniconfig import ( + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/rs/zerolog/log" "os" "path/filepath" @@ -259,7 +260,7 @@ func NewUserConfig(defaultConfig *UserConfig) (*UserConfig, error) { } if iniPath == "" { - iniPath = filepath.Join(filepath.Dir(exePath), AppName+".ini") + iniPath = filepath.Join(filepath.Dir(exePath), config.AppName+".ini") } defaultConfig.AppPath = exePath diff --git a/pkg/config/migrate/migrate.go b/pkg/config/migrate/migrate.go new file mode 100644 index 00000000..e58ca89a --- /dev/null +++ b/pkg/config/migrate/migrate.go @@ -0,0 +1,130 @@ +package migrate + +import ( + "github.com/ZaparooProject/zaparoo-core/pkg/config" + "github.com/ZaparooProject/zaparoo-core/pkg/config/migrate/iniconfig" + "gopkg.in/ini.v1" + "os" + "strconv" + "strings" +) + +func IniToToml(iniPath string) (config.Values, error) { + // allow_commands is being purposely ignored and must be explicitly enabled + // by the user after migration + + vals := config.BaseDefaults + var iniVals iniconfig.UserConfig + + iniCfg, err := ini.ShadowLoad(iniPath) + if err != nil { + return vals, err + } + + err = iniCfg.StrictMapTo(&iniVals) + if err != nil { + return vals, err + } + + // readers + for _, r := range iniVals.TapTo.Reader { + ps := strings.SplitN(r, ":", 2) + if len(ps) != 2 { + continue + } + + vals.Readers.Connect = append( + vals.Readers.Connect, + config.ReadersConnect{ + Driver: ps[0], + Path: ps[1], + }, + ) + } + + // connection string + conStr := iniVals.TapTo.ConnectionString + if conStr != "" { + ps := strings.SplitN(conStr, ":", 2) + if len(ps) != 2 { + vals.Readers.Connect = append( + vals.Readers.Connect, + config.ReadersConnect{ + Driver: ps[0], + Path: ps[1], + }, + ) + } + } + + // disable sounds + vals.Audio.ScanFeedback = !iniVals.TapTo.DisableSounds + + // probe device + vals.Readers.AutoDetect = iniVals.TapTo.ProbeDevice + + // exit game mode + if iniVals.TapTo.ExitGame { + vals.Readers.Scan.Mode = config.ScanModeHold + } else { + vals.Readers.Scan.Mode = config.ScanModeTap + } + + // exit game blocklist + vals.Readers.Scan.IgnoreSystem = iniVals.TapTo.ExitGameBlocklist + + // exit game delay + vals.Readers.Scan.ExitDelay = float32(iniVals.TapTo.ExitGameDelay) + + // debug + vals.DebugLogging = iniVals.TapTo.Debug + + // systems - games folder + vals.Launchers.IndexRoot = iniVals.Systems.GamesFolder + + // systems - set core + for _, v := range iniVals.Systems.SetCore { + ps := strings.SplitN(v, ":", 2) + if len(ps) != 2 { + continue + } + + vals.Systems.Default = append( + vals.Systems.Default, + config.SystemsDefault{ + System: ps[0], + Launcher: ps[1], + }, + ) + } + + // launchers - allow file + vals.Launchers.AllowFile = iniVals.Launchers.AllowFile + + // api - port + port, err := strconv.Atoi(iniVals.Api.Port) + if err == nil { + if port != vals.Service.ApiPort { + vals.Service.ApiPort = port + } + } + + // api - allow launch + vals.Service.AllowLaunch = iniVals.Api.AllowLaunch + + return vals, nil +} + +func Required(oldIni string, newToml string) bool { + iniExists := false + if _, err := os.Stat(oldIni); err == nil { + iniExists = true + } + + tomlExists := false + if _, err := os.Stat(newToml); err == nil { + tomlExists = true + } + + return iniExists && !tomlExists +} diff --git a/pkg/config/tapto.go b/pkg/config/tapto.go deleted file mode 100644 index 8177505d..00000000 --- a/pkg/config/tapto.go +++ /dev/null @@ -1,27 +0,0 @@ -package config - -import ( - "github.com/rs/zerolog/log" - "os" - "path/filepath" -) - -const ( - Version = "2.0.1" - GamesDbFilename = "games.db" - TapToDbFilename = "tapto.db" - DefaultApiPort = "7497" - LogFilename = "tapto.log" - AppName = "tapto" - UserConfigFilename = "tapto.ini" - PidFilename = "tapto.pid" -) - -func TempDir() string { - path := filepath.Join(os.TempDir(), AppName) - err := os.MkdirAll(path, 0755) - if err != nil { - log.Error().Err(err).Msg("error creating temp folder") - } - return path -} diff --git a/pkg/database/database.go b/pkg/database/database.go index db579d8f..ec87bf68 100644 --- a/pkg/database/database.go +++ b/pkg/database/database.go @@ -18,7 +18,7 @@ const ( ) func dbFile(pl platforms.Platform) string { - return filepath.Join(pl.ConfigFolder(), config.TapToDbFilename) + return filepath.Join(pl.DataDir(), config.TapToDbFile) } // Check if the db exists on disk. diff --git a/pkg/database/gamesdb/gamesdb.go b/pkg/database/gamesdb/gamesdb.go index 103ccb14..be317784 100644 --- a/pkg/database/gamesdb/gamesdb.go +++ b/pkg/database/gamesdb/gamesdb.go @@ -31,19 +31,19 @@ func NameKey(systemId string, name string) string { // Exists returns true if the media database exists on disk. func Exists(platform platforms.Platform) bool { - _, err := os.Stat(filepath.Join(platform.ConfigFolder(), config.GamesDbFilename)) + _, err := os.Stat(filepath.Join(platform.DataDir(), config.GamesDbFile)) return err == nil } // Open the gamesdb with the given options. If the database does not exist it // will be created and the buckets will be initialized. func open(platform platforms.Platform, options *bolt.Options) (*bolt.DB, error) { - err := os.MkdirAll(filepath.Dir(filepath.Join(platform.ConfigFolder(), config.GamesDbFilename)), 0755) + err := os.MkdirAll(filepath.Dir(filepath.Join(platform.DataDir(), config.GamesDbFile)), 0755) if err != nil { return nil, err } - db, err := bolt.Open(filepath.Join(platform.ConfigFolder(), config.GamesDbFilename), 0600, options) + db, err := bolt.Open(filepath.Join(platform.DataDir(), config.GamesDbFile), 0600, options) if err != nil { return nil, err } @@ -172,7 +172,7 @@ type IndexStatus struct { // Returns the total number of files indexed. func NewNamesIndex( platform platforms.Platform, - cfg *config.UserConfig, + cfg *config.Instance, systems []System, update func(IndexStatus), ) (int, error) { @@ -217,7 +217,7 @@ func NewNamesIndex( update(status) systemPaths := make(map[string][]string) - for _, v := range GetSystemPaths(platform, platform.RootFolders(cfg), systems) { + for _, v := range GetSystemPaths(platform, platform.RootDirs(cfg), systems) { systemPaths[v.System.Id] = append(systemPaths[v.System.Id], v.Path) } diff --git a/pkg/database/gamesdb/indexing.go b/pkg/database/gamesdb/indexing.go index f768770d..783304fb 100644 --- a/pkg/database/gamesdb/indexing.go +++ b/pkg/database/gamesdb/indexing.go @@ -109,7 +109,7 @@ func (r *resultsStack) get() (*[]string, error) { // files. This function deep searches .zip files and handles symlinks at all // levels. func GetFiles( - cfg *config.UserConfig, + cfg *config.Instance, platform platforms.Platform, systemId string, path string, @@ -188,7 +188,7 @@ func GetFiles( return err } - if utils.IsZip(path) && platform.ZipsAsFolders() { + if utils.IsZip(path) && platform.ZipsAsDirs() { // zip files zipFiles, err := utils.ListZip(path) if err != nil { diff --git a/pkg/database/gamesdb/systems.go b/pkg/database/gamesdb/systems.go index 79b07133..9e1767a5 100644 --- a/pkg/database/gamesdb/systems.go +++ b/pkg/database/gamesdb/systems.go @@ -8,8 +8,8 @@ import ( ) // The Systems list contains all the supported systems such as consoles, -// computers and media types that are indexable by TapTo. This is the reference -// list of hardcoded system IDs used throughout TapTo. A platform can choose +// computers and media types that are indexable by Zaparoo. This is the reference +// list of hardcoded system IDs used throughout Zaparoo. A platform can choose // not to support any of them. // // This list also contains some basic heuristics which, given a file path, can diff --git a/pkg/platforms/batocera/platform.go b/pkg/platforms/batocera/platform.go index 8fa99a8e..0a2caf3d 100644 --- a/pkg/platforms/batocera/platform.go +++ b/pkg/platforms/batocera/platform.go @@ -3,13 +3,14 @@ package batocera import ( "errors" "github.com/ZaparooProject/zaparoo-core/pkg/api/models" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" + "github.com/ZaparooProject/zaparoo-core/pkg/utils" "os" "os/exec" "path/filepath" "strings" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/database/gamesdb" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" "github.com/ZaparooProject/zaparoo-core/pkg/readers" @@ -26,7 +27,7 @@ func (p *Platform) Id() string { return "batocera" } -func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { +func (p *Platform) SupportedReaders(cfg *config.Instance) []readers.Reader { return []readers.Reader{ libnfc.NewReader(cfg), file.NewReader(cfg), @@ -34,7 +35,11 @@ func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { } } -func (p *Platform) Setup(_ *config.UserConfig, _ chan<- models.Notification) error { +func (p *Platform) StartPre(_ *config.Instance) error { + return nil +} + +func (p *Platform) StartPost(_ *config.Instance, _ chan<- models.Notification) error { return nil } @@ -50,34 +55,33 @@ func (p *Platform) ReadersUpdateHook(readers map[string]*readers.Reader) error { return nil } -func (p *Platform) RootFolders(cfg *config.UserConfig) []string { +func (p *Platform) RootDirs(cfg *config.Instance) []string { return []string{ "/userdata/roms", } } -func (p *Platform) ZipsAsFolders() bool { +func (p *Platform) ZipsAsDirs() bool { return false } -func exeDir() string { - exe, err := os.Executable() - if err != nil { - return "" - } +func (p *Platform) DataDir() string { + return utils.ExeDir() +} - return filepath.Dir(exe) +func (p *Platform) LogDir() string { + return utils.ExeDir() } -func (p *Platform) ConfigFolder() string { - return filepath.Join(exeDir(), "data") +func (p *Platform) ConfigDir() string { + return utils.ExeDir() } -func (p *Platform) LogFolder() string { - return filepath.Join(exeDir(), "logs") +func (p *Platform) TempDir() string { + return filepath.Join(os.TempDir(), config.AppName) } -func (p *Platform) NormalizePath(cfg *config.UserConfig, path string) string { +func (p *Platform) NormalizePath(cfg *config.Instance, path string) string { return path } @@ -101,10 +105,10 @@ func (p *Platform) GetActiveLauncher() string { return "" } -func (p *Platform) PlayFailSound(cfg *config.UserConfig) { +func (p *Platform) PlayFailSound(cfg *config.Instance) { } -func (p *Platform) PlaySuccessSound(cfg *config.UserConfig) { +func (p *Platform) PlaySuccessSound(cfg *config.Instance) { } func (p *Platform) ActiveSystem() string { @@ -123,16 +127,16 @@ func (p *Platform) ActiveGamePath() string { return "" } -func (p *Platform) LaunchSystem(cfg *config.UserConfig, id string) error { +func (p *Platform) LaunchSystem(cfg *config.Instance, id string) error { log.Info().Msgf("launching system: %s", id) return nil } -func (p *Platform) LaunchFile(cfg *config.UserConfig, path string) error { +func (p *Platform) LaunchFile(cfg *config.Instance, path string) error { log.Info().Msgf("launching file: %s", path) relPath := path - for _, rf := range p.RootFolders(cfg) { + for _, rf := range p.RootDirs(cfg) { if strings.HasPrefix(relPath, rf+"/") { relPath = strings.TrimPrefix(relPath, rf+"/") break @@ -196,7 +200,7 @@ func (p *Platform) Launchers() []platforms.Launcher { SystemId: gamesdb.SystemGenesis, Folders: []string{"megadrive"}, Extensions: []string{".bin", ".gen", ".md", ".sg", ".smd", ".zip", ".7z"}, - Launch: func(cfg *config.UserConfig, path string) error { + Launch: func(cfg *config.Instance, path string) error { cmd := exec.Command("emulatorlauncher", "-system", "megadrive", "-rom", path) cmd.Env = os.Environ() cmd.Env = append(cmd.Env, "DISPLAY=:0.0") diff --git a/pkg/platforms/mac/platform.go b/pkg/platforms/mac/platform.go index 505e3838..ebe2b66b 100644 --- a/pkg/platforms/mac/platform.go +++ b/pkg/platforms/mac/platform.go @@ -2,12 +2,13 @@ package mac import ( "github.com/ZaparooProject/zaparoo-core/pkg/api/models" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" + "github.com/ZaparooProject/zaparoo-core/pkg/utils" "os" "os/exec" "path/filepath" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" "github.com/ZaparooProject/zaparoo-core/pkg/readers" "github.com/ZaparooProject/zaparoo-core/pkg/readers/file" @@ -23,7 +24,7 @@ func (p *Platform) Id() string { return "mac" } -func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { +func (p *Platform) SupportedReaders(cfg *config.Instance) []readers.Reader { return []readers.Reader{ file.NewReader(cfg), simple_serial.NewReader(cfg), @@ -31,7 +32,11 @@ func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { } } -func (p *Platform) Setup(_ *config.UserConfig, _ chan<- models.Notification) error { +func (p *Platform) StartPre(_ *config.Instance) error { + return nil +} + +func (p *Platform) StartPost(_ *config.Instance, _ chan<- models.Notification) error { return nil } @@ -47,13 +52,11 @@ func (p *Platform) ReadersUpdateHook(readers map[string]*readers.Reader) error { return nil } -func (p *Platform) RootFolders(cfg *config.UserConfig) []string { - return []string{ - "C:\\scratch", - } +func (p *Platform) RootDirs(cfg *config.Instance) []string { + return []string{} } -func (p *Platform) ZipsAsFolders() bool { +func (p *Platform) ZipsAsDirs() bool { return false } @@ -66,15 +69,23 @@ func exeDir() string { return filepath.Dir(exe) } -func (p *Platform) ConfigFolder() string { - return filepath.Join(exeDir(), "data") +func (p *Platform) DataDir() string { + return utils.ExeDir() +} + +func (p *Platform) LogDir() string { + return utils.ExeDir() +} + +func (p *Platform) ConfigDir() string { + return utils.ExeDir() } -func (p *Platform) LogFolder() string { - return filepath.Join(exeDir(), "logs") +func (p *Platform) TempDir() string { + return filepath.Join(os.TempDir(), config.AppName) } -func (p *Platform) NormalizePath(cfg *config.UserConfig, path string) string { +func (p *Platform) NormalizePath(cfg *config.Instance, path string) string { return path } @@ -98,10 +109,10 @@ func (p *Platform) GetActiveLauncher() string { return "" } -func (p *Platform) PlayFailSound(cfg *config.UserConfig) { +func (p *Platform) PlayFailSound(cfg *config.Instance) { } -func (p *Platform) PlaySuccessSound(cfg *config.UserConfig) { +func (p *Platform) PlaySuccessSound(cfg *config.Instance) { } func (p *Platform) ActiveSystem() string { @@ -120,12 +131,12 @@ func (p *Platform) ActiveGamePath() string { return "" } -func (p *Platform) LaunchSystem(cfg *config.UserConfig, id string) error { +func (p *Platform) LaunchSystem(cfg *config.Instance, id string) error { log.Info().Msgf("launching system: %s", id) return nil } -func (p *Platform) LaunchFile(cfg *config.UserConfig, path string) error { +func (p *Platform) LaunchFile(cfg *config.Instance, path string) error { log.Info().Msgf("launching file: %s", path) if filepath.Ext(path) == ".txt" { diff --git a/pkg/platforms/mister/commands.go b/pkg/platforms/mister/commands.go index 65f96c74..f82aa2cb 100644 --- a/pkg/platforms/mister/commands.go +++ b/pkg/platforms/mister/commands.go @@ -69,7 +69,7 @@ func cmdMisterScript(plm Platform) func(platforms.Platform, platforms.CmdEnv) er return fmt.Errorf("invalid script: %s", script) } - scriptPath := filepath.Join(ScriptsFolder, script) + scriptPath := filepath.Join(ScriptsDir, script) if _, err := os.Stat(scriptPath); err != nil { return fmt.Errorf("script not found: %s", script) } diff --git a/pkg/platforms/mister/config.go b/pkg/platforms/mister/config.go index abdf8c55..95263f15 100644 --- a/pkg/platforms/mister/config.go +++ b/pkg/platforms/mister/config.go @@ -4,42 +4,36 @@ package mister import ( "github.com/ZaparooProject/zaparoo-core/pkg/config" + "github.com/ZaparooProject/zaparoo-core/pkg/platforms" mrextConfig "github.com/wizzomafizzo/mrext/pkg/config" ) const ( - TempFolder = "/tmp/tapto" - LogFile = TempFolder + "/tapto.log" - DisableLaunchFile = TempFolder + "/tapto.disabled" - SuccessSoundFile = TempFolder + "/success.wav" - FailSoundFile = TempFolder + "/fail.wav" - SocketFile = TempFolder + "/tapto.sock" - PidFile = TempFolder + "/tapto.pid" - MappingsFile = "/media/fat/nfc.csv" - TokenReadFile = "/tmp/TOKENREAD" - ConfigFolder = mrextConfig.ScriptsConfigFolder + "/tapto" - DbFile = ConfigFolder + "/tapto.db" - GamesDbFile = ConfigFolder + "/games.db" - ArcadeDbUrl = "https://api.github.com/repositories/521644036/contents/ArcadeDatabase_CSV" - ArcadeDbFile = ConfigFolder + "/ArcadeDatabase.csv" - ScriptsFolder = mrextConfig.ScriptsFolder - CmdInterface = "/dev/MiSTer_cmd" - LinuxFolder = "/media/fat/linux" + AssetsDir = DataDir + "/" + platforms.AssetsDir + TempDir = "/tmp/zaparoo" + DisableLaunchFile = TempDir + "/zaparoo.disabled" + SuccessSoundFile = AssetsDir + "/success.wav" + FailSoundFile = AssetsDir + "/fail.wav" + SocketFile = TempDir + "/core.sock" + LegacyMappingsPath = "/media/fat/nfc.csv" + TokenReadFile = "/tmp/TOKENREAD" // TODO: remove this, use file driver + DataDir = "/media/fat/zaparoo" + ArcadeDbUrl = "https://api.github.com/repositories/521644036/contents/ArcadeDatabase_CSV" + ArcadeDbFile = AssetsDir + "/ArcadeDatabase.csv" + ScriptsDir = mrextConfig.ScriptsFolder + CmdInterface = "/dev/MiSTer_cmd" + LinuxDir = "/media/fat/linux" ) -func UserConfigToMrext(cfg *config.UserConfig) *mrextConfig.UserConfig { +func UserConfigToMrext(cfg *config.Instance) *mrextConfig.UserConfig { + var setCore []string + for _, v := range cfg.SystemDefaults() { + setCore = append(setCore, v.System+":"+v.Launcher) + } return &mrextConfig.UserConfig{ - AppPath: cfg.AppPath, - IniPath: cfg.IniPath, - Nfc: mrextConfig.NfcConfig{ - ConnectionString: cfg.GetConnectionString(), - AllowCommands: cfg.GetAllowCommands(), - DisableSounds: cfg.GetDisableSounds(), - ProbeDevice: cfg.GetProbeDevice(), - }, Systems: mrextConfig.SystemsConfig{ - GamesFolder: cfg.Systems.GamesFolder, - SetCore: cfg.Systems.SetCore, + GamesFolder: cfg.IndexRoots(), + SetCore: setCore, }, } } diff --git a/pkg/platforms/mister/csvmappings.go b/pkg/platforms/mister/csvmappings.go index 463d2a54..64272041 100644 --- a/pkg/platforms/mister/csvmappings.go +++ b/pkg/platforms/mister/csvmappings.go @@ -1,23 +1,23 @@ //go:build linux || darwin /* -TapTo +Zaparoo Core Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package mister @@ -45,12 +45,12 @@ func LoadCsvMappings() (map[string]string, map[string]string, error) { uids := make(map[string]string) texts := make(map[string]string) - if _, err := os.Stat(MappingsFile); errors.Is(err, os.ErrNotExist) { - log.Info().Msg("no database file found, skipping") + if _, err := os.Stat(LegacyMappingsPath); errors.Is(err, os.ErrNotExist) { + log.Debug().Msg("no legacy mappings file found, skipping processing") return nil, nil, nil } - f, err := os.Open(MappingsFile) + f, err := os.Open(LegacyMappingsPath) if err != nil { return nil, nil, err } @@ -136,9 +136,9 @@ func StartCsvMappingsWatcher( } else if event.Has(fsnotify.Remove) { // editors may also delete the file on write time.Sleep(delay) - _, err := os.Stat(MappingsFile) + _, err := os.Stat(LegacyMappingsPath) if err == nil { - err = dbWatcher.Add(MappingsFile) + err = dbWatcher.Add(LegacyMappingsPath) if err != nil { log.Error().Msgf("error watching database: %s", err) } @@ -160,9 +160,11 @@ func StartCsvMappingsWatcher( } }() - err = dbWatcher.Add(MappingsFile) - if err != nil { - log.Error().Msgf("error watching database: %s", err) + if _, err := os.Stat(LegacyMappingsPath); err == nil { + err = dbWatcher.Add(LegacyMappingsPath) + if err != nil { + log.Error().Msgf("error watching database: %s", err) + } } return closeDbWatcher, nil diff --git a/pkg/platforms/mister/launchers.go b/pkg/platforms/mister/launchers.go index f6a2f205..4da7a720 100644 --- a/pkg/platforms/mister/launchers.go +++ b/pkg/platforms/mister/launchers.go @@ -17,15 +17,15 @@ import ( "time" ) -func launch(cfg *config.UserConfig, path string) error { +func launch(cfg *config.Instance, path string) error { return mister.LaunchGenericFile(UserConfigToMrext(cfg), path) } func launchSinden( systemId string, rbfName string, -) func(*config.UserConfig, string) error { - return func(cfg *config.UserConfig, path string) error { +) func(*config.Instance, string) error { + return func(cfg *config.Instance, path string) error { s, err := games.GetSystem(systemId) if err != nil { return err @@ -42,8 +42,8 @@ func launchSinden( func launchAltCore( systemId string, rbfPath string, -) func(*config.UserConfig, string) error { - return func(cfg *config.UserConfig, path string) error { +) func(*config.Instance, string) error { + return func(cfg *config.Instance, path string) error { s, err := games.GetSystem(systemId) if err != nil { return err @@ -55,12 +55,12 @@ func launchAltCore( } } -func killCore(_ *config.UserConfig) error { +func killCore(_ *config.Instance) error { return mister.LaunchMenu() } -func launchMPlayer(pl Platform) func(*config.UserConfig, string) error { - return func(_ *config.UserConfig, path string) error { +func launchMPlayer(pl Platform) func(*config.Instance, string) error { + return func(_ *config.Instance, path string) error { if len(path) == 0 { return fmt.Errorf("no path specified") } @@ -97,12 +97,12 @@ func launchMPlayer(pl Platform) func(*config.UserConfig, string) error { "nice", "-n", "-20", - filepath.Join(LinuxFolder, "mplayer"), + filepath.Join(LinuxDir, "mplayer"), "-cache", "8192", path, ) - cmd.Env = append(os.Environ(), "LD_LIBRARY_PATH="+LinuxFolder) + cmd.Env = append(os.Environ(), "LD_LIBRARY_PATH="+LinuxDir) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -136,7 +136,7 @@ func launchMPlayer(pl Platform) func(*config.UserConfig, string) error { } } -func killMPlayer(_ *config.UserConfig) error { +func killMPlayer(_ *config.Instance) error { psCmd := exec.Command("sh", "-c", "ps aux | grep mplayer | grep -v grep") output, err := psCmd.Output() if err != nil { diff --git a/pkg/platforms/mister/methods.go b/pkg/platforms/mister/methods.go index 6b087b11..a4676fe9 100644 --- a/pkg/platforms/mister/methods.go +++ b/pkg/platforms/mister/methods.go @@ -3,12 +3,12 @@ package mister import ( + "github.com/ZaparooProject/zaparoo-core/pkg/config" "os" "os/exec" "strings" "github.com/ZaparooProject/zaparoo-core/pkg/assets" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/rs/zerolog/log" mrextConfig "github.com/wizzomafizzo/mrext/pkg/config" "github.com/wizzomafizzo/mrext/pkg/games" @@ -21,33 +21,37 @@ import ( // and are annoying to compile statically func Setup(tr *Tracker) error { - // copy success sound to temp - sf, err := os.Create(SuccessSoundFile) - if err != nil { - log.Error().Msgf("error creating success sound file: %s", err) - } - _, err = sf.Write(assets.SuccessSound) - if err != nil { - log.Error().Msgf("error writing success sound file: %s", err) + if _, err := os.Stat(SuccessSoundFile); err != nil { + // copy success sound to temp + sf, err := os.Create(SuccessSoundFile) + if err != nil { + log.Error().Msgf("error creating success sound file: %s", err) + } + _, err = sf.Write(assets.SuccessSound) + if err != nil { + log.Error().Msgf("error writing success sound file: %s", err) + } + _ = sf.Close() } - _ = sf.Close() - // copy fail sound to temp - ff, err := os.Create(FailSoundFile) - if err != nil { - log.Error().Msgf("error creating fail sound file: %s", err) - } - _, err = ff.Write(assets.FailSound) - if err != nil { - log.Error().Msgf("error writing fail sound file: %s", err) + if _, err := os.Stat(FailSoundFile); err != nil { + // copy fail sound to temp + ff, err := os.Create(FailSoundFile) + if err != nil { + log.Error().Msgf("error creating fail sound file: %s", err) + } + _, err = ff.Write(assets.FailSound) + if err != nil { + log.Error().Msgf("error writing fail sound file: %s", err) + } + _ = ff.Close() } - _ = ff.Close() // attempt arcadedb update go func() { haveInternet := utils.WaitForInternet(30) if !haveInternet { - log.Info().Msg("no internet connection, skipping network tasks") + log.Warn().Msg("no internet connection, skipping network tasks") return } @@ -74,8 +78,8 @@ func Setup(tr *Tracker) error { return nil } -func PlaySuccess(cfg *config.UserConfig) { - if cfg.GetDisableSounds() { +func PlaySuccess(cfg *config.Instance) { + if !cfg.AudioFeedback() { return } @@ -85,8 +89,8 @@ func PlaySuccess(cfg *config.UserConfig) { } } -func PlayFail(cfg *config.UserConfig) { - if cfg.GetDisableSounds() { +func PlayFail(cfg *config.Instance) { + if !cfg.AudioFeedback() { return } @@ -108,7 +112,7 @@ func GetActiveCoreName() string { return coreName } -func NormalizePath(cfg *config.UserConfig, path string) string { +func NormalizePath(cfg *config.Instance, path string) string { sys, err := games.BestSystemMatch(UserConfigToMrext(cfg), path) if err != nil { return path diff --git a/pkg/platforms/mister/platform.go b/pkg/platforms/mister/platform.go index 41be6731..561a5176 100644 --- a/pkg/platforms/mister/platform.go +++ b/pkg/platforms/mister/platform.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "github.com/ZaparooProject/zaparoo-core/pkg/api/models" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/database/gamesdb" "github.com/ZaparooProject/zaparoo-core/pkg/readers/optical_drive" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" @@ -20,7 +21,6 @@ import ( "strings" "time" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" "github.com/ZaparooProject/zaparoo-core/pkg/readers" "github.com/ZaparooProject/zaparoo-core/pkg/readers/file" @@ -75,7 +75,7 @@ func (p *Platform) Id() string { return "mister" } -func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { +func (p *Platform) SupportedReaders(cfg *config.Instance) []readers.Reader { return []readers.Reader{ libnfc.NewReader(cfg), file.NewReader(cfg), @@ -84,7 +84,34 @@ func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { } } -func (p *Platform) Setup(cfg *config.UserConfig, ns chan<- models.Notification) error { +func (p *Platform) StartPre(cfg *config.Instance) error { + err := os.MkdirAll(TempDir, 0755) + if err != nil { + return err + } + + err = os.MkdirAll(DataDir, 0755) + if err != nil { + return err + } + + err = os.MkdirAll(filepath.Join(p.DataDir(), platforms.AssetsDir), 0755) + if err != nil { + return err + } + + // migrate old config folder db + oldTaptoDbPath := "/media/fat/Scripts/.config/tapto/tapto.db" + newTaptoDbPath := filepath.Join(p.DataDir(), config.TapToDbFile) + if _, err := os.Stat(oldTaptoDbPath); err == nil { + if _, err := os.Stat(newTaptoDbPath); errors.Is(err, os.ErrNotExist) { + err := utils.CopyFile(oldTaptoDbPath, newTaptoDbPath) + if err != nil { + return err + } + } + } + kbd, err := input.NewKeyboard() if err != nil { return err @@ -94,7 +121,7 @@ func (p *Platform) Setup(cfg *config.UserConfig, ns chan<- models.Notification) gpd, err := uinput.CreateGamepad( "/dev/uinput", - []byte("tapto"), + []byte("zaparoo"), 0x1234, 0x5678, ) @@ -103,14 +130,6 @@ func (p *Platform) Setup(cfg *config.UserConfig, ns chan<- models.Notification) } p.gpd = gpd - tr, stopTr, err := StartTracker(*UserConfigToMrext(cfg), ns) - if err != nil { - return err - } - - p.tr = tr - p.stopTr = stopTr - uids, texts, err := LoadCsvMappings() if err != nil { log.Error().Msgf("error loading mappings: %s", err) @@ -158,6 +177,18 @@ func (p *Platform) Setup(cfg *config.UserConfig, ns chan<- models.Notification) return nil } +func (p *Platform) StartPost(cfg *config.Instance, ns chan<- models.Notification) error { + tr, stopTr, err := StartTracker(*UserConfigToMrext(cfg), ns) + if err != nil { + return err + } + + p.tr = tr + p.stopTr = stopTr + + return nil +} + func (p *Platform) Stop() error { if p.stopTr != nil { err := p.stopTr() @@ -211,23 +242,31 @@ func (p *Platform) ReadersUpdateHook(readers map[string]*readers.Reader) error { return nil } -func (p *Platform) RootFolders(cfg *config.UserConfig) []string { +func (p *Platform) RootDirs(cfg *config.Instance) []string { return games.GetGamesFolders(UserConfigToMrext(cfg)) } -func (p *Platform) ZipsAsFolders() bool { +func (p *Platform) ZipsAsDirs() bool { return true } -func (p *Platform) ConfigFolder() string { - return ConfigFolder +func (p *Platform) DataDir() string { + return DataDir +} + +func (p *Platform) LogDir() string { + return TempDir +} + +func (p *Platform) ConfigDir() string { + return DataDir } -func (p *Platform) LogFolder() string { - return TempFolder +func (p *Platform) TempDir() string { + return TempDir } -func (p *Platform) NormalizePath(cfg *config.UserConfig, path string) string { +func (p *Platform) NormalizePath(cfg *config.Instance, path string) string { return NormalizePath(cfg, path) } @@ -260,11 +299,11 @@ func (p *Platform) GetActiveLauncher() string { return core } -func (p *Platform) PlayFailSound(cfg *config.UserConfig) { +func (p *Platform) PlayFailSound(cfg *config.Instance) { PlayFail(cfg) } -func (p *Platform) PlaySuccessSound(cfg *config.UserConfig) { +func (p *Platform) PlaySuccessSound(cfg *config.Instance) { PlaySuccess(cfg) } @@ -284,7 +323,7 @@ func (p *Platform) ActiveGamePath() string { return p.tr.ActiveGamePath } -func (p *Platform) LaunchSystem(cfg *config.UserConfig, id string) error { +func (p *Platform) LaunchSystem(cfg *config.Instance, id string) error { system, err := games.LookupSystem(id) if err != nil { return err @@ -293,7 +332,7 @@ func (p *Platform) LaunchSystem(cfg *config.UserConfig, id string) error { return mister.LaunchCore(UserConfigToMrext(cfg), *system) } -func (p *Platform) LaunchFile(cfg *config.UserConfig, path string) error { +func (p *Platform) LaunchFile(cfg *config.Instance, path string) error { launchers := utils.PathToLaunchers(cfg, p, path) if len(launchers) == 0 { @@ -435,7 +474,7 @@ func (p *Platform) Launchers() []platforms.Launcher { Extensions: []string{".adf"}, Launch: launch, Scanner: func( - cfg *config.UserConfig, + cfg *config.Instance, systemId string, results []platforms.ScanResult, ) ([]platforms.ScanResult, error) { @@ -449,7 +488,7 @@ func (p *Platform) Launchers() []platforms.Launcher { return results, err } - sfs := gamesdb.GetSystemPaths(p, p.RootFolders(cfg), []gamesdb.System{*s}) + sfs := gamesdb.GetSystemPaths(p, p.RootDirs(cfg), []gamesdb.System{*s}) for _, sf := range sfs { for _, txt := range []string{aGamesPath, aDemosPath} { tp, err := gamesdb.FindPath(filepath.Join(sf.Path, txt)) @@ -492,7 +531,7 @@ func (p *Platform) Launchers() []platforms.Launcher { Extensions: []string{".neo"}, Launch: launch, Scanner: func( - cfg *config.UserConfig, + cfg *config.Instance, systemId string, results []platforms.ScanResult, ) ([]platforms.ScanResult, error) { @@ -505,7 +544,7 @@ func (p *Platform) Launchers() []platforms.Launcher { return results, err } - sfs := gamesdb.GetSystemPaths(p, p.RootFolders(cfg), []gamesdb.System{*s}) + sfs := gamesdb.GetSystemPaths(p, p.RootDirs(cfg), []gamesdb.System{*s}) for _, sf := range sfs { rsf, err := gamesdb.FindPath(filepath.Join(sf.Path, romsetsFilename)) if err == nil { diff --git a/pkg/platforms/mister/socket.go b/pkg/platforms/mister/socket.go index ccbf700d..38d8ae20 100644 --- a/pkg/platforms/mister/socket.go +++ b/pkg/platforms/mister/socket.go @@ -3,6 +3,7 @@ package mister import ( + "errors" "fmt" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "net" @@ -38,7 +39,9 @@ func StartSocketServer( conn, err := socket.Accept() if err != nil { - log.Error().Msgf("error accepting connection: %s", err) + if !errors.Is(err, net.ErrClosed) { + log.Error().Msgf("error accepting connection: %s", err) + } return } diff --git a/pkg/platforms/mistex/platform.go b/pkg/platforms/mistex/platform.go index a094de9d..6499bda2 100644 --- a/pkg/platforms/mistex/platform.go +++ b/pkg/platforms/mistex/platform.go @@ -5,6 +5,7 @@ package mistex import ( "fmt" "github.com/ZaparooProject/zaparoo-core/pkg/api/models" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "os" "os/exec" @@ -12,7 +13,6 @@ import ( "strconv" "time" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" "github.com/ZaparooProject/zaparoo-core/pkg/platforms/mister" "github.com/ZaparooProject/zaparoo-core/pkg/readers" @@ -37,7 +37,7 @@ func (p *Platform) Id() string { return "mistex" } -func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { +func (p *Platform) SupportedReaders(cfg *config.Instance) []readers.Reader { return []readers.Reader{ libnfc.NewReader(cfg), file.NewReader(cfg), @@ -45,7 +45,17 @@ func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { } } -func (p *Platform) Setup(cfg *config.UserConfig, ns chan<- models.Notification) error { +func (p *Platform) StartPre(_ *config.Instance) error { + err := os.MkdirAll(mister.TempDir, 0755) + if err != nil { + return err + } + + err = os.MkdirAll(mister.DataDir, 0755) + if err != nil { + return err + } + kbd, err := input.NewKeyboard() if err != nil { return err @@ -54,7 +64,7 @@ func (p *Platform) Setup(cfg *config.UserConfig, ns chan<- models.Notification) gpd, err := uinput.CreateGamepad( "/dev/uinput", - []byte("tapto"), + []byte("zaparoo"), 0x1234, 0x5678, ) @@ -63,19 +73,23 @@ func (p *Platform) Setup(cfg *config.UserConfig, ns chan<- models.Notification) } p.gpd = gpd - tr, stopTr, err := mister.StartTracker(*mister.UserConfigToMrext(cfg), ns) + err = mister.Setup(p.tr) if err != nil { return err } - p.tr = tr - p.stopTr = stopTr + return nil +} - err = mister.Setup(p.tr) +func (p *Platform) StartPost(cfg *config.Instance, ns chan<- models.Notification) error { + tr, stopTr, err := mister.StartTracker(*mister.UserConfigToMrext(cfg), ns) if err != nil { return err } + p.tr = tr + p.stopTr = stopTr + return nil } @@ -115,23 +129,31 @@ func (p *Platform) ReadersUpdateHook(readers map[string]*readers.Reader) error { return nil } -func (p *Platform) RootFolders(cfg *config.UserConfig) []string { +func (p *Platform) RootDirs(cfg *config.Instance) []string { return games.GetGamesFolders(mister.UserConfigToMrext(cfg)) } -func (p *Platform) ZipsAsFolders() bool { +func (p *Platform) ZipsAsDirs() bool { return true } -func (p *Platform) ConfigFolder() string { - return mister.ConfigFolder +func (p *Platform) DataDir() string { + return mister.DataDir +} + +func (p *Platform) LogDir() string { + return mister.TempDir +} + +func (p *Platform) ConfigDir() string { + return mister.DataDir } -func (p *Platform) LogFolder() string { - return mister.TempFolder +func (p *Platform) TempDir() string { + return mister.TempDir } -func (p *Platform) NormalizePath(cfg *config.UserConfig, path string) string { +func (p *Platform) NormalizePath(cfg *config.Instance, path string) string { return mister.NormalizePath(cfg, path) } @@ -180,11 +202,11 @@ func (p *Platform) GetActiveLauncher() string { return core } -func (p *Platform) PlayFailSound(cfg *config.UserConfig) { +func (p *Platform) PlayFailSound(cfg *config.Instance) { mister.PlayFail(cfg) } -func (p *Platform) PlaySuccessSound(cfg *config.UserConfig) { +func (p *Platform) PlaySuccessSound(cfg *config.Instance) { mister.PlaySuccess(cfg) } @@ -204,7 +226,7 @@ func (p *Platform) ActiveGamePath() string { return p.tr.ActiveGamePath } -func (p *Platform) LaunchSystem(cfg *config.UserConfig, id string) error { +func (p *Platform) LaunchSystem(cfg *config.Instance, id string) error { system, err := games.LookupSystem(id) if err != nil { return err @@ -213,7 +235,7 @@ func (p *Platform) LaunchSystem(cfg *config.UserConfig, id string) error { return mm.LaunchCore(mister.UserConfigToMrext(cfg), *system) } -func (p *Platform) LaunchFile(cfg *config.UserConfig, path string) error { +func (p *Platform) LaunchFile(cfg *config.Instance, path string) error { return mm.LaunchGenericFile(mister.UserConfigToMrext(cfg), path) } diff --git a/pkg/platforms/platforms.go b/pkg/platforms/platforms.go index 5b5e8742..2b3633c2 100644 --- a/pkg/platforms/platforms.go +++ b/pkg/platforms/platforms.go @@ -8,11 +8,16 @@ import ( "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" ) +const ( + AssetsDir = "assets" + MappingsDir = "mappings" +) + type CmdEnv struct { Cmd string Args string NamedArgs map[string]string - Cfg *config.UserConfig + Cfg *config.Instance Playlist playlists.PlaylistController Manual bool Text string @@ -38,42 +43,52 @@ type Launcher struct { // Accepted schemes for URI-style launches. Schemes []string // Launch function, takes a direct as possible path/ID media file. - Launch func(*config.UserConfig, string) error + Launch func(*config.Instance, string) error // Kill function kills the current active launcher, if possible. - Kill func(*config.UserConfig) error + Kill func(*config.Instance) error // Optional function to perform custom media scanning. Takes the list of // results from the standard scan, if any, and returns the final list. - Scanner func(*config.UserConfig, string, []ScanResult) ([]ScanResult, error) + Scanner func(*config.Instance, string, []ScanResult) ([]ScanResult, error) // If true, all resolved paths must be in the allow list before they // can be launched. AllowListOnly bool } type Platform interface { - // Unique ID of the platform. + // Id returns the unique ID of this platform. Id() string - // Any initial setup required before daemon is fully started. - Setup(*config.UserConfig, chan<- models.Notification) error - // TOOD: what is this? + // StartPre runs any necessary platform setup functions before the main + // service has started running. + StartPre(*config.Instance) error + // StartPost runs any necessary platform setup function after the main + // service has started running. + StartPost(*config.Instance, chan<- models.Notification) error + // Stop runs any necessary cleanup function before the rest of the service + // starts shutting down. Stop() error // Run immediately after a successful scan, before it is processed for launching. AfterScanHook(tokens.Token) error // Run after the active readers have been updated. ReadersUpdateHook(map[string]*readers.Reader) error // List of supported readers for this platform. - SupportedReaders(*config.UserConfig) []readers.Reader + SupportedReaders(*config.Instance) []readers.Reader // List of root folders to scan for media files. - RootFolders(*config.UserConfig) []string + RootDirs(*config.Instance) []string // Whether to treat zip files as folders during media scanning. - ZipsAsFolders() bool - // Path to the configuration/database data for TapTo. - ConfigFolder() string // TODO: rename to data folder (because that's what it is) - // Path to the log folder for TapTo. - LogFolder() string + ZipsAsDirs() bool + // Path to the configuration/database data for Zaparoo Core. + DataDir() string + // Path to the log folder for Zaparoo Core. + LogDir() string + // ConfigDir returns the path of the parent directory of the config file. + ConfigDir() string + // TempDir return the path for storing temporary files. It may be called + // multiple times and must return the same path for the service lifetime. + TempDir() string // Convert a path to a normalized form for the platform, the shortest - // possible path that can interpreted and lanched by TapTo. For writing + // possible path that can interpreted and lanched by Zaparoo Core. For writing // to tokens. - NormalizePath(*config.UserConfig, string) string + NormalizePath(*config.Instance, string) string // Kill the currently running launcher process if possible. KillLauncher() error LaunchingEnabled() bool // TODO: remove? should be mister only? @@ -81,9 +96,9 @@ type Platform interface { // Return the ID of the currently active launcher. Empty string if none. GetActiveLauncher() string // Play a sound effect for error feedback. - PlayFailSound(*config.UserConfig) // TODO: change to like PlaySound? + PlayFailSound(*config.Instance) // TODO: change to like PlaySound? // Play a sound effect for success feedback. - PlaySuccessSound(*config.UserConfig) + PlaySuccessSound(*config.Instance) // Returns the currently active system ID. ActiveSystem() string // Returns the currently active game ID. @@ -93,9 +108,9 @@ type Platform interface { // Returns the currently active game path. ActiveGamePath() string // Launch a system by ID. - LaunchSystem(*config.UserConfig, string) error + LaunchSystem(*config.Instance, string) error // Launch a file by path. - LaunchFile(*config.UserConfig, string) error + LaunchFile(*config.Instance, string) error // Launch a shell command. Shell(string) error KeyboardInput(string) error // DEPRECATED diff --git a/pkg/platforms/steamos/platform.go b/pkg/platforms/steamos/platform.go index 4dc3abe3..26a9f24a 100644 --- a/pkg/platforms/steamos/platform.go +++ b/pkg/platforms/steamos/platform.go @@ -27,6 +27,7 @@ import ( "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "github.com/ZaparooProject/zaparoo-core/pkg/utils" "github.com/adrg/xdg" + "os" "os/exec" "path/filepath" "strings" @@ -48,7 +49,7 @@ func (p *Platform) Id() string { return "steamos" } -func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { +func (p *Platform) SupportedReaders(cfg *config.Instance) []readers.Reader { return []readers.Reader{ file.NewReader(cfg), simple_serial.NewReader(cfg), @@ -57,7 +58,11 @@ func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { } } -func (p *Platform) Setup(_ *config.UserConfig, _ chan<- models.Notification) error { +func (p *Platform) StartPre(_ *config.Instance) error { + return os.MkdirAll(filepath.Join(xdg.DataHome, config.AppName), 0755) +} + +func (p *Platform) StartPost(_ *config.Instance, _ chan<- models.Notification) error { return nil } @@ -73,23 +78,31 @@ func (p *Platform) ReadersUpdateHook(_ map[string]*readers.Reader) error { return nil } -func (p *Platform) RootFolders(_ *config.UserConfig) []string { +func (p *Platform) RootDirs(_ *config.Instance) []string { return []string{} } -func (p *Platform) ZipsAsFolders() bool { +func (p *Platform) ZipsAsDirs() bool { return false } -func (p *Platform) ConfigFolder() string { +func (p *Platform) DataDir() string { return filepath.Join(xdg.DataHome, config.AppName) } -func (p *Platform) LogFolder() string { +func (p *Platform) LogDir() string { return filepath.Join(xdg.DataHome, config.AppName) } -func (p *Platform) NormalizePath(_ *config.UserConfig, path string) string { +func (p *Platform) ConfigDir() string { + return filepath.Join(xdg.ConfigHome, config.AppName) +} + +func (p *Platform) TempDir() string { + return filepath.Join(os.TempDir(), config.AppName) +} + +func (p *Platform) NormalizePath(_ *config.Instance, path string) string { return path } @@ -114,10 +127,10 @@ func (p *Platform) GetActiveLauncher() string { return "" } -func (p *Platform) PlayFailSound(_ *config.UserConfig) { +func (p *Platform) PlayFailSound(_ *config.Instance) { } -func (p *Platform) PlaySuccessSound(_ *config.UserConfig) { +func (p *Platform) PlaySuccessSound(_ *config.Instance) { } func (p *Platform) ActiveSystem() string { @@ -137,11 +150,11 @@ func (p *Platform) ActiveGamePath() string { return "" } -func (p *Platform) LaunchSystem(_ *config.UserConfig, _ string) error { +func (p *Platform) LaunchSystem(_ *config.Instance, _ string) error { return nil } -func (p *Platform) LaunchFile(cfg *config.UserConfig, path string) error { +func (p *Platform) LaunchFile(cfg *config.Instance, path string) error { log.Info().Msgf("launching file: %s", path) launchers := utils.PathToLaunchers(cfg, p, path) if len(launchers) == 0 { @@ -181,7 +194,7 @@ func (p *Platform) Launchers() []platforms.Launcher { SystemId: gamesdb.SystemPC, Schemes: []string{"steam"}, Scanner: func( - cfg *config.UserConfig, + cfg *config.Instance, systemId string, results []platforms.ScanResult, ) ([]platforms.ScanResult, error) { @@ -192,7 +205,7 @@ func (p *Platform) Launchers() []platforms.Launcher { } return append(results, appResults...), nil }, - Launch: func(cfg *config.UserConfig, path string) error { + Launch: func(cfg *config.Instance, path string) error { id := strings.TrimPrefix(path, "steam://") id = strings.TrimPrefix(id, "rungameid/") return exec.Command( @@ -205,7 +218,7 @@ func (p *Platform) Launchers() []platforms.Launcher { Id: "Generic", Extensions: []string{".sh"}, AllowListOnly: true, - Launch: func(cfg *config.UserConfig, path string) error { + Launch: func(cfg *config.Instance, path string) error { return exec.Command("bash", "-c", path).Start() }, }, diff --git a/pkg/platforms/windows/platform.go b/pkg/platforms/windows/platform.go index 7567b88a..95eb0021 100644 --- a/pkg/platforms/windows/platform.go +++ b/pkg/platforms/windows/platform.go @@ -4,6 +4,7 @@ import ( "encoding/xml" "errors" "fmt" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "github.com/ZaparooProject/zaparoo-core/pkg/utils" "io" @@ -14,7 +15,6 @@ import ( "github.com/ZaparooProject/zaparoo-core/pkg/api/models" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/database/gamesdb" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" "github.com/ZaparooProject/zaparoo-core/pkg/readers" @@ -32,7 +32,7 @@ func (p *Platform) Id() string { return "windows" } -func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { +func (p *Platform) SupportedReaders(cfg *config.Instance) []readers.Reader { return []readers.Reader{ file.NewReader(cfg), simple_serial.NewReader(cfg), @@ -41,7 +41,11 @@ func (p *Platform) SupportedReaders(cfg *config.UserConfig) []readers.Reader { } } -func (p *Platform) Setup(_ *config.UserConfig, _ chan<- models.Notification) error { +func (p *Platform) StartPre(_ *config.Instance) error { + return nil +} + +func (p *Platform) StartPost(_ *config.Instance, _ chan<- models.Notification) error { return nil } @@ -57,33 +61,32 @@ func (p *Platform) ReadersUpdateHook(readers map[string]*readers.Reader) error { return nil } -func (p *Platform) RootFolders(cfg *config.UserConfig) []string { +func (p *Platform) RootDirs(cfg *config.Instance) []string { return []string{} } -func (p *Platform) ZipsAsFolders() bool { +func (p *Platform) ZipsAsDirs() bool { return false } -func exeDir() string { - exe, err := os.Executable() - if err != nil { - return "" - } +func (p *Platform) DataDir() string { + // TODO: this could be AppData instead + return utils.ExeDir() +} - return filepath.Dir(exe) +func (p *Platform) LogDir() string { + return utils.ExeDir() } -func (p *Platform) ConfigFolder() string { - // this could be AppData instead - return filepath.Join(exeDir(), "data") +func (p *Platform) ConfigDir() string { + return utils.ExeDir() } -func (p *Platform) LogFolder() string { - return filepath.Join(exeDir(), "logs") +func (p *Platform) TempDir() string { + return filepath.Join(os.TempDir(), config.AppName) } -func (p *Platform) NormalizePath(cfg *config.UserConfig, path string) string { +func (p *Platform) NormalizePath(cfg *config.Instance, path string) string { return path } @@ -107,10 +110,10 @@ func (p *Platform) GetActiveLauncher() string { return "" } -func (p *Platform) PlayFailSound(cfg *config.UserConfig) { +func (p *Platform) PlayFailSound(cfg *config.Instance) { } -func (p *Platform) PlaySuccessSound(cfg *config.UserConfig) { +func (p *Platform) PlaySuccessSound(cfg *config.Instance) { } func (p *Platform) ActiveSystem() string { @@ -129,12 +132,12 @@ func (p *Platform) ActiveGamePath() string { return "" } -func (p *Platform) LaunchSystem(cfg *config.UserConfig, id string) error { +func (p *Platform) LaunchSystem(cfg *config.Instance, id string) error { log.Info().Msgf("launching system: %s", id) return nil } -func (p *Platform) LaunchFile(cfg *config.UserConfig, path string) error { +func (p *Platform) LaunchFile(cfg *config.Instance, path string) error { log.Info().Msgf("launching file: %s", path) launchers := make([]platforms.Launcher, 0) @@ -173,7 +176,7 @@ func (p *Platform) LaunchFile(cfg *config.UserConfig, path string) error { if l.Launch != nil { if l.AllowListOnly { - if cfg.IsFileAllowed(path) { + if cfg.IsLauncherFileAllowed(path) { return l.Launch(cfg, path) } else { return errors.New("file not in allow list: " + path) @@ -438,7 +441,7 @@ func (p *Platform) Launchers() []platforms.Launcher { SystemId: gamesdb.SystemPC, Schemes: []string{"steam"}, Scanner: func( - cfg *config.UserConfig, + cfg *config.Instance, systemId string, results []platforms.ScanResult, ) ([]platforms.ScanResult, error) { @@ -450,7 +453,7 @@ func (p *Platform) Launchers() []platforms.Launcher { } return append(results, appResults...), nil }, - Launch: func(cfg *config.UserConfig, path string) error { + Launch: func(cfg *config.Instance, path string) error { id := strings.TrimPrefix(path, "steam://") id = strings.TrimPrefix(id, "rungameid/") return exec.Command( @@ -464,7 +467,7 @@ func (p *Platform) Launchers() []platforms.Launcher { Id: "Flashpoint", SystemId: gamesdb.SystemPC, Schemes: []string{"flashpoint"}, - Launch: func(cfg *config.UserConfig, path string) error { + Launch: func(cfg *config.Instance, path string) error { id := strings.TrimPrefix(path, "flashpoint://") id = strings.TrimPrefix(id, "run/") return exec.Command( @@ -478,7 +481,7 @@ func (p *Platform) Launchers() []platforms.Launcher { Id: "Generic", Extensions: []string{".exe", ".bat", ".cmd", ".lnk", ".a3x"}, AllowListOnly: true, - Launch: func(cfg *config.UserConfig, path string) error { + Launch: func(cfg *config.Instance, path string) error { return exec.Command("cmd", "/c", path).Start() }, }, @@ -486,7 +489,7 @@ func (p *Platform) Launchers() []platforms.Launcher { Id: "LaunchBox", Schemes: []string{"launchbox"}, Scanner: func( - cfg *config.UserConfig, + cfg *config.Instance, systemId string, results []platforms.ScanResult, ) ([]platforms.ScanResult, error) { @@ -542,7 +545,7 @@ func (p *Platform) Launchers() []platforms.Launcher { return results, nil }, - Launch: func(cfg *config.UserConfig, path string) error { + Launch: func(cfg *config.Instance, path string) error { lbDir, err := findLaunchBoxDir() if err != nil { return err diff --git a/pkg/readers/acr122_pcsc/acr122_pcsc.go b/pkg/readers/acr122_pcsc/acr122_pcsc.go index 266a7abd..c3f93de8 100644 --- a/pkg/readers/acr122_pcsc/acr122_pcsc.go +++ b/pkg/readers/acr122_pcsc/acr122_pcsc.go @@ -4,11 +4,11 @@ import ( "bytes" "encoding/hex" "errors" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "strings" "time" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/readers" "github.com/ZaparooProject/zaparoo-core/pkg/utils" "github.com/ebfe/scard" @@ -16,14 +16,14 @@ import ( ) type Acr122Pcsc struct { - cfg *config.UserConfig + cfg *config.Instance device string name string polling bool ctx *scard.Context } -func NewAcr122Pcsc(cfg *config.UserConfig) *Acr122Pcsc { +func NewAcr122Pcsc(cfg *config.Instance) *Acr122Pcsc { return &Acr122Pcsc{ cfg: cfg, } diff --git a/pkg/readers/acr122_pcsc/ndef.go b/pkg/readers/acr122_pcsc/ndef.go index 2c63d9ea..f8d878f4 100644 --- a/pkg/readers/acr122_pcsc/ndef.go +++ b/pkg/readers/acr122_pcsc/ndef.go @@ -1,22 +1,22 @@ /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package acr122_pcsc diff --git a/pkg/readers/file/file.go b/pkg/readers/file/file.go index 4c16f2d6..6a5d94f5 100644 --- a/pkg/readers/file/file.go +++ b/pkg/readers/file/file.go @@ -3,13 +3,13 @@ package file import ( "encoding/hex" "errors" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "os" "path/filepath" "strings" "time" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/readers" "github.com/ZaparooProject/zaparoo-core/pkg/utils" "github.com/rs/zerolog/log" @@ -18,13 +18,13 @@ import ( const TokenType = "file" type Reader struct { - cfg *config.UserConfig + cfg *config.Instance device string path string polling bool } -func NewReader(cfg *config.UserConfig) *Reader { +func NewReader(cfg *config.Instance) *Reader { return &Reader{ cfg: cfg, } diff --git a/pkg/readers/libnfc/libnfc.go b/pkg/readers/libnfc/libnfc.go index 0abbbcfe..8bf6837e 100644 --- a/pkg/readers/libnfc/libnfc.go +++ b/pkg/readers/libnfc/libnfc.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "errors" "fmt" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "os" "path/filepath" @@ -13,7 +14,6 @@ import ( "sync" "time" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/readers" "github.com/ZaparooProject/zaparoo-core/pkg/readers/libnfc/tags" "github.com/ZaparooProject/zaparoo-core/pkg/utils" @@ -41,7 +41,7 @@ type WriteRequest struct { } type Reader struct { - cfg *config.UserConfig + cfg *config.Instance conn string pnd *nfc.Device polling bool @@ -49,7 +49,7 @@ type Reader struct { write chan WriteRequest } -func NewReader(cfg *config.UserConfig) *Reader { +func NewReader(cfg *config.Instance) *Reader { return &Reader{ cfg: cfg, write: make(chan WriteRequest), @@ -149,7 +149,7 @@ func (r *Reader) Ids() []string { } func (r *Reader) Detect(connected []string) string { - if !r.cfg.GetProbeDevice() { + if !r.cfg.Readers().AutoDetect { return "" } diff --git a/pkg/readers/libnfc/tags/mifare.go b/pkg/readers/libnfc/tags/mifare.go index c021d1a7..742ad210 100644 --- a/pkg/readers/libnfc/tags/mifare.go +++ b/pkg/readers/libnfc/tags/mifare.go @@ -1,23 +1,23 @@ //go:build (linux || darwin) && cgo /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package tags diff --git a/pkg/readers/libnfc/tags/ndef.go b/pkg/readers/libnfc/tags/ndef.go index 7e1abdf4..d3acb9f4 100644 --- a/pkg/readers/libnfc/tags/ndef.go +++ b/pkg/readers/libnfc/tags/ndef.go @@ -1,24 +1,24 @@ //go:build (linux || darwin) && cgo /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package tags diff --git a/pkg/readers/libnfc/tags/ndef_test.go b/pkg/readers/libnfc/tags/ndef_test.go index 1fffbbc3..9858120a 100644 --- a/pkg/readers/libnfc/tags/ndef_test.go +++ b/pkg/readers/libnfc/tags/ndef_test.go @@ -1,23 +1,23 @@ //go:build (linux || darwin) && cgo /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package tags diff --git a/pkg/readers/libnfc/tags/ntag.go b/pkg/readers/libnfc/tags/ntag.go index 1f2ae6de..70a3bf6a 100644 --- a/pkg/readers/libnfc/tags/ntag.go +++ b/pkg/readers/libnfc/tags/ntag.go @@ -1,23 +1,23 @@ //go:build (linux || darwin) && cgo /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package tags diff --git a/pkg/readers/libnfc/tags/tags.go b/pkg/readers/libnfc/tags/tags.go index ffeca9f3..0da7ce74 100644 --- a/pkg/readers/libnfc/tags/tags.go +++ b/pkg/readers/libnfc/tags/tags.go @@ -1,24 +1,24 @@ //go:build (linux || darwin) && cgo /* -TapTo +Zaparoo Core Copyright (C) 2023, 2024 Callan Barrett Copyright (C) 2023 Gareth Jones -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package tags diff --git a/pkg/readers/optical_drive/optical_drive.go b/pkg/readers/optical_drive/optical_drive.go index 341c57f7..2d06df9f 100644 --- a/pkg/readers/optical_drive/optical_drive.go +++ b/pkg/readers/optical_drive/optical_drive.go @@ -17,13 +17,13 @@ import ( const TokenType = "disc" type FileReader struct { - cfg *config.UserConfig + cfg *config.Instance device string path string polling bool } -func NewReader(cfg *config.UserConfig) *FileReader { +func NewReader(cfg *config.Instance) *FileReader { return &FileReader{ cfg: cfg, } diff --git a/pkg/readers/pn532_uart/ndef.go b/pkg/readers/pn532_uart/ndef.go index be7e30fa..fdfd50f7 100644 --- a/pkg/readers/pn532_uart/ndef.go +++ b/pkg/readers/pn532_uart/ndef.go @@ -1,22 +1,22 @@ /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package pn532_uart diff --git a/pkg/readers/pn532_uart/pn532_uart.go b/pkg/readers/pn532_uart/pn532_uart.go index 82b49c5e..e408ee6b 100644 --- a/pkg/readers/pn532_uart/pn532_uart.go +++ b/pkg/readers/pn532_uart/pn532_uart.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "errors" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "os" "path/filepath" @@ -12,7 +13,6 @@ import ( "sync" "time" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/readers" "github.com/ZaparooProject/zaparoo-core/pkg/utils" "github.com/rs/zerolog/log" @@ -21,7 +21,7 @@ import ( ) type Pn532UartReader struct { - cfg *config.UserConfig + cfg *config.Instance device string name string polling bool @@ -29,7 +29,7 @@ type Pn532UartReader struct { lastToken *tokens.Token } -func NewReader(cfg *config.UserConfig) *Pn532UartReader { +func NewReader(cfg *config.Instance) *Pn532UartReader { return &Pn532UartReader{ cfg: cfg, } diff --git a/pkg/readers/simple_serial/simple_serial.go b/pkg/readers/simple_serial/simple_serial.go index 12fe324f..bdd1f73e 100644 --- a/pkg/readers/simple_serial/simple_serial.go +++ b/pkg/readers/simple_serial/simple_serial.go @@ -2,13 +2,13 @@ package simple_serial import ( "errors" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "os" "runtime" "strings" "time" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/readers" "github.com/ZaparooProject/zaparoo-core/pkg/utils" "github.com/rs/zerolog/log" @@ -17,7 +17,7 @@ import ( ) type SimpleSerialReader struct { - cfg *config.UserConfig + cfg *config.Instance device string path string polling bool @@ -25,7 +25,7 @@ type SimpleSerialReader struct { lastToken *tokens.Token } -func NewReader(cfg *config.UserConfig) *SimpleSerialReader { +func NewReader(cfg *config.Instance) *SimpleSerialReader { return &SimpleSerialReader{ cfg: cfg, } diff --git a/pkg/service/mappings.go b/pkg/service/mappings.go index 63575c86..d9824597 100644 --- a/pkg/service/mappings.go +++ b/pkg/service/mappings.go @@ -1,22 +1,22 @@ /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package service diff --git a/pkg/service/readers.go b/pkg/service/readers.go index 0a9fcf8e..61417946 100644 --- a/pkg/service/readers.go +++ b/pkg/service/readers.go @@ -2,11 +2,11 @@ package service import ( "errors" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "strings" "time" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" "github.com/ZaparooProject/zaparoo-core/pkg/readers" "github.com/ZaparooProject/zaparoo-core/pkg/service/state" @@ -15,11 +15,11 @@ import ( ) func shouldExit( - cfg *config.UserConfig, + cfg *config.Instance, pl platforms.Platform, st *state.State, ) bool { - if !cfg.GetExitGame() { + if !cfg.HoldModeEnabled() { return false } @@ -41,7 +41,7 @@ func shouldExit( func connectReaders( pl platforms.Platform, - cfg *config.UserConfig, + cfg *config.Instance, st *state.State, iq chan<- readers.Scan, ) error { @@ -51,16 +51,11 @@ func connectReaders( // TODO: this needs to gather the final list of reader paths, resolve any // symlinks, remove duplicates, and then connect to them - userDevice := cfg.GetConnectionString() - if userDevice != "" && !utils.Contains(rs, userDevice) { - log.Debug().Msgf("user device not connected, adding: %s", userDevice) - toConnect = append(toConnect, userDevice) - } - - for _, device := range cfg.GetReader() { - if !utils.Contains(rs, device) && !utils.Contains(toConnect, device) { + for _, device := range cfg.Readers().Connect { + connStr := device.Driver + ":" + device.Path + if !utils.Contains(rs, connStr) && !utils.Contains(toConnect, connStr) { log.Debug().Msgf("config device not connected, adding: %s", device) - toConnect = append(toConnect, device) + toConnect = append(toConnect, connStr) } } @@ -127,7 +122,7 @@ func connectReaders( func readerManager( pl platforms.Platform, - cfg *config.UserConfig, + cfg *config.Instance, st *state.State, itq chan<- tokens.Token, lsq chan *tokens.Token, @@ -157,7 +152,7 @@ func readerManager( } } - timerLen := time.Second * time.Duration(cfg.GetExitGameDelay()) + timerLen := time.Second * time.Duration(cfg.ReadersScan().ExitDelay) log.Debug().Msgf("exit timer set to: %s seconds", timerLen) exitTimer = time.NewTimer(timerLen) diff --git a/pkg/service/service.go b/pkg/service/service.go index 07248794..8d8478c4 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -1,22 +1,22 @@ /* -TapTo +Zaparoo Core Copyright (C) 2023 Gareth Jones Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package service @@ -26,6 +26,7 @@ import ( "github.com/ZaparooProject/zaparoo-core/pkg/api" "github.com/ZaparooProject/zaparoo-core/pkg/service/playlists" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" + "os" "strings" "time" @@ -33,15 +34,15 @@ import ( "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/database" - "github.com/ZaparooProject/zaparoo-core/pkg/launcher" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" "github.com/ZaparooProject/zaparoo-core/pkg/service/state" + "github.com/ZaparooProject/zaparoo-core/pkg/zapscript" "github.com/rs/zerolog/log" ) -func inExitGameBlocklist(platform platforms.Platform, cfg *config.UserConfig) bool { +func inExitGameBlocklist(platform platforms.Platform, cfg *config.Instance) bool { var blocklist []string - for _, v := range cfg.GetExitGameBlocklist() { + for _, v := range cfg.ReadersScan().IgnoreSystem { blocklist = append(blocklist, strings.ToLower(v)) } return slices.Contains(blocklist, strings.ToLower(platform.GetActiveLauncher())) @@ -49,7 +50,7 @@ func inExitGameBlocklist(platform platforms.Platform, cfg *config.UserConfig) bo func launchToken( platform platforms.Platform, - cfg *config.UserConfig, + cfg *config.Instance, token tokens.Token, db *database.Database, lsq chan<- *tokens.Token, @@ -71,12 +72,12 @@ func launchToken( cmds := strings.Split(text, "||") for i, cmd := range cmds { - err, softwareSwap := launcher.LaunchToken( + err, softwareSwap := zapscript.LaunchToken( platform, cfg, plsc, token, - cfg.GetAllowCommands() || mapped, + mapped, cmd, len(cmds), i, @@ -96,7 +97,7 @@ func launchToken( func processTokenQueue( platform platforms.Platform, - cfg *config.UserConfig, + cfg *config.Instance, st *state.State, itq <-chan tokens.Token, db *database.Database, @@ -219,58 +220,63 @@ func processTokenQueue( } func Start( - platform platforms.Platform, - cfg *config.UserConfig, + pl platforms.Platform, + cfg *config.Instance, ) (func() error, error) { + dirs := []string{pl.DataDir(), pl.TempDir()} + for _, dir := range dirs { + err := os.MkdirAll(dir, 0755) + if err != nil { + return nil, err + } + } + // TODO: define the notifications chan here instead of in state - st, ns := state.NewState(platform) + st, ns := state.NewState(pl) // TODO: convert this to a *token channel itq := make(chan tokens.Token) lsq := make(chan *tokens.Token) plq := make(chan *playlists.Playlist) - log.Info().Msgf("Zaparoo v%s", config.Version) - log.Info().Msgf("config path = %s", cfg.IniPath) - log.Info().Msgf("app path = %s", cfg.AppPath) - log.Info().Msgf("connection_string = %s", cfg.GetConnectionString()) - log.Info().Msgf("allow_commands = %t", cfg.GetAllowCommands()) - log.Info().Msgf("disable_sounds = %t", cfg.GetDisableSounds()) - log.Info().Msgf("probe_device = %t", cfg.GetProbeDevice()) - log.Info().Msgf("exit_game = %t", cfg.GetExitGame()) - log.Info().Msgf("exit_game_blocklist = %s", cfg.GetExitGameBlocklist()) - log.Info().Msgf("debug = %t", cfg.GetDebug()) - - log.Debug().Msg("opening database") - db, err := database.Open(platform) + log.Info().Msg("running platform pre start") + err := pl.StartPre(cfg) if err != nil { - log.Error().Err(err).Msgf("error opening database") + log.Error().Err(err).Msg("platform start pre error") return nil, err } - log.Debug().Msg("starting API service") - go api.Start(platform, cfg, st, itq, db, ns) - - log.Debug().Msg("running platform setup") - err = platform.Setup(cfg, st.Notifications) + log.Info().Msg("opening database") + db, err := database.Open(pl) if err != nil { - log.Error().Msgf("error setting up platform: %s", err) + log.Error().Err(err).Msgf("error opening database") return nil, err } - if !platform.LaunchingEnabled() { + log.Info().Msg("starting API service") + go api.Start(pl, cfg, st, itq, db, ns) + + if !pl.LaunchingEnabled() { + log.Warn().Msg("launching disabled") st.DisableLauncher() } - log.Debug().Msg("starting reader manager") - go readerManager(platform, cfg, st, itq, lsq) + log.Info().Msg("starting reader manager") + go readerManager(pl, cfg, st, itq, lsq) + + log.Info().Msg("starting token queue manager") + go processTokenQueue(pl, cfg, st, itq, db, lsq, plq) - log.Debug().Msg("starting token queue manager") - go processTokenQueue(platform, cfg, st, itq, db, lsq, plq) + log.Info().Msg("running platform post start") + err = pl.StartPost(cfg, st.Notifications) + if err != nil { + log.Error().Err(err).Msg("platform start pre error") + return nil, err + } return func() error { - err = platform.Stop() + err = pl.Stop() if err != nil { - log.Warn().Msgf("error stopping platform: %s", err) + log.Warn().Msgf("error stopping pl: %s", err) } st.StopService() close(plq) diff --git a/pkg/utils/logging.go b/pkg/utils/logging.go index 28325744..a6a630f0 100644 --- a/pkg/utils/logging.go +++ b/pkg/utils/logging.go @@ -7,39 +7,27 @@ import ( "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" - "github.com/rs/zerolog" "github.com/rs/zerolog/log" "gopkg.in/natefinch/lumberjack.v2" ) -func InitLogging(cfg *config.UserConfig, pl platforms.Platform) error { - logFile := filepath.Join(pl.LogFolder(), config.LogFilename) - - err := os.MkdirAll(filepath.Dir(logFile), 0755) +func InitLogging(pl platforms.Platform, writers []io.Writer) error { + err := os.MkdirAll(pl.LogDir(), 0755) if err != nil { return err } - var BaseLogWriters = []io.Writer{&lumberjack.Logger{ - Filename: logFile, + var logWriters = []io.Writer{&lumberjack.Logger{ + Filename: filepath.Join(pl.LogDir(), config.LogFile), MaxSize: 1, MaxBackups: 2, }} - if cfg.TapTo.ConsoleLogging { - // BaseLogWriters = append(BaseLogWriters, zerolog.ConsoleWriter{Out: os.Stderr}) - BaseLogWriters = append(BaseLogWriters, os.Stderr) + if len(writers) > 0 { + logWriters = append(logWriters, writers...) } - zerolog.TimeFieldFormat = zerolog.TimeFormatUnix - - log.Logger = log.Output(io.MultiWriter(BaseLogWriters...)) - - if cfg.GetDebug() { - zerolog.SetGlobalLevel(zerolog.DebugLevel) - } else { - zerolog.SetGlobalLevel(zerolog.InfoLevel) - } + log.Logger = log.Output(io.MultiWriter(logWriters...)) return nil } diff --git a/pkg/utils/paths.go b/pkg/utils/paths.go index bce214ab..abdfe94b 100644 --- a/pkg/utils/paths.go +++ b/pkg/utils/paths.go @@ -13,7 +13,7 @@ import ( // PathIsLauncher returns true if a given path matches against any of the // criteria defined in a launcher. func PathIsLauncher( - cfg *config.UserConfig, + cfg *config.Instance, pl platforms.Platform, l platforms.Launcher, path string, @@ -39,7 +39,7 @@ func PathIsLauncher( // check root folder if it's not a generic launcher if len(l.Folders) > 0 { inRoot := false - for _, folder := range pl.RootFolders(cfg) { + for _, folder := range pl.RootDirs(cfg) { if strings.HasPrefix(lp, strings.ToLower(folder)) { inRoot = true break @@ -66,7 +66,7 @@ func PathIsLauncher( // MatchSystemFile returns true if a given path is for a given system. func MatchSystemFile( - cfg *config.UserConfig, + cfg *config.Instance, pl platforms.Platform, systemId string, path string, @@ -84,7 +84,7 @@ func MatchSystemFile( // PathToLaunchers is a reverse lookup to match a given path against all // possible launchers in a platform. Returns all matched launchers. func PathToLaunchers( - cfg *config.UserConfig, + cfg *config.Instance, pl platforms.Platform, path string, ) []platforms.Launcher { diff --git a/pkg/utils/service.go b/pkg/utils/service.go index 6711c17d..0f23a580 100644 --- a/pkg/utils/service.go +++ b/pkg/utils/service.go @@ -35,6 +35,11 @@ type ServiceArgs struct { } func NewService(args ServiceArgs) (*Service, error) { + err := os.MkdirAll(args.Platform.TempDir(), 0755) + if err != nil { + return nil, err + } + return &Service{ daemon: !args.NoDaemon, start: args.Entry, @@ -44,7 +49,7 @@ func NewService(args ServiceArgs) (*Service, error) { // Create new PID file using current process PID. func (s *Service) createPidFile() error { - path := filepath.Join(config.TempDir(), config.PidFilename) + path := filepath.Join(s.pl.TempDir(), config.PidFile) pid := os.Getpid() err := os.WriteFile(path, []byte(fmt.Sprintf("%d", pid)), 0644) if err != nil { @@ -54,7 +59,7 @@ func (s *Service) createPidFile() error { } func (s *Service) removePidFile() error { - err := os.Remove(filepath.Join(config.TempDir(), config.PidFilename)) + err := os.Remove(filepath.Join(s.pl.TempDir(), config.PidFile)) if err != nil { return err } @@ -64,7 +69,7 @@ func (s *Service) removePidFile() error { // Pid returns the process ID of the current running service daemon. func (s *Service) Pid() (int, error) { pid := 0 - path := filepath.Join(config.TempDir(), config.PidFilename) + path := filepath.Join(s.pl.TempDir(), config.PidFile) if _, err := os.Stat(path); err == nil { pidFile, err := os.ReadFile(path) @@ -123,7 +128,7 @@ func (s *Service) stopService() error { tempPath, err := os.Executable() if err != nil { log.Error().Err(err).Msg("error getting executable path") - } else if strings.HasPrefix(tempPath, config.TempDir()) { + } else if strings.HasPrefix(tempPath, s.pl.TempDir()) { err = os.Remove(tempPath) if err != nil { log.Error().Err(err).Msg("error removing temporary binary") @@ -206,7 +211,7 @@ func (s *Service) Start() error { // create a copy in binary in tmp so the original can be updated binPath := "" - appPath := os.Getenv(config.UserAppPathEnv) + appPath := os.Getenv(config.AppEnv) if appPath != "" { binPath = appPath } else { @@ -222,7 +227,7 @@ func (s *Service) Start() error { return fmt.Errorf("error opening binary: %w", err) } - tempPath := filepath.Join(config.TempDir(), filepath.Base(binPath)) + tempPath := filepath.Join(s.pl.TempDir(), filepath.Base(binPath)) tempFile, err := os.OpenFile(tempPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) if err != nil { return fmt.Errorf("error creating temp binary: %w", err) @@ -247,12 +252,12 @@ func (s *Service) Start() error { cmd.Env = env // point new binary to existing config file - configPath := filepath.Join(filepath.Dir(binPath), config.UserConfigFilename) + configPath := filepath.Join(s.pl.ConfigDir(), config.CfgFile) if _, err := os.Stat(configPath); err == nil { - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", config.UserConfigEnv, configPath)) + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", config.CfgEnv, configPath)) } - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", config.UserAppPathEnv, binPath)) + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", config.AppEnv, binPath)) err = cmd.Start() if err != nil { diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 12860e0d..6b20c310 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1,21 +1,21 @@ /* -TapTo +Zaparoo Core Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ package utils diff --git a/pkg/launcher/commands.go b/pkg/zapscript/commands.go similarity index 90% rename from pkg/launcher/commands.go rename to pkg/zapscript/commands.go index c7d5c07c..46e6a51a 100644 --- a/pkg/launcher/commands.go +++ b/pkg/zapscript/commands.go @@ -1,27 +1,29 @@ /* -TapTo +Zaparoo Core Copyright (C) 2023, 2024 Callan Barrett -This file is part of TapTo. +This file is part of Zaparoo Core. -TapTo is free software: you can redistribute it and/or modify +Zaparoo Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -TapTo is distributed in the hope that it will be useful, +Zaparoo Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with TapTo. If not, see . +along with Zaparoo Core. If not, see . */ -package launcher +package zapscript import ( + "errors" "fmt" + "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/service/playlists" "github.com/ZaparooProject/zaparoo-core/pkg/service/tokens" "net/url" @@ -33,7 +35,6 @@ import ( "github.com/rs/zerolog/log" - "github.com/ZaparooProject/zaparoo-core/pkg/config" "github.com/ZaparooProject/zaparoo-core/pkg/platforms" ) @@ -92,7 +93,7 @@ func forwardCmd(pl platforms.Platform, env platforms.CmdEnv) error { } // Check all games folders for a relative path to a file -func findFile(pl platforms.Platform, cfg *config.UserConfig, path string) (string, error) { +func findFile(pl platforms.Platform, cfg *config.Instance, path string) (string, error) { // TODO: can do basic file exists check here too if filepath.IsAbs(path) { return path, nil @@ -104,7 +105,7 @@ func findFile(pl platforms.Platform, cfg *config.UserConfig, path string) (strin // if the file is inside a zip or virtual list, we just check that file exists // TODO: both of these things are very specific to mister, it would be good to // have a more generic way of handling this for other platforms, or - // implement them from tapto(?) + // implement them from zaparoo(?) for i, p := range ps { ext := filepath.Ext(strings.ToLower(p)) if ext == ".zip" || ext == ".txt" { @@ -114,7 +115,7 @@ func findFile(pl platforms.Platform, cfg *config.UserConfig, path string) (strin } } - for _, gf := range pl.RootFolders(cfg) { + for _, gf := range pl.RootDirs(cfg) { fullPath := filepath.Join(gf, statPath) if _, err := os.Stat(fullPath); err == nil { log.Debug().Msgf("found file: %s", fullPath) @@ -131,7 +132,7 @@ func findFile(pl platforms.Platform, cfg *config.UserConfig, path string) (strin */ func LaunchToken( pl platforms.Platform, - cfg *config.UserConfig, + cfg *config.Instance, plsc playlists.PlaylistController, t tokens.Token, manual bool, @@ -188,12 +189,18 @@ func LaunchToken( if f, ok := commandMappings[cmd]; ok { log.Info().Msgf("launching command: %s", cmd) + + if cmd == "shell" && !cfg.IsShellCmdAllowed(args) { + return errors.New("shell command not allowed"), false + } + softwareChange := slices.Contains(softwareChangeCommands, cmd) if softwareChange { // a launch triggered outside a playlist itself log.Debug().Msg("clearing current playlist") plsc.Queue <- nil } + return f(pl, env), softwareChange } else { return fmt.Errorf("unknown command: %s", cmd), false diff --git a/pkg/launcher/http.go b/pkg/zapscript/http.go similarity index 98% rename from pkg/launcher/http.go rename to pkg/zapscript/http.go index acd45fe7..81260d5b 100644 --- a/pkg/launcher/http.go +++ b/pkg/zapscript/http.go @@ -1,4 +1,4 @@ -package launcher +package zapscript import ( "fmt" diff --git a/pkg/launcher/input.go b/pkg/zapscript/input.go similarity index 99% rename from pkg/launcher/input.go rename to pkg/zapscript/input.go index 0c10cc27..abe42b48 100644 --- a/pkg/launcher/input.go +++ b/pkg/zapscript/input.go @@ -1,4 +1,4 @@ -package launcher +package zapscript import ( "fmt" diff --git a/pkg/launcher/launch.go b/pkg/zapscript/launch.go similarity index 99% rename from pkg/launcher/launch.go rename to pkg/zapscript/launch.go index f7f522de..768d5e0f 100644 --- a/pkg/launcher/launch.go +++ b/pkg/zapscript/launch.go @@ -1,4 +1,4 @@ -package launcher +package zapscript import ( "fmt" diff --git a/pkg/launcher/utils.go b/pkg/zapscript/utils.go similarity index 96% rename from pkg/launcher/utils.go rename to pkg/zapscript/utils.go index 0af68437..33dab01c 100644 --- a/pkg/launcher/utils.go +++ b/pkg/zapscript/utils.go @@ -1,4 +1,4 @@ -package launcher +package zapscript import ( "fmt" diff --git a/scripts/mister/build/Dockerfile b/scripts/mister/build/Dockerfile index 431bcdda..241d984e 100755 --- a/scripts/mister/build/Dockerfile +++ b/scripts/mister/build/Dockerfile @@ -1,5 +1,4 @@ -# glibc in this version matches mister -FROM arm32v7/debian:bullseye-backports +FROM arm32v7/debian:bookworm-backports RUN apt-get update -y && apt-get upgrade -y @@ -11,7 +10,7 @@ RUN apt-get install -y ca-certificates openssl && \ # install go and app dependencies RUN apt-get install build-essential git curl wget ncurses-dev -y && \ - apt-get install golang-doc/bullseye-backports golang-go/bullseye-backports golang-src/bullseye-backports golang/bullseye-backports -y + apt-get install golang-doc/bookworm-backports golang-go/bookworm-backports golang-src/bookworm-backports golang/bookworm-backports -y RUN mkdir /internal # install pcsc-lite and ccid dependencies diff --git a/scripts/mister/build/build.sh b/scripts/mister/build/build.sh index b9ad3c85..7f74268e 100644 --- a/scripts/mister/build/build.sh +++ b/scripts/mister/build/build.sh @@ -7,4 +7,4 @@ export CGO_LDFLAGS="-lpcsclite -lnfc -lusb -lcurses" go build \ --ldflags "-linkmode external -extldflags -static -s -w" \ - -o _build/mister_arm/tapto.sh ./cmd/mister + -o _build/mister_arm/zaparoo.sh ./cmd/mister diff --git a/scripts/mister/repo/generate.py b/scripts/mister/repo/generate.py index 4700854e..9ec0a580 100644 --- a/scripts/mister/repo/generate.py +++ b/scripts/mister/repo/generate.py @@ -9,12 +9,12 @@ from typing import TypedDict, Union, Optional, List DB_ID = "mrext/tapto" -DL_URL_PREFIX = "https://github.com/wizzomafizzo/tapto/releases/download/{}" -ZIP_FILENAME = "tapto-mister_arm-{}.zip" +DL_URL_PREFIX = "https://github.com/ZaparooProject/zaparoo-core/releases/download/{}" +ZIP_FILENAME = "zaparoo-mister_arm-{}.zip" SCRATCH_FOLDER = "_scratch" REPO_FOLDER = "scripts/mister/repo" FILES = [ - "tapto.sh", + "zaparoo.sh", ] @@ -80,7 +80,7 @@ class RepoDb(TypedDict): zips: dict[str, RepoDbZipsItem] -def create_tapto_db(tag: str) -> RepoDb: +def create_zaparoo_db(tag: str) -> RepoDb: zip_filename = ZIP_FILENAME.format(tag[1:]) folders: dict[str, RepoDbZipFilesItem] = {