Update config manager

This commit is contained in:
Sergey Stepanov 2023-04-22 16:53:39 +03:00 committed by sergystepanov
parent c13099c56a
commit 8893e1e5bf
38 changed files with 319 additions and 243 deletions

View file

@ -1,7 +1,7 @@
package main
import (
config "github.com/giongto35/cloud-game/v3/pkg/config/coordinator"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/coordinator"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/os"
@ -10,7 +10,7 @@ import (
var Version = "?"
func main() {
conf := config.NewConfig()
conf := config.NewCoordinatorConfig()
conf.ParseFlags()
log := logger.NewConsole(conf.Coordinator.Debug, "c", false)

View file

@ -3,7 +3,7 @@ package main
import (
"time"
config "github.com/giongto35/cloud-game/v3/pkg/config/worker"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/os"
"github.com/giongto35/cloud-game/v3/pkg/worker"
@ -13,7 +13,7 @@ import (
var Version = "?"
func run() {
conf := config.NewConfig()
conf := config.NewWorkerConfig()
conf.ParseFlags()
log := logger.NewConsole(conf.Worker.Debug, "w", false)

8
go.mod
View file

@ -9,7 +9,8 @@ require (
github.com/goccy/go-json v0.10.2
github.com/gofrs/flock v0.8.1
github.com/gorilla/websocket v1.5.0
github.com/kkyr/fig v0.3.1
github.com/knadh/koanf/maps v0.1.1
github.com/knadh/koanf/v2 v2.0.1
github.com/pion/interceptor v0.1.12
github.com/pion/logging v0.2.2
github.com/pion/webrtc/v3 v3.1.60
@ -18,14 +19,16 @@ require (
github.com/veandco/go-sdl2 v0.4.34
golang.org/x/crypto v0.8.0
golang.org/x/image v0.7.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/google/uuid v1.3.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.2.6 // indirect
github.com/pion/ice/v2 v2.3.2 // indirect
@ -45,5 +48,4 @@ require (
golang.org/x/net v0.9.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

12
go.sum
View file

@ -34,8 +34,10 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/kkyr/fig v0.3.1 h1:GqsamO9dwY05t2xh6ubzjPPYw2It4hoWbKZEWmDxM0o=
github.com/kkyr/fig v0.3.1/go.mod h1:ItUILF8IIzgZOMhx5xpJ1W/bviQsWRKOwKXfE/tqUoA=
github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g=
github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -48,8 +50,12 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -59,8 +65,6 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8=
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
github.com/pion/dtls/v2 v2.2.6 h1:yXMxKr0Skd+Ub6A8UqXTRLSywskx93ooMRHsQUtd+Z4=

66
pkg/config/coordinator.go Normal file
View file

@ -0,0 +1,66 @@
package config
import "flag"
type CoordinatorConfig struct {
Coordinator Coordinator
Emulator Emulator
Recording Recording
Version Version
Webrtc Webrtc
}
type Coordinator struct {
Analytics Analytics
Debug bool
Library Library
Monitoring Monitoring
Origin struct {
UserWs string
WorkerWs string
}
Selector string
Server Server
}
type Library struct {
// some directory which is going to be
// the root folder for the library
BasePath string
// a list of supported file extensions
Supported []string
// a list of ignored words in the files
Ignored []string
// print some additional info
Verbose bool
// enable directory changes watch
WatchMode bool
}
func (l Library) GetSupportedExtensions() []string { return l.Supported }
// Analytics is optional Google Analytics
type Analytics struct {
Inject bool
Gtag string
}
const SelectByPing = "ping"
// allows custom config path
var coordinatorConfigPath string
func NewCoordinatorConfig() (conf CoordinatorConfig) {
err := LoadConfig(&conf, coordinatorConfigPath)
if err != nil {
panic(err)
}
return
}
func (c *CoordinatorConfig) ParseFlags() {
c.Coordinator.Server.WithFlags()
flag.IntVar(&c.Coordinator.Monitoring.Port, "monitoring.port", c.Coordinator.Monitoring.Port, "Monitoring server port")
flag.StringVar(&coordinatorConfigPath, "c-conf", coordinatorConfigPath, "Set custom configuration file path")
flag.Parse()
}

View file

@ -1,59 +0,0 @@
package coordinator
import (
"flag"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/config/emulator"
"github.com/giongto35/cloud-game/v3/pkg/config/monitoring"
"github.com/giongto35/cloud-game/v3/pkg/config/shared"
"github.com/giongto35/cloud-game/v3/pkg/config/webrtc"
"github.com/giongto35/cloud-game/v3/pkg/games"
)
type Config struct {
Coordinator Coordinator
Emulator emulator.Emulator
Recording shared.Recording
Version shared.Version
Webrtc webrtc.Webrtc
}
type Coordinator struct {
Analytics Analytics
Debug bool
Library games.Config
Monitoring monitoring.Config
Origin struct {
UserWs string
WorkerWs string
}
Selector string
Server shared.Server
}
// Analytics is optional Google Analytics
type Analytics struct {
Inject bool
Gtag string
}
const SelectByPing = "ping"
// allows custom config path
var configPath string
func NewConfig() (conf Config) {
err := config.LoadConfig(&conf, configPath)
if err != nil {
panic(err)
}
return
}
func (c *Config) ParseFlags() {
c.Coordinator.Server.WithFlags()
flag.IntVar(&c.Coordinator.Monitoring.Port, "monitoring.port", c.Coordinator.Monitoring.Port, "Monitoring server port")
flag.StringVar(&configPath, "c-conf", configPath, "Set custom configuration file path")
flag.Parse()
}

View file

@ -1,4 +1,4 @@
package emulator
package config
import (
"math"

View file

@ -1,4 +1,4 @@
package emulator
package config
import "testing"

View file

@ -1,26 +0,0 @@
package encoder
type Encoder struct {
Audio Audio
Video Video
}
type Audio struct {
Frame int
}
type Video struct {
Codec string
Concurrency int
H264 struct {
Crf uint8
Preset string
Profile string
Tune string
LogLevel int
}
Vpx struct {
Bitrate uint
KeyframeInterval uint
}
}

View file

@ -2,16 +2,69 @@ package config
import (
"os"
"path/filepath"
"strings"
"github.com/kkyr/fig"
"github.com/knadh/koanf/maps"
"github.com/knadh/koanf/v2"
"gopkg.in/yaml.v3"
)
const EnvPrefix = "CLOUD_GAME"
const EnvPrefix = "CLOUD_GAME_"
type File string
func (f *File) ReadBytes() ([]byte, error) { return os.ReadFile(string(*f)) }
func (f *File) Read() (map[string]interface{}, error) { return nil, nil }
type YAML struct{}
func (p *YAML) Marshal(map[string]interface{}) ([]byte, error) { return nil, nil }
func (p *YAML) Unmarshal(b []byte) (map[string]interface{}, error) {
var out map[string]interface{}
if err := yaml.Unmarshal(b, &out); err != nil {
return nil, err
}
return out, nil
}
type Env string
func (e *Env) ReadBytes() ([]byte, error) { return nil, nil }
func (e *Env) Read() (map[string]interface{}, error) {
var keys []string
for _, k := range os.Environ() {
if strings.HasPrefix(k, string(*e)) {
keys = append(keys, k)
}
}
mp := make(map[string]interface{})
for _, k := range keys {
parts := strings.SplitN(k, "=", 2)
n := strings.ToLower(strings.TrimPrefix(parts[0], string(*e)))
if n == "" {
continue
}
// convert VAR_VAR to VAR.VAR or if we need to preserve _
// i.e. VAR_VAR__KEY_HAS_SLASHES to VAR.VAR.KEY_HAS_SLASHES
// with the result: VAR: { VAR: { KEY_HAS_SLASHES: '' } } }
x := strings.Index(n, "__")
var key string
if x == -1 {
key = strings.Replace(n, "_", ".", -1)
} else {
key = strings.Replace(n[:x+1], "_", ".", -1) + n[x+2:]
}
mp[key] = parts[1]
}
return maps.Unflatten(mp, "."), nil
}
var k = koanf.New("_")
// LoadConfig loads a configuration file into the given struct.
// The path param specifies a custom path to the configuration file.
// Reads and puts environment variables with the prefix CLOUD_GAME_.
// Params from the config should be in uppercase separated with _.
func LoadConfig(config any, path string) error {
dirs := []string{path}
if path == "" {
@ -24,18 +77,23 @@ func LoadConfig(config any, path string) error {
dirs = append(dirs, homeDir)
}
if err := fig.Load(config, fig.Dirs(dirs...), fig.UseEnv(EnvPrefix)); err != nil {
for _, dir := range dirs {
f := File(filepath.Join(filepath.Clean(dir), "config.yaml"))
if _, err := os.Stat(string(f)); !os.IsNotExist(err) {
if err := k.Load(&f, &YAML{}); err != nil {
return err
}
}
}
env := Env(EnvPrefix)
if err := k.Load(&env, nil); err != nil {
return err
}
// override from /home
if homeDir != "" {
_ = fig.Load(config, fig.Dirs(homeDir))
if err := k.Unmarshal("", config); err != nil {
return err
}
return nil
}
func LoadConfigEnv(config any) error {
return fig.Load(config, fig.IgnoreFile(), fig.UseEnv(EnvPrefix))
}

32
pkg/config/loader_test.go Normal file
View file

@ -0,0 +1,32 @@
package config
import (
"os"
"testing"
)
func TestConfigEnv(t *testing.T) {
var out WorkerConfig
_ = os.Setenv("CLOUD_GAME_ENCODER_AUDIO_FRAME", "33")
defer func() { _ = os.Unsetenv("CLOUD_GAME_ENCODER_AUDIO_FRAME") }()
_ = os.Setenv("CLOUD_GAME_EMULATOR_LIBRETRO_CORES_LIST_PCSX_OPTIONS__PCSX_REARMED_DRC", "x")
defer func() {
_ = os.Unsetenv("CLOUD_GAME_EMULATOR_LIBRETRO_CORES_LIST_PCSX_OPTIONS__PCSX_REARMED_DRC")
}()
err := LoadConfig(&out, "../../configs")
if err != nil {
t.Fatal(err)
}
if out.Encoder.Audio.Frame != 33 {
t.Errorf("%v is not 33", out.Encoder.Audio.Frame)
}
v := out.Emulator.Libretro.Cores.List["pcsx"].Options["pcsx_rearmed_drc"]
if v != "x" {
t.Errorf("%v is not x", v)
}
}

View file

@ -1,10 +0,0 @@
package monitoring
type Config struct {
Port int
URLPrefix string
MetricEnabled bool `json:"metric_enabled"`
ProfilingEnabled bool `json:"profiling_enabled"`
}
func (c *Config) IsEnabled() bool { return c.MetricEnabled || c.ProfilingEnabled }

View file

@ -1,9 +1,18 @@
package shared
package config
import "flag"
type Version int
type Monitoring struct {
Port int
URLPrefix string
MetricEnabled bool `json:"metric_enabled"`
ProfilingEnabled bool `json:"profiling_enabled"`
}
func (c *Monitoring) IsEnabled() bool { return c.MetricEnabled || c.ProfilingEnabled }
type Server struct {
Address string
Https bool

View file

@ -1,6 +0,0 @@
package storage
type Storage struct {
Provider string
Key string
}

View file

@ -1,4 +1,4 @@
package webrtc
package config
type Webrtc struct {
DisableDefaultInterceptors bool

View file

@ -1,4 +1,4 @@
package worker
package config
import (
"flag"
@ -8,29 +8,27 @@ import (
"path/filepath"
"strings"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/config/emulator"
"github.com/giongto35/cloud-game/v3/pkg/config/encoder"
"github.com/giongto35/cloud-game/v3/pkg/config/monitoring"
"github.com/giongto35/cloud-game/v3/pkg/config/shared"
"github.com/giongto35/cloud-game/v3/pkg/config/storage"
"github.com/giongto35/cloud-game/v3/pkg/config/webrtc"
"github.com/giongto35/cloud-game/v3/pkg/os"
)
type Config struct {
Encoder encoder.Encoder
Emulator emulator.Emulator
Recording shared.Recording
Storage storage.Storage
type WorkerConfig struct {
Encoder Encoder
Emulator Emulator
Recording Recording
Storage Storage
Worker Worker
Webrtc webrtc.Webrtc
Version shared.Version
Webrtc Webrtc
Version Version
}
type Storage struct {
Provider string
Key string
}
type Worker struct {
Debug bool
Monitoring monitoring.Config
Monitoring Monitoring
Network struct {
CoordinatorAddress string
Endpoint string
@ -39,15 +37,40 @@ type Worker struct {
Secure bool
Zone string
}
Server shared.Server
Server Server
Tag string
}
// allows custom config path
var configPath string
type Encoder struct {
Audio Audio
Video Video
}
func NewConfig() (conf Config) {
err := config.LoadConfig(&conf, configPath)
type Audio struct {
Frame int
}
type Video struct {
Codec string
Concurrency int
H264 struct {
Crf uint8
Preset string
Profile string
Tune string
LogLevel int
}
Vpx struct {
Bitrate uint
KeyframeInterval uint
}
}
// allows custom config path
var workerConfigPath string
func NewWorkerConfig() (conf WorkerConfig) {
err := LoadConfig(&conf, workerConfigPath)
if err != nil {
panic(err)
}
@ -59,17 +82,17 @@ func NewConfig() (conf Config) {
// ParseFlags updates config values from passed runtime flags.
// Define own flags with default value set to the current config param.
// Don't forget to call flag.Parse().
func (c *Config) ParseFlags() {
func (c *WorkerConfig) ParseFlags() {
c.Worker.Server.WithFlags()
flag.IntVar(&c.Worker.Monitoring.Port, "monitoring.port", c.Worker.Monitoring.Port, "Monitoring server port")
flag.StringVar(&c.Worker.Network.CoordinatorAddress, "coordinatorhost", c.Worker.Network.CoordinatorAddress, "Worker URL to connect")
flag.StringVar(&c.Worker.Network.Zone, "zone", c.Worker.Network.Zone, "Worker network zone (us, eu, etc.)")
flag.StringVar(&configPath, "w-conf", configPath, "Set custom configuration file path")
flag.StringVar(&workerConfigPath, "w-conf", workerConfigPath, "Set custom configuration file path")
flag.Parse()
}
// expandSpecialTags replaces all the special tags in the config.
func (c *Config) expandSpecialTags() {
func (c *WorkerConfig) expandSpecialTags() {
tag := "{user}"
for _, dir := range []*string{&c.Emulator.Storage, &c.Emulator.Libretro.Cores.Repo.ExtLock} {
if *dir == "" || !strings.Contains(*dir, tag) {
@ -85,10 +108,10 @@ func (c *Config) expandSpecialTags() {
}
// fixValues tries to fix some values otherwise hard to set externally.
func (c *Config) fixValues() {
func (c *WorkerConfig) fixValues() {
// with ICE lite we clear ICE servers
if c.Webrtc.IceLite {
c.Webrtc.IceServers = []webrtc.IceServer{}
c.Webrtc.IceServers = []IceServer{}
}
}

View file

@ -4,8 +4,7 @@ import (
"html/template"
"net/http"
"github.com/giongto35/cloud-game/v3/pkg/config/coordinator"
"github.com/giongto35/cloud-game/v3/pkg/config/shared"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/games"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/monitoring"
@ -13,7 +12,7 @@ import (
"github.com/giongto35/cloud-game/v3/pkg/service"
)
func New(conf coordinator.Config, log *logger.Logger) (services service.Group) {
func New(conf config.CoordinatorConfig, log *logger.Logger) (services service.Group) {
lib := games.NewLibWhitelisted(conf.Coordinator.Library, conf.Emulator, log)
lib.Scan()
hub := NewHub(conf, lib, log)
@ -33,7 +32,7 @@ func New(conf coordinator.Config, log *logger.Logger) (services service.Group) {
return
}
func NewHTTPServer(conf coordinator.Config, log *logger.Logger, fnMux func(*httpx.Mux) *httpx.Mux) (*httpx.Server, error) {
func NewHTTPServer(conf config.CoordinatorConfig, log *logger.Logger, fnMux func(*httpx.Mux) *httpx.Mux) (*httpx.Server, error) {
return httpx.NewServer(
conf.Coordinator.Server.GetAddr(),
func(s *httpx.Server) httpx.Handler {
@ -46,7 +45,7 @@ func NewHTTPServer(conf coordinator.Config, log *logger.Logger, fnMux func(*http
)
}
func index(conf coordinator.Config, log *logger.Logger) httpx.Handler {
func index(conf config.CoordinatorConfig, log *logger.Logger) httpx.Handler {
const indexHTML = "./web/index.html"
handler := func(tpl *template.Template, w httpx.ResponseWriter, r *httpx.Request) {
@ -56,8 +55,8 @@ func index(conf coordinator.Config, log *logger.Logger) httpx.Handler {
}
// render index page with some tpl values
tplData := struct {
Analytics coordinator.Analytics
Recording shared.Recording
Analytics config.Analytics
Recording config.Recording
}{conf.Coordinator.Analytics, conf.Recording}
if err := tpl.Execute(w, tplData); err != nil {
log.Fatal().Err(err).Msg("error with the analytics template file")

View file

@ -9,7 +9,7 @@ import (
"github.com/giongto35/cloud-game/v3/pkg/api"
"github.com/giongto35/cloud-game/v3/pkg/com"
"github.com/giongto35/cloud-game/v3/pkg/config/coordinator"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/games"
"github.com/giongto35/cloud-game/v3/pkg/logger"
)
@ -24,14 +24,14 @@ type Connection interface {
}
type Hub struct {
conf coordinator.Config
conf config.CoordinatorConfig
launcher games.Launcher
log *logger.Logger
users com.NetMap[*User]
workers com.NetMap[*Worker]
}
func NewHub(conf coordinator.Config, lib games.GameLibrary, log *logger.Logger) *Hub {
func NewHub(conf config.CoordinatorConfig, lib games.GameLibrary, log *logger.Logger) *Hub {
return &Hub{
conf: conf,
users: com.NewNetMap[*User](),
@ -168,7 +168,7 @@ func (h *Hub) findWorkerFor(usr *User, q url.Values, log *logger.Logger) *Worker
log.Debug().Msgf("Worker with id: %v has been found", wid)
} else {
switch h.conf.Coordinator.Selector {
case coordinator.SelectByPing:
case config.SelectByPing:
log.Debug().Msgf("Searching fastest free worker...")
if worker = h.findFastestWorker(zone,
func(servers []string) (map[string]int64, error) { return usr.CheckLatency(servers) }); worker != nil {

View file

@ -3,7 +3,7 @@ package coordinator
import (
"github.com/giongto35/cloud-game/v3/pkg/api"
"github.com/giongto35/cloud-game/v3/pkg/com"
"github.com/giongto35/cloud-game/v3/pkg/config/coordinator"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/games"
"github.com/giongto35/cloud-game/v3/pkg/logger"
)
@ -42,7 +42,7 @@ func (u *User) Disconnect() {
}
}
func (u *User) HandleRequests(info HasServerInfo, launcher games.Launcher, conf coordinator.Config) chan struct{} {
func (u *User) HandleRequests(info HasServerInfo, launcher games.Launcher, conf config.CoordinatorConfig) chan struct{} {
return u.ProcessPackets(func(x api.In[com.Uid]) error {
payload := x.GetPayload()
switch x.GetType() {

View file

@ -4,7 +4,7 @@ import (
"unsafe"
"github.com/giongto35/cloud-game/v3/pkg/api"
"github.com/giongto35/cloud-game/v3/pkg/config/webrtc"
"github.com/giongto35/cloud-game/v3/pkg/config"
)
// CheckLatency sends a list of server addresses to the user
@ -22,7 +22,7 @@ func (u *User) CheckLatency(req api.CheckLatencyUserResponse) (api.CheckLatencyU
}
// InitSession signals the user that the app is ready to go.
func (u *User) InitSession(wid string, ice []webrtc.IceServer, games []string) {
func (u *User) InitSession(wid string, ice []config.IceServer, games []string) {
u.Notify(api.InitSession, api.InitSessionUserResponse{
// don't do this at home
Ice: *(*[]api.IceServer)(unsafe.Pointer(&ice)),

View file

@ -5,7 +5,7 @@ import (
"github.com/giongto35/cloud-game/v3/pkg/api"
"github.com/giongto35/cloud-game/v3/pkg/com"
"github.com/giongto35/cloud-game/v3/pkg/config/coordinator"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/games"
)
@ -26,7 +26,7 @@ func (u *User) HandleWebrtcIceCandidate(rq api.WebrtcUserIceCandidate) {
u.w.WebrtcIceCandidate(u.Id(), string(rq))
}
func (u *User) HandleStartGame(rq api.GameStartUserRequest, launcher games.Launcher, conf coordinator.Config) {
func (u *User) HandleStartGame(rq api.GameStartUserRequest, launcher games.Launcher, conf config.CoordinatorConfig) {
// +injects game data into the original game request
// the name of the game either in the `room id` field or
// it's in the initial request

View file

@ -11,24 +11,10 @@ import (
"time"
"github.com/fsnotify/fsnotify"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
)
// Config is an external configuration
type Config struct {
// some directory which is going to be
// the root folder for the library
BasePath string
// a list of supported file extensions
Supported []string
// a list of ignored words in the files
Ignored []string
// print some additional info
Verbose bool
// enable directory changes watch
WatchMode bool
}
// libConf is an optimized internal library configuration
type libConf struct {
path string
@ -82,11 +68,11 @@ type GameMetadata struct {
func (g GameMetadata) FullPath() string { return filepath.Join(g.Base, g.Path) }
func (c Config) GetSupportedExtensions() []string { return c.Supported }
func NewLib(conf config.Library, log *logger.Logger) GameLibrary {
return NewLibWhitelisted(conf, conf, log)
}
func NewLib(conf Config, log *logger.Logger) GameLibrary { return NewLibWhitelisted(conf, conf, log) }
func NewLibWhitelisted(conf Config, filter FileExtensionWhitelist, log *logger.Logger) GameLibrary {
func NewLibWhitelisted(conf config.Library, filter FileExtensionWhitelist, log *logger.Logger) GameLibrary {
hasSource := true
dir, err := filepath.Abs(conf.BasePath)
if err != nil {

View file

@ -3,6 +3,7 @@ package games
import (
"testing"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
)
@ -21,7 +22,7 @@ func TestLibraryScan(t *testing.T) {
l := logger.NewConsole(false, "w", false)
for _, test := range tests {
library := NewLib(Config{
library := NewLib(config.Library{
BasePath: test.directory,
Supported: []string{"gba", "zip", "nes"},
Ignored: []string{"neogeo", "pgm"},

View file

@ -7,7 +7,7 @@ import (
"strconv"
"github.com/VictoriaMetrics/metrics"
"github.com/giongto35/cloud-game/v3/pkg/config/monitoring"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/network/httpx"
)
@ -16,14 +16,14 @@ const debugEndpoint = "/debug/pprof"
const metricsEndpoint = "/metrics"
type Monitoring struct {
conf monitoring.Config
conf config.Monitoring
server *httpx.Server
log *logger.Logger
}
// New creates new monitoring service.
// The tag param specifies owner label for logs.
func New(conf monitoring.Config, baseAddr string, log *logger.Logger) *Monitoring {
func New(conf config.Monitoring, baseAddr string, log *logger.Logger) *Monitoring {
serv, err := httpx.NewServer(
net.JoinHostPort(baseAddr, strconv.Itoa(conf.Port)),
func(s *httpx.Server) httpx.Handler {

View file

@ -3,7 +3,7 @@ package httpx
import (
"time"
"github.com/giongto35/cloud-game/v3/pkg/config/shared"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
)
@ -47,7 +47,7 @@ func HttpsRedirect(redirect bool) Option {
func WithPortRoll(roll bool) Option { return func(opts *Options) { opts.PortRoll = roll } }
func WithZone(zone string) Option { return func(opts *Options) { opts.Zone = zone } }
func WithServerConfig(conf shared.Server) Option {
func WithServerConfig(conf config.Server) Option {
return func(opts *Options) {
opts.Https = conf.Https
opts.HttpsCert = conf.Tls.HttpsCert

View file

@ -4,7 +4,7 @@ import (
"fmt"
"net"
conf "github.com/giongto35/cloud-game/v3/pkg/config/webrtc"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/network/socket"
"github.com/pion/interceptor"
@ -19,7 +19,7 @@ type ApiFactory struct {
type ModApiFun func(m *webrtc.MediaEngine, i *interceptor.Registry, s *webrtc.SettingEngine)
func NewApiFactory(conf conf.Webrtc, log *logger.Logger, mod ModApiFun) (api *ApiFactory, err error) {
func NewApiFactory(conf config.Webrtc, log *logger.Logger, mod ModApiFun) (api *ApiFactory, err error) {
m := &webrtc.MediaEngine{}
if err = m.RegisterDefaultCodecs(); err != nil {
return

View file

@ -5,7 +5,7 @@ import (
"github.com/giongto35/cloud-game/v3/pkg/api"
"github.com/giongto35/cloud-game/v3/pkg/com"
"github.com/giongto35/cloud-game/v3/pkg/config/worker"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/network/webrtc"
)
@ -27,7 +27,7 @@ type coordinator struct {
var connector com.Client
func newCoordinatorConnection(host string, conf worker.Worker, addr string, log *logger.Logger) (*coordinator, error) {
func newCoordinatorConnection(host string, conf config.Worker, addr string, log *logger.Logger) (*coordinator, error) {
scheme := "ws"
if conf.Network.Secure {
scheme = "wss"

View file

@ -5,14 +5,14 @@ import (
"github.com/giongto35/cloud-game/v3/pkg/api"
"github.com/giongto35/cloud-game/v3/pkg/com"
"github.com/giongto35/cloud-game/v3/pkg/config/worker"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/games"
"github.com/giongto35/cloud-game/v3/pkg/network/webrtc"
"github.com/goccy/go-json"
)
// buildConnQuery builds initial connection data query to a coordinator.
func buildConnQuery(id com.Uid, conf worker.Worker, address string) (string, error) {
func buildConnQuery(id com.Uid, conf config.Worker, address string) (string, error) {
addr := conf.GetPingAddr(address)
return toBase64Json(api.ConnectionRequest[com.Uid]{
Addr: addr.Hostname(),

View file

@ -8,7 +8,7 @@ import (
"sync/atomic"
"time"
conf "github.com/giongto35/cloud-game/v3/pkg/config/emulator"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/os"
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator"
@ -21,7 +21,7 @@ type Frontend struct {
input InputState
conf conf.Emulator
conf config.Emulator
storage Storage
// out frame size
@ -64,7 +64,7 @@ var (
)
// NewFrontend implements Emulator interface for a Libretro frontend.
func NewFrontend(conf conf.Emulator, log *logger.Logger) (*Frontend, error) {
func NewFrontend(conf config.Emulator, log *logger.Logger) (*Frontend, error) {
log = log.Extend(log.With().Str("m", "Libretro"))
ll := log.Extend(log.Level(logger.Level(conf.Libretro.LogLevel)).With())
SetLibretroLogger(ll)
@ -105,15 +105,15 @@ func NewFrontend(conf conf.Emulator, log *logger.Logger) (*Frontend, error) {
}
func (f *Frontend) LoadMetadata(emu string) {
config := f.conf.GetLibretroCoreConfig(emu)
conf := f.conf.GetLibretroCoreConfig(emu)
meta := emulator.Metadata{
AutoGlContext: config.AutoGlContext,
HasMultitap: config.HasMultitap,
HasVFR: config.VFR,
IsGlAllowed: config.IsGlAllowed,
LibPath: config.Lib,
Options: config.Options,
UsesLibCo: config.UsesLibCo,
AutoGlContext: conf.AutoGlContext,
HasMultitap: conf.HasMultitap,
HasVFR: conf.VFR,
IsGlAllowed: conf.IsGlAllowed,
LibPath: conf.Lib,
Options: conf.Options,
UsesLibCo: conf.UsesLibCo,
}
f.mu.Lock()
coreLoad(meta)

View file

@ -1,12 +1,12 @@
package manager
import (
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator/libretro"
"os"
"path/filepath"
"strings"
"github.com/giongto35/cloud-game/v3/pkg/config/emulator"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator/libretro"
)
type Manager interface {
@ -14,10 +14,10 @@ type Manager interface {
}
type BasicManager struct {
Conf emulator.LibretroConfig
Conf config.LibretroConfig
}
func (m BasicManager) GetInstalled() (installed []emulator.CoreInfo, err error) {
func (m BasicManager) GetInstalled() (installed []config.CoreInfo, err error) {
dir := m.Conf.GetCoresStorePath()
arch, err := libretro.GetCoreExt()
if err != nil {
@ -32,7 +32,7 @@ func (m BasicManager) GetInstalled() (installed []emulator.CoreInfo, err error)
for _, file := range files {
name := file.Name()
if filepath.Ext(name) == arch.LibExt {
installed = append(installed, emulator.CoreInfo{Name: strings.TrimSuffix(name, arch.LibExt)})
installed = append(installed, config.CoreInfo{Name: strings.TrimSuffix(name, arch.LibExt)})
}
}
return

View file

@ -1,11 +1,11 @@
package remotehttp
import (
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator/libretro"
"os"
"github.com/giongto35/cloud-game/v3/pkg/config/emulator"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator/libretro"
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator/libretro/manager"
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator/libretro/repo"
"github.com/gofrs/flock"
@ -22,7 +22,7 @@ type Manager struct {
log *logger.Logger
}
func NewRemoteHttpManager(conf emulator.LibretroConfig, log *logger.Logger) Manager {
func NewRemoteHttpManager(conf config.LibretroConfig, log *logger.Logger) Manager {
repoConf := conf.Cores.Repo.Main
altRepoConf := conf.Cores.Repo.Secondary
// used for synchronization of multiple process
@ -55,7 +55,7 @@ func NewRemoteHttpManager(conf emulator.LibretroConfig, log *logger.Logger) Mana
return m
}
func CheckCores(conf emulator.Emulator, log *logger.Logger) error {
func CheckCores(conf config.Emulator, log *logger.Logger) error {
if !conf.Libretro.Cores.Repo.Sync {
return nil
}
@ -95,7 +95,7 @@ func (m *Manager) getCoreUrls(names []string, repo repo.Repository) (urls []Down
return
}
func (m *Manager) download(cores []emulator.CoreInfo) (failed []string) {
func (m *Manager) download(cores []config.CoreInfo) (failed []string) {
if len(cores) == 0 || m.repo == nil {
return
}
@ -132,7 +132,7 @@ func (m *Manager) down(cores []string, repo repo.Repository) (failed []string) {
}
// diff returns a list of not installed cores.
func diff(declared, installed []emulator.CoreInfo) (diff []emulator.CoreInfo) {
func diff(declared, installed []config.CoreInfo) (diff []config.CoreInfo) {
if len(declared) == 0 {
return
}

View file

@ -4,7 +4,7 @@ import (
"reflect"
"testing"
"github.com/giongto35/cloud-game/v3/pkg/config/emulator"
"github.com/giongto35/cloud-game/v3/pkg/config"
)
func TestDiff(t *testing.T) {
@ -39,9 +39,9 @@ func TestDiff(t *testing.T) {
},
}
toCoreInfo := func(names []string) (r []emulator.CoreInfo) {
toCoreInfo := func(names []string) (r []config.CoreInfo) {
for _, n := range names {
r = append(r, emulator.CoreInfo{Name: n})
r = append(r, config.CoreInfo{Name: n})
}
return
}

View file

@ -12,7 +12,6 @@ import (
"unsafe"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/config/worker"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator"
)
@ -50,7 +49,7 @@ func GetEmulatorMock(room string, system string) *EmulatorMock {
rootPath := getRootPath()
configPath := rootPath + "configs/"
var conf worker.Config
var conf config.WorkerConfig
if err := config.LoadConfig(&conf, configPath); err != nil {
panic(err)
}

View file

@ -4,7 +4,7 @@ import (
"sync"
"time"
conf "github.com/giongto35/cloud-game/v3/pkg/config/encoder"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator"
"github.com/giongto35/cloud-game/v3/pkg/worker/encoder"
"github.com/giongto35/cloud-game/v3/pkg/worker/encoder/h264"
@ -68,7 +68,7 @@ func (b *Buffer) Write(s Samples, onFull OnFull) (r int) {
// GetFrameSizeFor calculates audio frame size, i.e. 48k*frame/1000*2
func GetFrameSizeFor(hz int, frame int) int { return hz * frame / 1000 * audioChannels }
func (r *Room) initAudio(frequency int, conf conf.Audio) {
func (r *Room) initAudio(frequency int, conf config.Audio) {
buf := NewBuffer(GetFrameSizeFor(frequency, conf.Frame))
resample, frameLen := frequency != audioFrequency, 0
if resample {
@ -107,7 +107,7 @@ func (r *Room) initAudio(frequency int, conf conf.Audio) {
}
// initVideo processes videoFrames images with an encoder (codec) then pushes the result to WebRTC.
func (r *Room) initVideo(width, height int, conf conf.Video) {
func (r *Room) initVideo(width, height int, conf config.Video) {
var enc encoder.Encoder
var err error

View file

@ -1,7 +1,7 @@
package worker
import (
"github.com/giongto35/cloud-game/v3/pkg/config/worker"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator"
"github.com/giongto35/cloud-game/v3/pkg/worker/recorder"
)
@ -11,7 +11,7 @@ type RecordingRoom struct {
rec *recorder.Recording
}
func WithRecording(room GamingRoom, rec bool, recUser string, game string, conf worker.Config) *RecordingRoom {
func WithRecording(room GamingRoom, rec bool, recUser string, game string, conf config.WorkerConfig) *RecordingRoom {
rr := &RecordingRoom{GamingRoom: room, rec: recorder.NewRecording(
recorder.Meta{UserName: recUser},
room.GetLog(),

View file

@ -4,8 +4,7 @@ import (
"time"
"github.com/giongto35/cloud-game/v3/pkg/com"
conf "github.com/giongto35/cloud-game/v3/pkg/config/emulator"
"github.com/giongto35/cloud-game/v3/pkg/config/worker"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/games"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/os"
@ -42,7 +41,7 @@ type Room struct {
log *logger.Logger
}
func NewRoom(id string, game games.GameMetadata, onClose func(*Room), conf worker.Config, log *logger.Logger) *Room {
func NewRoom(id string, game games.GameMetadata, onClose func(*Room), conf config.WorkerConfig, log *logger.Logger) *Room {
if id == "" {
id = games.GenerateRoomID(game.Name)
}
@ -110,7 +109,7 @@ func (r *Room) EnableAutosave(periodSec int) {
}
}
func (r *Room) whatsFrame(conf conf.Emulator) (ww int, hh int) {
func (r *Room) whatsFrame(conf config.Emulator) (ww int, hh int) {
w, h := r.emulator.GetFrameSize()
// nwidth, nheight are the WebRTC output size
var nwidth, nheight int

View file

@ -17,7 +17,6 @@ import (
"time"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/config/worker"
"github.com/giongto35/cloud-game/v3/pkg/games"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/worker/emulator"
@ -206,7 +205,7 @@ func dumpCanvas(frame *image2.Frame, name string, caption string, path string) {
func getRoomMock(cfg roomMockConfig) roomMock {
cfg.game.Path = cfg.gamesPath + cfg.game.Path
var conf worker.Config
var conf config.WorkerConfig
if err := config.LoadConfig(&conf, whereIsConfigs); err != nil {
panic(err)
}
@ -249,7 +248,7 @@ func getRoomMock(cfg roomMockConfig) roomMock {
// fixEmulators makes absolute game paths in global GameList and passes GL context config.
// hack: emulator paths should be absolute and visible to the tests.
func fixEmulators(config *worker.Config, autoGlContext bool) {
func fixEmulators(config *config.WorkerConfig, autoGlContext bool) {
rootPath := getRootPath()
config.Emulator.Libretro.Cores.Paths.Libs =

View file

@ -3,7 +3,7 @@ package worker
import (
"time"
"github.com/giongto35/cloud-game/v3/pkg/config/worker"
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/monitoring"
"github.com/giongto35/cloud-game/v3/pkg/network/httpx"
@ -13,7 +13,7 @@ import (
type Worker struct {
address string
conf worker.Config
conf config.WorkerConfig
cord *coordinator
log *logger.Logger
router Router
@ -23,7 +23,7 @@ type Worker struct {
const retry = 10 * time.Second
func New(conf worker.Config, log *logger.Logger, done chan struct{}) (services service.Group) {
func New(conf config.WorkerConfig, log *logger.Logger, done chan struct{}) (services service.Group) {
if err := remotehttp.CheckCores(conf.Emulator, log); err != nil {
log.Error().Err(err).Msg("cores sync error")
}