From 9790f72ae783d26932ce6ac4bbe3dfacbcec9820 Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Wed, 27 Nov 2024 21:02:25 +0800 Subject: [PATCH] Add initial concept of playlists (#119) * Add deprecated "random" command as a software change command. * Add playlist management to service and launcher * Refactor token imports to new service package. * Playlist launching working. * Add playlist navigation commands and token source checks * Refactor TokenQueue to use channels and remove queue.go --- pkg/api/methods/launch.go | 8 +- pkg/api/models/requests/requests.go | 4 +- pkg/api/server.go | 8 +- pkg/launcher/commands.go | 30 +++++- pkg/launcher/launch.go | 55 +++++++++++ pkg/platforms/batocera/platform.go | 2 +- pkg/platforms/mac/platform.go | 2 +- pkg/platforms/mister/platform.go | 6 +- pkg/platforms/mister/socket.go | 2 +- pkg/platforms/mistex/platform.go | 2 +- pkg/platforms/platforms.go | 4 +- pkg/platforms/windows/platform.go | 2 +- pkg/readers/acr122_pcsc/acr122_pcsc.go | 2 +- pkg/readers/file/file.go | 2 +- pkg/readers/libnfc/libnfc.go | 2 +- pkg/readers/libnfc/tags/mifare.go | 2 +- pkg/readers/libnfc/tags/ntag.go | 2 +- pkg/readers/libnfc/tags/tags.go | 2 +- pkg/readers/optical_drive/optical_drive.go | 2 +- pkg/readers/pn532_uart/pn532.go | 2 +- pkg/readers/pn532_uart/pn532_uart.go | 2 +- pkg/readers/readers.go | 2 +- pkg/readers/simple_serial/simple_serial.go | 2 +- pkg/service/mappings.go | 2 +- pkg/service/playlists/playlists.go | 44 +++++++++ pkg/service/readers.go | 12 +-- pkg/service/service.go | 103 ++++++++++++++++++--- pkg/service/state/state.go | 2 +- pkg/{ => service}/tokens/tokens.go | 1 + pkg/tokens/queue.go | 23 ----- pkg/utils/utils.go | 3 +- 31 files changed, 259 insertions(+), 78 deletions(-) create mode 100644 pkg/service/playlists/playlists.go rename pkg/{ => service}/tokens/tokens.go (90%) delete mode 100644 pkg/tokens/queue.go diff --git a/pkg/api/methods/launch.go b/pkg/api/methods/launch.go index 155dea83..3d088295 100644 --- a/pkg/api/methods/launch.go +++ b/pkg/api/methods/launch.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/wizzomafizzo/tapto/pkg/api/models" "github.com/wizzomafizzo/tapto/pkg/api/models/requests" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "golang.org/x/text/unicode/norm" "net/http" "net/url" @@ -13,7 +14,6 @@ import ( "github.com/go-chi/chi/v5" "github.com/rs/zerolog/log" "github.com/wizzomafizzo/tapto/pkg/service/state" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) var ( @@ -83,7 +83,7 @@ func HandleLaunch(env requests.RequestEnv) (any, error) { // TODO: how do we report back errors? put channel in queue env.State.SetActiveCard(t) - env.TokenQueue.Enqueue(t) + env.TokenQueue <- t return nil, nil } @@ -91,7 +91,7 @@ func HandleLaunch(env requests.RequestEnv) (any, error) { // TODO: this is still insecure func HandleLaunchBasic( st *state.State, - tq *tokens.TokenQueue, + itq chan<- tokens.Token, ) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { log.Info().Msg("received basic launch request") @@ -113,7 +113,7 @@ func HandleLaunchBasic( } st.SetActiveCard(t) - tq.Enqueue(t) + itq <- t } } diff --git a/pkg/api/models/requests/requests.go b/pkg/api/models/requests/requests.go index 77d6cda1..50637350 100644 --- a/pkg/api/models/requests/requests.go +++ b/pkg/api/models/requests/requests.go @@ -6,7 +6,7 @@ import ( "github.com/wizzomafizzo/tapto/pkg/database" "github.com/wizzomafizzo/tapto/pkg/platforms" "github.com/wizzomafizzo/tapto/pkg/service/state" - "github.com/wizzomafizzo/tapto/pkg/tokens" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" ) type RequestEnv struct { @@ -14,7 +14,7 @@ type RequestEnv struct { Config *config.UserConfig State *state.State Database *database.Database - TokenQueue *tokens.TokenQueue + TokenQueue chan<- tokens.Token IsLocal bool Id uuid.UUID Params []byte diff --git a/pkg/api/server.go b/pkg/api/server.go index 268d28e8..442540d4 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -7,6 +7,7 @@ import ( "github.com/wizzomafizzo/tapto/pkg/api/methods" "github.com/wizzomafizzo/tapto/pkg/api/models" "github.com/wizzomafizzo/tapto/pkg/api/models/requests" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "net" "net/http" "strings" @@ -22,7 +23,6 @@ import ( "github.com/wizzomafizzo/tapto/pkg/database" "github.com/wizzomafizzo/tapto/pkg/platforms" "github.com/wizzomafizzo/tapto/pkg/service/state" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) // TODO: should there be a TTL for request timestamps? what about offline misters? @@ -132,7 +132,7 @@ func Start( pl platforms.Platform, cfg *config.UserConfig, st *state.State, - tq *tokens.TokenQueue, + itq chan<- tokens.Token, db *database.Database, ns <-chan models.Notification, ) { @@ -229,7 +229,7 @@ func Start( Config: cfg, State: st, Database: db, - TokenQueue: tq, + TokenQueue: itq, IsLocal: clientIp.IsLoopback(), }, req) if err != nil { @@ -262,7 +262,7 @@ func Start( }) // TODO: use allow list - r.Get("/l/*", methods.HandleLaunchBasic(st, tq)) + r.Get("/l/*", methods.HandleLaunchBasic(st, itq)) err := http.ListenAndServe(":"+cfg.Api.Port, r) if err != nil { diff --git a/pkg/launcher/commands.go b/pkg/launcher/commands.go index 7b3e2217..88b0f8d6 100644 --- a/pkg/launcher/commands.go +++ b/pkg/launcher/commands.go @@ -22,6 +22,8 @@ package launcher import ( "fmt" + "github.com/wizzomafizzo/tapto/pkg/service/playlists" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "net/url" "os" "path/filepath" @@ -44,6 +46,10 @@ var commandMappings = map[string]func(platforms.Platform, platforms.CmdEnv) erro "launch.random": cmdRandom, "launch.search": cmdSearch, + "playlist.play": cmdPlaylistPlay, + "playlist.next": cmdPlaylistNext, + "playlist.previous": cmdPlaylistPrevious, + "shell": cmdShell, "delay": cmdDelay, @@ -72,6 +78,7 @@ var commandMappings = map[string]func(platforms.Platform, platforms.CmdEnv) erro } var softwareChangeCommands = []string{ + "random", // DEPRECATED "launch", "launch.system", "launch.random", @@ -125,6 +132,8 @@ func findFile(pl platforms.Platform, cfg *config.UserConfig, path string) (strin func LaunchToken( pl platforms.Platform, cfg *config.UserConfig, + plsc playlists.PlaylistController, + t tokens.Token, manual bool, text string, totalCommands int, @@ -152,6 +161,11 @@ func LaunchToken( // explicit commands must begin with ** if strings.HasPrefix(text, "**") { + if t.Source == tokens.SourcePlaylist { + log.Debug().Str("text", text).Msgf("playlists cannot run commands, skipping") + return nil, false + } + text = strings.TrimPrefix(text, "**") ps := strings.SplitN(text, ":", 2) if len(ps) < 2 { @@ -165,6 +179,7 @@ func LaunchToken( Args: args, NamedArgs: namedArgs, Cfg: cfg, + Playlist: plsc, Manual: manual, Text: text, TotalCommands: totalCommands, @@ -172,12 +187,25 @@ func LaunchToken( } if f, ok := commandMappings[cmd]; ok { - return f(pl, env), slices.Contains(softwareChangeCommands, cmd) + log.Info().Msgf("launching command: %s", cmd) + 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 } } + if t.Source != tokens.SourcePlaylist { + // a launch triggered outside a playlist itself + log.Debug().Msg("clearing current playlist") + plsc.Queue <- nil + } + // if it's not a command, treat it as a generic launch command return cmdLaunch(pl, platforms.CmdEnv{ Cmd: "launch", diff --git a/pkg/launcher/launch.go b/pkg/launcher/launch.go index 03d4a5a2..3f3c02d0 100644 --- a/pkg/launcher/launch.go +++ b/pkg/launcher/launch.go @@ -2,6 +2,7 @@ package launcher import ( "fmt" + "github.com/wizzomafizzo/tapto/pkg/service/playlists" "os" "path/filepath" "regexp" @@ -292,3 +293,57 @@ func cmdSearch(pl platforms.Platform, env platforms.CmdEnv) error { return launch(res[0].Path) } + +func cmdPlaylistPlay(_ platforms.Platform, env platforms.CmdEnv) error { + if env.Args == "" { + return fmt.Errorf("no playlist path specified") + } + + if _, err := os.Stat(env.Args); err != nil { + return err + } + + files, err := os.ReadDir(env.Args) + if err != nil { + return err + } + + media := make([]string, 0) + for _, file := range files { + if file.IsDir() || filepath.Ext(file.Name()) == "" { + continue + } + + media = append(media, filepath.Join(env.Args, file.Name())) + } + + if len(media) == 0 { + return fmt.Errorf("no media found in: %s", env.Args) + } + + log.Info().Any("media", media).Msgf("new playlist: %s", env.Args) + pls := playlists.NewPlaylist(media) + env.Playlist.Queue <- pls + + return nil +} + +func cmdPlaylistNext(_ platforms.Platform, env platforms.CmdEnv) error { + if env.Playlist.Active == nil { + return fmt.Errorf("no playlist active") + } + + env.Playlist.Queue <- playlists.Next(*env.Playlist.Active) + + return nil +} + +func cmdPlaylistPrevious(_ platforms.Platform, env platforms.CmdEnv) error { + if env.Playlist.Active == nil { + return fmt.Errorf("no playlist active") + } + + env.Playlist.Queue <- playlists.Previous(*env.Playlist.Active) + + return nil +} diff --git a/pkg/platforms/batocera/platform.go b/pkg/platforms/batocera/platform.go index 22e2b681..6c46489c 100644 --- a/pkg/platforms/batocera/platform.go +++ b/pkg/platforms/batocera/platform.go @@ -3,6 +3,7 @@ package batocera import ( "errors" "github.com/wizzomafizzo/tapto/pkg/api/models" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "os" "os/exec" "path/filepath" @@ -16,7 +17,6 @@ import ( "github.com/wizzomafizzo/tapto/pkg/readers/file" "github.com/wizzomafizzo/tapto/pkg/readers/libnfc" "github.com/wizzomafizzo/tapto/pkg/readers/simple_serial" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) type Platform struct { diff --git a/pkg/platforms/mac/platform.go b/pkg/platforms/mac/platform.go index cf11e4bc..d451ef59 100644 --- a/pkg/platforms/mac/platform.go +++ b/pkg/platforms/mac/platform.go @@ -2,6 +2,7 @@ package mac import ( "github.com/wizzomafizzo/tapto/pkg/api/models" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "os" "os/exec" "path/filepath" @@ -13,7 +14,6 @@ import ( "github.com/wizzomafizzo/tapto/pkg/readers/file" "github.com/wizzomafizzo/tapto/pkg/readers/pn532_uart" "github.com/wizzomafizzo/tapto/pkg/readers/simple_serial" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) type Platform struct { diff --git a/pkg/platforms/mister/platform.go b/pkg/platforms/mister/platform.go index 88933d95..be7ffc15 100644 --- a/pkg/platforms/mister/platform.go +++ b/pkg/platforms/mister/platform.go @@ -9,6 +9,7 @@ import ( "github.com/wizzomafizzo/tapto/pkg/api/models" "github.com/wizzomafizzo/tapto/pkg/database/gamesdb" "github.com/wizzomafizzo/tapto/pkg/readers/optical_drive" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "os" "os/exec" "path/filepath" @@ -29,7 +30,6 @@ import ( "github.com/wizzomafizzo/tapto/pkg/readers/file" "github.com/wizzomafizzo/tapto/pkg/readers/libnfc" "github.com/wizzomafizzo/tapto/pkg/readers/simple_serial" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) type Platform struct { @@ -178,7 +178,9 @@ func (p *Platform) Stop() error { } } - p.stopSocket() + if p.stopSocket != nil { + p.stopSocket() + } return nil } diff --git a/pkg/platforms/mister/socket.go b/pkg/platforms/mister/socket.go index fd0eb510..7e1a778d 100644 --- a/pkg/platforms/mister/socket.go +++ b/pkg/platforms/mister/socket.go @@ -4,12 +4,12 @@ package mister import ( "fmt" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "net" "strings" "github.com/rs/zerolog/log" "github.com/wizzomafizzo/tapto/pkg/readers" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) const ( diff --git a/pkg/platforms/mistex/platform.go b/pkg/platforms/mistex/platform.go index 0d3130fb..b41d1bfc 100644 --- a/pkg/platforms/mistex/platform.go +++ b/pkg/platforms/mistex/platform.go @@ -5,6 +5,7 @@ package mistex import ( "fmt" "github.com/wizzomafizzo/tapto/pkg/api/models" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "os" "os/exec" "path/filepath" @@ -23,7 +24,6 @@ import ( "github.com/wizzomafizzo/tapto/pkg/readers/file" "github.com/wizzomafizzo/tapto/pkg/readers/libnfc" "github.com/wizzomafizzo/tapto/pkg/readers/simple_serial" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) type Platform struct { diff --git a/pkg/platforms/platforms.go b/pkg/platforms/platforms.go index 3773fb9b..905d52d1 100644 --- a/pkg/platforms/platforms.go +++ b/pkg/platforms/platforms.go @@ -2,12 +2,13 @@ package platforms import ( "github.com/wizzomafizzo/tapto/pkg/api/models" + "github.com/wizzomafizzo/tapto/pkg/service/playlists" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "path/filepath" "strings" "github.com/wizzomafizzo/tapto/pkg/config" "github.com/wizzomafizzo/tapto/pkg/readers" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) type CmdEnv struct { @@ -15,6 +16,7 @@ type CmdEnv struct { Args string NamedArgs map[string]string Cfg *config.UserConfig + Playlist playlists.PlaylistController Manual bool Text string TotalCommands int diff --git a/pkg/platforms/windows/platform.go b/pkg/platforms/windows/platform.go index 120d2a76..50ae99bd 100644 --- a/pkg/platforms/windows/platform.go +++ b/pkg/platforms/windows/platform.go @@ -4,6 +4,7 @@ import ( "encoding/xml" "errors" "fmt" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "io" "os" "os/exec" @@ -22,7 +23,6 @@ import ( "github.com/wizzomafizzo/tapto/pkg/readers/file" "github.com/wizzomafizzo/tapto/pkg/readers/pn532_uart" "github.com/wizzomafizzo/tapto/pkg/readers/simple_serial" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) type Platform struct { diff --git a/pkg/readers/acr122_pcsc/acr122_pcsc.go b/pkg/readers/acr122_pcsc/acr122_pcsc.go index 1d5563ab..9c04df1b 100644 --- a/pkg/readers/acr122_pcsc/acr122_pcsc.go +++ b/pkg/readers/acr122_pcsc/acr122_pcsc.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "errors" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "strings" "time" @@ -11,7 +12,6 @@ import ( "github.com/rs/zerolog/log" "github.com/wizzomafizzo/tapto/pkg/config" "github.com/wizzomafizzo/tapto/pkg/readers" - "github.com/wizzomafizzo/tapto/pkg/tokens" "github.com/wizzomafizzo/tapto/pkg/utils" ) diff --git a/pkg/readers/file/file.go b/pkg/readers/file/file.go index 77b30111..99660189 100644 --- a/pkg/readers/file/file.go +++ b/pkg/readers/file/file.go @@ -3,6 +3,7 @@ package file import ( "encoding/hex" "errors" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "os" "path/filepath" "strings" @@ -11,7 +12,6 @@ import ( "github.com/rs/zerolog/log" "github.com/wizzomafizzo/tapto/pkg/config" "github.com/wizzomafizzo/tapto/pkg/readers" - "github.com/wizzomafizzo/tapto/pkg/tokens" "github.com/wizzomafizzo/tapto/pkg/utils" ) diff --git a/pkg/readers/libnfc/libnfc.go b/pkg/readers/libnfc/libnfc.go index c90b30f0..bdab9593 100644 --- a/pkg/readers/libnfc/libnfc.go +++ b/pkg/readers/libnfc/libnfc.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "errors" "fmt" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "os" "path/filepath" "strings" @@ -17,7 +18,6 @@ import ( "github.com/wizzomafizzo/tapto/pkg/config" "github.com/wizzomafizzo/tapto/pkg/readers" "github.com/wizzomafizzo/tapto/pkg/readers/libnfc/tags" - "github.com/wizzomafizzo/tapto/pkg/tokens" "github.com/wizzomafizzo/tapto/pkg/utils" ) diff --git a/pkg/readers/libnfc/tags/mifare.go b/pkg/readers/libnfc/tags/mifare.go index adfb7a78..a43659dd 100644 --- a/pkg/readers/libnfc/tags/mifare.go +++ b/pkg/readers/libnfc/tags/mifare.go @@ -28,9 +28,9 @@ import ( "errors" "fmt" "github.com/rs/zerolog/log" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "github.com/clausecker/nfc/v2" - "github.com/wizzomafizzo/tapto/pkg/tokens" "golang.org/x/exp/slices" ) diff --git a/pkg/readers/libnfc/tags/ntag.go b/pkg/readers/libnfc/tags/ntag.go index e082f82e..ede7968d 100644 --- a/pkg/readers/libnfc/tags/ntag.go +++ b/pkg/readers/libnfc/tags/ntag.go @@ -27,10 +27,10 @@ import ( "encoding/hex" "errors" "fmt" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "github.com/clausecker/nfc/v2" "github.com/rs/zerolog/log" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) const ( diff --git a/pkg/readers/libnfc/tags/tags.go b/pkg/readers/libnfc/tags/tags.go index 53a68a8d..f9c9390d 100644 --- a/pkg/readers/libnfc/tags/tags.go +++ b/pkg/readers/libnfc/tags/tags.go @@ -26,9 +26,9 @@ package tags import ( "encoding/hex" "fmt" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "github.com/clausecker/nfc/v2" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) const ( diff --git a/pkg/readers/optical_drive/optical_drive.go b/pkg/readers/optical_drive/optical_drive.go index fa9ec027..c6387d3c 100644 --- a/pkg/readers/optical_drive/optical_drive.go +++ b/pkg/readers/optical_drive/optical_drive.go @@ -5,7 +5,7 @@ import ( "github.com/rs/zerolog/log" "github.com/wizzomafizzo/tapto/pkg/config" "github.com/wizzomafizzo/tapto/pkg/readers" - "github.com/wizzomafizzo/tapto/pkg/tokens" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "github.com/wizzomafizzo/tapto/pkg/utils" "os" "os/exec" diff --git a/pkg/readers/pn532_uart/pn532.go b/pkg/readers/pn532_uart/pn532.go index bf8e805f..420258f0 100644 --- a/pkg/readers/pn532_uart/pn532.go +++ b/pkg/readers/pn532_uart/pn532.go @@ -4,10 +4,10 @@ import ( "bytes" "errors" "fmt" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "time" "github.com/rs/zerolog/log" - "github.com/wizzomafizzo/tapto/pkg/tokens" "go.bug.st/serial" ) diff --git a/pkg/readers/pn532_uart/pn532_uart.go b/pkg/readers/pn532_uart/pn532_uart.go index 5f2e4f7a..c41b9726 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/wizzomafizzo/tapto/pkg/service/tokens" "os" "path/filepath" "runtime" @@ -14,7 +15,6 @@ import ( "github.com/rs/zerolog/log" "github.com/wizzomafizzo/tapto/pkg/config" "github.com/wizzomafizzo/tapto/pkg/readers" - "github.com/wizzomafizzo/tapto/pkg/tokens" "github.com/wizzomafizzo/tapto/pkg/utils" "go.bug.st/serial" diff --git a/pkg/readers/readers.go b/pkg/readers/readers.go index be7ef716..d57bb440 100644 --- a/pkg/readers/readers.go +++ b/pkg/readers/readers.go @@ -1,7 +1,7 @@ package readers import ( - "github.com/wizzomafizzo/tapto/pkg/tokens" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" ) type Scan struct { diff --git a/pkg/readers/simple_serial/simple_serial.go b/pkg/readers/simple_serial/simple_serial.go index 084de50e..1bd802f1 100644 --- a/pkg/readers/simple_serial/simple_serial.go +++ b/pkg/readers/simple_serial/simple_serial.go @@ -2,6 +2,7 @@ package simple_serial import ( "errors" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "os" "runtime" "strings" @@ -10,7 +11,6 @@ import ( "github.com/rs/zerolog/log" "github.com/wizzomafizzo/tapto/pkg/config" "github.com/wizzomafizzo/tapto/pkg/readers" - "github.com/wizzomafizzo/tapto/pkg/tokens" "github.com/wizzomafizzo/tapto/pkg/utils" "go.bug.st/serial" diff --git a/pkg/service/mappings.go b/pkg/service/mappings.go index 8df8602f..8eca39f2 100644 --- a/pkg/service/mappings.go +++ b/pkg/service/mappings.go @@ -22,13 +22,13 @@ along with TapTo. If not, see . package service import ( + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "regexp" "strings" "github.com/rs/zerolog/log" "github.com/wizzomafizzo/tapto/pkg/database" "github.com/wizzomafizzo/tapto/pkg/platforms" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) func checkMappingUid(m database.Mapping, t tokens.Token) bool { diff --git a/pkg/service/playlists/playlists.go b/pkg/service/playlists/playlists.go new file mode 100644 index 00000000..0d1b4b5b --- /dev/null +++ b/pkg/service/playlists/playlists.go @@ -0,0 +1,44 @@ +package playlists + +type Playlist struct { + Media []string + Index int +} + +func NewPlaylist(media []string) *Playlist { + return &Playlist{ + Media: media, + Index: 0, + } +} + +func Next(p Playlist) *Playlist { + idx := p.Index + 1 + if idx >= len(p.Media) { + idx = 0 + } + return &Playlist{ + Media: p.Media, + Index: idx, + } +} + +func Previous(p Playlist) *Playlist { + idx := p.Index - 1 + if idx < 0 { + idx = len(p.Media) - 1 + } + return &Playlist{ + Media: p.Media, + Index: idx, + } +} + +func (p *Playlist) Current() string { + return p.Media[p.Index] +} + +type PlaylistController struct { + Active *Playlist + Queue chan<- *Playlist +} diff --git a/pkg/service/readers.go b/pkg/service/readers.go index 8765d518..a9ee86d5 100644 --- a/pkg/service/readers.go +++ b/pkg/service/readers.go @@ -2,6 +2,7 @@ package service import ( "errors" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "strings" "time" @@ -10,7 +11,6 @@ import ( "github.com/wizzomafizzo/tapto/pkg/platforms" "github.com/wizzomafizzo/tapto/pkg/readers" "github.com/wizzomafizzo/tapto/pkg/service/state" - "github.com/wizzomafizzo/tapto/pkg/tokens" "github.com/wizzomafizzo/tapto/pkg/utils" ) @@ -129,8 +129,8 @@ func readerManager( pl platforms.Platform, cfg *config.UserConfig, st *state.State, - launchQueue *tokens.TokenQueue, - softwareQueue chan *tokens.Token, + itq chan<- tokens.Token, + lsq chan *tokens.Token, ) { inputQueue := make(chan readers.Scan) @@ -175,7 +175,7 @@ func readerManager( log.Warn().Msgf("error killing launcher: %s", err) } - softwareQueue <- nil + lsq <- nil }() } @@ -218,7 +218,7 @@ func readerManager( continue } scan = t.Token - case stoken := <-softwareQueue: + case stoken := <-lsq: // a token has been launched that starts software log.Debug().Msgf("new software token: %v", st) @@ -265,7 +265,7 @@ func readerManager( log.Info().Msgf("sending token: %v", scan) pl.PlaySuccessSound(cfg) - launchQueue.Enqueue(*scan) + itq <- *scan } } else { log.Info().Msg("token was removed") diff --git a/pkg/service/service.go b/pkg/service/service.go index 2a1f67d2..3a039c17 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -24,6 +24,8 @@ package service import ( "fmt" "github.com/wizzomafizzo/tapto/pkg/api" + "github.com/wizzomafizzo/tapto/pkg/service/playlists" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "strings" "time" @@ -35,7 +37,6 @@ import ( "github.com/wizzomafizzo/tapto/pkg/launcher" "github.com/wizzomafizzo/tapto/pkg/platforms" "github.com/wizzomafizzo/tapto/pkg/service/state" - "github.com/wizzomafizzo/tapto/pkg/tokens" ) func inExitGameBlocklist(platform platforms.Platform, cfg *config.UserConfig) bool { @@ -52,6 +53,7 @@ func launchToken( token tokens.Token, db *database.Database, lsq chan<- *tokens.Token, + plsc playlists.PlaylistController, ) error { text := token.Text @@ -72,6 +74,8 @@ func launchToken( err, softwareSwap := launcher.LaunchToken( platform, cfg, + plsc, + token, cfg.GetAllowCommands() || mapped, cmd, len(cmds), @@ -90,17 +94,75 @@ func launchToken( return nil } -func processLaunchQueue( +func processTokenQueue( platform platforms.Platform, cfg *config.UserConfig, st *state.State, - tq *tokens.TokenQueue, + itq <-chan tokens.Token, db *database.Database, lsq chan<- *tokens.Token, + plq chan *playlists.Playlist, ) { + var activePlaylist *playlists.Playlist + for { select { - case t := <-tq.Tokens: + case pls := <-plq: + log.Info().Msgf("processing playlist update: %v", pls) + + if pls == nil { + if activePlaylist != nil { + log.Info().Msg("clearing active playlist") + } else { + log.Debug().Msg("no active playlist to clear") + } + activePlaylist = nil + continue + } else if activePlaylist == nil { + log.Info().Msg("setting new active playlist, launching token") + activePlaylist = pls + go func() { + t := tokens.Token{ + Text: pls.Current(), + ScanTime: time.Now(), + Source: tokens.SourcePlaylist, + } + plsc := playlists.PlaylistController{ + Active: activePlaylist, + Queue: plq, + } + err := launchToken(platform, cfg, t, db, lsq, plsc) + if err != nil { + log.Error().Err(err).Msgf("error launching token") + } + }() + continue + } else { + if pls.Current() == activePlaylist.Current() { + log.Debug().Msg("playlist current token unchanged, skipping") + continue + } + + log.Info().Msg("updating active playlist, launching token") + activePlaylist = pls + go func() { + t := tokens.Token{ + Text: pls.Current(), + ScanTime: time.Now(), + Source: tokens.SourcePlaylist, + } + plsc := playlists.PlaylistController{ + Active: activePlaylist, + Queue: plq, + } + err := launchToken(platform, cfg, t, db, lsq, plsc) + if err != nil { + log.Error().Err(err).Msgf("error launching token") + } + }() + continue + } + case t := <-itq: // TODO: change this channel to send a token pointer or something if t.ScanTime.IsZero() { // ignore empty tokens @@ -132,7 +194,12 @@ func processLaunchQueue( // launch tokens in separate thread go func() { - err = launchToken(platform, cfg, t, db, lsq) + plsc := playlists.PlaylistController{ + Active: activePlaylist, + Queue: plq, + } + + err = launchToken(platform, cfg, t, db, lsq, plsc) if err != nil { log.Error().Err(err).Msgf("error launching token") } @@ -145,8 +212,7 @@ func processLaunchQueue( }() case <-time.After(100 * time.Millisecond): if st.ShouldStopService() { - tq.Close() - return + break } } } @@ -156,12 +222,14 @@ func Start( platform platforms.Platform, cfg *config.UserConfig, ) (func() error, error) { - // TODO: define the models chan here instead of in state + // TODO: define the notifications chan here instead of in state st, ns := state.NewState(platform) - tq := tokens.NewTokenQueue() // TODO: convert this to a *token channel + // 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("TapTo v%s", config.Version) + 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()) @@ -180,7 +248,7 @@ func Start( } log.Debug().Msg("starting API service") - go api.Start(platform, cfg, st, tq, db, ns) + go api.Start(platform, cfg, st, itq, db, ns) log.Debug().Msg("running platform setup") err = platform.Setup(cfg, st.Notifications) @@ -193,16 +261,21 @@ func Start( st.DisableLauncher() } - go readerManager(platform, cfg, st, tq, lsq) - go processLaunchQueue(platform, cfg, st, tq, db, lsq) + log.Debug().Msg("starting reader manager") + go readerManager(platform, cfg, st, itq, lsq) + + log.Debug().Msg("starting token queue manager") + go processTokenQueue(platform, cfg, st, itq, db, lsq, plq) return func() error { - tq.Close() - st.StopService() err = platform.Stop() if err != nil { log.Warn().Msgf("error stopping platform: %s", err) } + st.StopService() + close(plq) + close(lsq) + close(itq) return nil }, nil } diff --git a/pkg/service/state/state.go b/pkg/service/state/state.go index 592d7116..3b10f5e0 100644 --- a/pkg/service/state/state.go +++ b/pkg/service/state/state.go @@ -2,12 +2,12 @@ package state import ( "github.com/wizzomafizzo/tapto/pkg/api/models" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "sync" "github.com/rs/zerolog/log" "github.com/wizzomafizzo/tapto/pkg/platforms" "github.com/wizzomafizzo/tapto/pkg/readers" - "github.com/wizzomafizzo/tapto/pkg/tokens" "github.com/wizzomafizzo/tapto/pkg/utils" ) diff --git a/pkg/tokens/tokens.go b/pkg/service/tokens/tokens.go similarity index 90% rename from pkg/tokens/tokens.go rename to pkg/service/tokens/tokens.go index dbc4c0a8..1e68efbb 100644 --- a/pkg/tokens/tokens.go +++ b/pkg/service/tokens/tokens.go @@ -17,4 +17,5 @@ const ( TypeMifare = "MIFARE" TypeAmiibo = "Amiibo" TypeLegoDimensions = "LegoDimensions" + SourcePlaylist = "Playlist" ) diff --git a/pkg/tokens/queue.go b/pkg/tokens/queue.go deleted file mode 100644 index 7394c8cb..00000000 --- a/pkg/tokens/queue.go +++ /dev/null @@ -1,23 +0,0 @@ -package tokens - -type TokenQueue struct { - Tokens chan Token -} - -func (q *TokenQueue) Enqueue(t Token) { - q.Tokens <- t -} - -func (q *TokenQueue) Dequeue() Token { - return <-q.Tokens -} - -func (q *TokenQueue) Close() { - close(q.Tokens) -} - -func NewTokenQueue() *TokenQueue { - return &TokenQueue{ - Tokens: make(chan Token), - } -} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index de8daed8..baf332a2 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -25,6 +25,7 @@ import ( "crypto/md5" "fmt" "github.com/rs/zerolog/log" + "github.com/wizzomafizzo/tapto/pkg/service/tokens" "io" "math/rand" "net" @@ -34,8 +35,6 @@ import ( "sort" "strings" "time" - - "github.com/wizzomafizzo/tapto/pkg/tokens" ) var r = rand.New(rand.NewSource(time.Now().UnixNano()))