Skip to content

Commit

Permalink
feat: multiple
Browse files Browse the repository at this point in the history
- feat: settings singleton in core
- feat: sources model for multiple sources of media
- feat: auto discover http URL of server
  • Loading branch information
ItsNotGoodName committed Nov 6, 2023
1 parent 4901d26 commit 5feb15e
Show file tree
Hide file tree
Showing 30 changed files with 787 additions and 92 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ tmp
.env
dist
radiomux.json
radiomux.json.tmp
radiomux
radiomux-demo
4 changes: 2 additions & 2 deletions cmd/radiomux-demo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ func run(cfg *demo.Config) lieut.Executor {
androidWSServer := demo.NewAndroidWSServer()
notificationServer := apiws.NewNotificationServer(bus, playerStore)
apiWSServer := apiws.NewServer(androidStateService, playerStore, notificationServer)
apiServer := api.NewServer(playerStore, androidWSServer)
apiServer := api.NewServer(playerStore, nil)
playerService := webrpc.
NewPlayerServiceServer(rpc.
NewPlayerService(playerStore, androidWSServer))
NewPlayerService(playerStore))
presetService := webrpc.
NewPresetServiceServer(rpc.
NewPresetService(presetStore))
Expand Down
18 changes: 11 additions & 7 deletions cmd/radiomux/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import (
"github.com/ItsNotGoodName/radiomux/internal/build"
"github.com/ItsNotGoodName/radiomux/internal/bus"
"github.com/ItsNotGoodName/radiomux/internal/config"
"github.com/ItsNotGoodName/radiomux/internal/file"
"github.com/ItsNotGoodName/radiomux/internal/core"
"github.com/ItsNotGoodName/radiomux/internal/http"
"github.com/ItsNotGoodName/radiomux/internal/jsondb"
"github.com/ItsNotGoodName/radiomux/internal/rpc"
"github.com/ItsNotGoodName/radiomux/internal/webrpc"
"github.com/ItsNotGoodName/radiomux/pkg/sutureext"
Expand Down Expand Up @@ -55,6 +56,8 @@ func run(cfg *config.Config) lieut.Executor {
return fmt.Errorf("failed to parse config: %w", err)
}

core.Init(cfg.HTTPURL)

// Supervisor
super := suture.New("root", suture.Spec{
EventHook: sutureext.EventHook(),
Expand All @@ -65,21 +68,22 @@ func run(cfg *config.Config) lieut.Executor {
androidStatePubSub := android.NewStateMemPubSub()

// Store
jsonStore := file.NewStore(cfg.File)
playerStore := file.NewPlayerStore(jsonStore, bus)
presetStore := file.NewPresetStore(jsonStore, bus)
jsonStore := jsondb.NewStore(cfg.File)
playerStore := jsondb.NewPlayerStore(jsonStore, bus)
presetStore := jsondb.NewPresetStore(jsonStore, bus)
sourceStore := jsondb.NewSourceStore(jsonStore)
androidStateStore := android.NewStateMemStore(androidStatePubSub, bus, playerStore)

// Services
androidStateService := android.NewStateService(androidStatePubSub, androidStateStore)
androidController := android.NewController(androidStateService, bus)
androidWSServer := androidws.NewServer(playerStore, androidController, androidStateService, cfg.HTTPURL)
androidWSServer := androidws.NewServer(playerStore, androidController, androidStateService, cfg.HTTPURLRaw)
notificationServer := apiws.NewNotificationServer(bus, playerStore)
apiWSServer := apiws.NewServer(androidStateService, playerStore, notificationServer)
apiServer := api.NewServer(playerStore, androidWSServer)
apiServer := api.NewServer(playerStore, sourceStore)
playerService := webrpc.
NewPlayerServiceServer(rpc.
NewPlayerService(playerStore, androidWSServer))
NewPlayerService(playerStore))
presetService := webrpc.
NewPresetServiceServer(rpc.
NewPresetService(presetStore))
Expand Down
4 changes: 4 additions & 0 deletions cmd/scratch/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package main

func main() {
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.21
require (
github.com/Rican7/lieut v0.1.1
github.com/caarlos0/env/v9 v9.0.0
github.com/cyphar/filepath-securejoin v0.2.4
github.com/gorilla/websocket v1.5.0
github.com/labstack/echo/v4 v4.11.1
github.com/oapi-codegen/runtime v1.0.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvF
github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc=
github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down
7 changes: 0 additions & 7 deletions internal/androidws/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package androidws

import (
"errors"
"fmt"

"github.com/ItsNotGoodName/radiomux/internal"
"github.com/ItsNotGoodName/radiomux/internal/android"
Expand All @@ -26,12 +25,6 @@ func NewServer(playerStore core.PlayerStore, controller *android.Controller, bus
}
}

const Path = "/api/android/ws"

func (s Server) PlayerWSURL(p core.Player) string {
return fmt.Sprintf("%s%s?id=%d&token=%s", s.wsURL, Path, p.ID, p.Token)
}

func (s Server) ServeEcho(c echo.Context) error {
ctx := c.Request().Context()

Expand Down
37 changes: 28 additions & 9 deletions internal/api/server.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
package api

import (
"context"
"net/http"

"github.com/ItsNotGoodName/radiomux/internal/core"
"github.com/ItsNotGoodName/radiomux/internal/openapi"
"github.com/cyphar/filepath-securejoin"
echo "github.com/labstack/echo/v4"
qrcode "github.com/skip2/go-qrcode"
)

func NewServer(playerStore core.PlayerStore, androidWSServer core.AndroidWSServer) *Server {
type SourceStore interface {
GetFileSource(ctx context.Context, id int64) (core.FileSource, error)
}

func NewServer(playerStore core.PlayerStore, sourceStore SourceStore) *Server {
return &Server{
playerStore: playerStore,
androidWSServer: androidWSServer,
playerStore: playerStore,
sourceStore: sourceStore,
}
}

type Server struct {
playerStore core.PlayerStore
androidWSServer core.AndroidWSServer
playerStore core.PlayerStore
sourceStore SourceStore
}

func (s *Server) GetSourcesIdSlug(c echo.Context, id int64, slug string) error {
ctx := c.Request().Context()

source, err := s.sourceStore.GetFileSource(ctx, id)
if err != nil {
return err
}

securePath, err := securejoin.SecureJoin(source.Path, slug)
if err != nil {
return err
}

return c.File(securePath)
}

func (s *Server) GetPlayersIdQr(c echo.Context, id int64) error {
Expand All @@ -30,7 +51,7 @@ func (s *Server) GetPlayersIdQr(c echo.Context, id int64) error {
}

var png []byte
url := s.androidWSServer.PlayerWSURL(player)
url := core.Settings.PlayerWSURL(player)
png, err = qrcode.Encode(url, qrcode.Medium, 256)
if err != nil {
return err
Expand All @@ -39,5 +60,3 @@ func (s *Server) GetPlayersIdQr(c echo.Context, id int64) error {
c.Response().Header().Set("Cache-Control", "no-store")
return c.Blob(http.StatusOK, "image/png", png)
}

var _ openapi.ServerInterface = (*Server)(nil)
40 changes: 34 additions & 6 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ package config

import (
"flag"
"fmt"
"net/url"

"github.com/ItsNotGoodName/radiomux/internal/core"
"github.com/caarlos0/env/v9"
"github.com/rs/zerolog/log"
)

type Config struct {
File string `env:"RADIOMUX_FILE"`
HTTPHost string `env:"RADIOMUX_HTTP_HOST"`
HTTPPort int `env:"RADIOMUX_HTTP_PORT"`
HTTPURL string `env:"RADIOMUX_HTTP_URL"`
File string `env:"RADIOMUX_FILE"`
HTTPHost string `env:"RADIOMUX_HTTP_HOST"`
HTTPPort int `env:"RADIOMUX_HTTP_PORT"`
HTTPURL *url.URL `env:"-"`
HTTPURLRaw string `env:"RADIOMUX_HTTP_URL"`
}

var Default = struct {
Expand All @@ -33,9 +38,32 @@ func (c *Config) WithFlag(flags *flag.FlagSet) {

flags.StringVar(&c.HTTPHost, "http-host", "", "HTTP host to listen on.")
flags.IntVar(&c.HTTPPort, "http-port", Default.HTTPPort, "HTTP port to listen on.")
flags.StringVar(&c.HTTPURL, "http-url", "", "HTTP public URL (e.g. http://127.0.0.1:8080).")
flags.StringVar(&c.HTTPURLRaw, "http-url", "", "HTTP public URL (e.g. http://127.0.0.1:8080).")
}

func (c *Config) Parse() error {
return env.Parse(c)
err := env.Parse(c)
if err != nil {
return err
}

if c.HTTPURLRaw == "" {
ips, err := core.PossiblePublicIPs()
if err != nil {
log.Err(err).Caller().Msg("Failed to list public ips")
} else if len(ips) > 0 {
ip := ips[0]
c.HTTPURL, err = url.Parse(fmt.Sprintf("http://%s:%d", ip, c.HTTPPort))
if err != nil {
return err
}
}
} else {
c.HTTPURL, err = url.Parse(c.HTTPURLRaw)
if err != nil {
return err
}
}

return nil
}
39 changes: 24 additions & 15 deletions internal/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package core

import (
"context"

"github.com/ItsNotGoodName/radiomux/pkg/pagination"
)

type Player struct {
Expand All @@ -24,25 +26,32 @@ type PlayerStore interface {
Drop(ctx context.Context) ([]Player, error)
}

type Preset struct {
ID int64
Name string
URL string
type FileSource struct {
ID int64
Name string
Path string
Readonly bool
}

func (p Preset) URI() string {
return p.URL
type File struct {
SourceID int64
Path string
Directory bool
}

type PresetStore interface {
Create(ctx context.Context, req Preset) (Preset, error)
Get(ctx context.Context, id int64) (Preset, error)
List(ctx context.Context) ([]Preset, error)
Update(ctx context.Context, req Preset) (Preset, error)
Delete(ctx context.Context, id int64) error
Drop(ctx context.Context) ([]Preset, error)
type FileListRequest struct {
Page pagination.Page
}

type FileListResponse struct {
Items []File
PageResult pagination.PageResult
}

type AndroidWSServer interface {
PlayerWSURL(p Player) string
type SubsonicSource struct {
ID int64
Name string
Address string
Username string
Password string
}
19 changes: 19 additions & 0 deletions internal/core/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package core
import (
"crypto/rand"
"encoding/base64"
"net"
"strings"
)

func GenerateToken() (string, error) {
Expand All @@ -14,3 +16,20 @@ func GenerateToken() (string, error) {

return base64.URLEncoding.EncodeToString(secret), nil
}

func PossiblePublicIPs() ([]net.IP, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}

var ips []net.IP
for _, addr := range addrs {
ip := net.ParseIP(strings.Split(addr.String(), "/")[0])
if ip.To4() != nil && ip.String() != "127.0.0.1" {
ips = append(ips, ip)
}
}

return ips, nil
}
Loading

0 comments on commit 5feb15e

Please sign in to comment.