Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Env var settings #197

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion chatcommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ var commands = &CommandControl{

pw := html.UnescapeString(strings.Join(args, " "))

if settings.AdminPassword == pw {
if settings.GetAdminPassword() == pw {
cl.CmdLevel = common.CmdlAdmin
cl.belongsTo.AddModNotice(cl.name + " used the admin password")
common.LogInfof("[auth] %s used the admin password\n", cl.name)
Expand Down
4 changes: 2 additions & 2 deletions chatroom.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type ChatRoom struct {
modPasswordsMtx sync.Mutex
}

//initializing the chatroom
// initializing the chatroom
func newChatRoom() (*ChatRoom, error) {
cr := &ChatRoom{
queue: make(chan common.ChatData, 1000),
Expand Down Expand Up @@ -322,7 +322,7 @@ func (cr *ChatRoom) UserCount() int {
return len(cr.clients)
}

//broadcasting all the messages in the queue in one block
// broadcasting all the messages in the queue in one block
func (cr *ChatRoom) Broadcast() {
send := func(data common.ChatData, client *Client) {
err := client.SendChatData(data)
Expand Down
4 changes: 1 addition & 3 deletions emotes.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ import (
"golang.org/x/exp/slices"
)

var emotesDir string

func loadEmotes() error {
var err error
common.Emotes, err = processEmoteDir(emotesDir)
common.Emotes, err = processEmoteDir(settings.GetEmotesDir())
if err != nil {
return fmt.Errorf("could not process emote dir: %w", err)
}
Expand Down
8 changes: 4 additions & 4 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ func (w writeFlusher) Flush() error {
func wsEmotes(w http.ResponseWriter, r *http.Request) {
file := strings.TrimPrefix(r.URL.Path, "/")

emoteDirSuffix := filepath.Base(emotesDir)
emoteDirSuffix := filepath.Base(settings.GetEmotesDir())
if emoteDirSuffix == filepath.SplitList(file)[0] {
file = strings.TrimPrefix(file, emoteDirSuffix+"/")
}

var body []byte
err := filepath.WalkDir(emotesDir, func(path string, d fs.DirEntry, err error) error {
err := filepath.WalkDir(settings.GetEmotesDir(), func(path string, d fs.DirEntry, err error) error {
if d.IsDir() || err != nil || len(body) > 0 {
return nil
}
Expand Down Expand Up @@ -177,7 +177,7 @@ func checkRoomAccess(w http.ResponseWriter, r *http.Request) bool {
common.LogErrorf("Unable to get session for client %s: %v\n", r.RemoteAddr, err)
}

if settings.RoomAccess == AccessPin {
if settings.GetRoomAccess() == AccessPin {
pin := session.Values["pin"]
// No pin found in session
if pin == nil || len(pin.(string)) == 0 {
Expand Down Expand Up @@ -223,7 +223,7 @@ func checkRoomAccess(w http.ResponseWriter, r *http.Request) bool {
}

// Pin found in session, but it has changed since last time.
if pin.(string) != settings.RoomAccessPin {
if pin.(string) != settings.GetRoomAccessPin() {
// Clear out the old pin.
session.Values["pin"] = nil
err = session.Save(r, w)
Expand Down
84 changes: 26 additions & 58 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,52 +16,41 @@ import (
"github.com/nareix/joy4/format"
"github.com/nareix/joy4/format/rtmp"
"github.com/zorchenhimer/MovieNight/common"
"github.com/zorchenhimer/MovieNight/files"
)

//go:embed static/*.html static/css static/img static/js
var staticFS embed.FS

var stats = newStreamStats()

func setupSettings(adminPass string, confFile string) error {
if confFile == "" {
confFile = files.JoinRunPath("settings.json")
}

func setupSettings(args args) error {
var err error
settings, err = LoadSettings(confFile)
settings, err = LoadSettings(args)
if err != nil {
return fmt.Errorf("unable to load settings: %w", err)
}
if len(settings.StreamKey) == 0 {
return fmt.Errorf("missing stream key is settings.json")
}

if adminPass != "" {
fmt.Println("Password provided at runtime; ignoring password in set in settings.")
settings.AdminPassword = adminPass
}
return nil
}

func setupCookieStore() {
sstore = sessions.NewCookieStore([]byte(settings.SessionKey))
sstore.Options = &sessions.Options{
Path: "/",
MaxAge: 60 * 60 * 24, // one day
SameSite: http.SameSiteStrictMode,
}

return nil
}

type args struct {
Addr string `arg:"-l,--addr" help:"host:port of the HTTP server"`
RtmpAddr string `arg:"-r,--rtmp" help:"host:port of the RTMP server"`
StreamKey string `arg:"-k,--key" help:"Stream key, to protect your stream"`
AdminPass string `arg:"-a,--admin" help:"Set admin password. Overrides configuration in settings.json. This will not write the password to settings.json."`
ConfigFile string `arg:"-f,--config" help:"URI of the conf file"`
StaticDir string `arg:"-s,--static" help:"Directory to read static files from by default"`
EmotesDir string `arg:"-e,--emotes" help:"Directory to read emotes. By default it uses the executable directory"`
WriteStatic bool `arg:"--write-static" help:"write static files to the static dir"`
Addr string `arg:"-l,--addr,env:MN_ADDR" help:"host:port of the HTTP server"`
RtmpAddr string `arg:"-r,--rtmp,env:MN_RTMP" help:"host:port of the RTMP server"`
StreamKey string `arg:"-k,--key,env:MN_STREAM_KEY" default:"" help:"Stream key, to protect your stream"`
AdminPass string `arg:"-a,--admin,env:MN_ADMIN_PASS" default:"" help:"Set admin password. Overrides configuration in settings.json. This will not write the password to settings.json."`
ConfigFile string `arg:"-f,--config,env:MN_CONFIG" default:"settings.json" help:"URI of the conf file"`
StaticDir string `arg:"-s,--static,env:MN_STATIC" default:"" help:"Directory to read static files from by default"` // default static dir should be `static` I guess. Zorglube
EmotesDir string `arg:"-e,--emotes,env:MN_EMOTES" default:"emotes" help:"Directory to read emotes. By default it uses the executable directory"`
WriteStatic bool `arg:"--write-static,env:MN_WRITE_STATIC" default:"false" help:"write static files to the static dir"`
}

func main() {
Expand All @@ -74,30 +63,23 @@ func run(args args) {
var err error
start := time.Now()

emotesDir = args.EmotesDir
if emotesDir == "" {
emotesDir = files.JoinRunPath("emotes")
if err := setupSettings(args); err != nil {
log.Fatalf("Error loading settings: %v\n", err)
}

staticFsys, err := files.FS(staticFS, args.StaticDir, "static")
if err != nil {
log.Fatalf("Error creating static FS: %v\n", err)
}
setupCookieStore()
staticFsys := settings.GetStaticFsys()

if args.WriteStatic {
if settings.GetWriteStatic() {
count, err := staticFsys.WriteFiles(".")
fmt.Printf("%d files were writen to disk\n", count)
if err != nil {
log.Fatalf("Error writing files to static dir %q: %v\n", args.StaticDir, err)
log.Fatalf("Error writing files to static dir %q: %v\n", settings.GetStaticDir(), err)
}
}

format.RegisterAll()

if err := setupSettings(args.AdminPass, args.ConfigFile); err != nil {
log.Fatalf("Error loading settings: %v\n", err)
}

if err := common.InitTemplates(staticFsys); err != nil {
common.LogErrorln(err)
os.Exit(1)
Expand All @@ -113,31 +95,17 @@ func run(args args) {
os.Exit(1)
}

if args.Addr == "" {
args.Addr = settings.ListenAddress
}

if args.RtmpAddr == "" {
args.RtmpAddr = settings.RtmpListenAddress
}

// A stream key was passed on the command line. Use it, but don't save
// it over the stream key in the settings.json file.
if args.StreamKey != "" {
settings.SetTempKey(args.StreamKey)
}

common.LogInfoln("Stream key: ", settings.GetStreamKey())
common.LogInfoln("Admin password: ", settings.AdminPassword)
common.LogInfoln("HTTP server listening on: ", args.Addr)
common.LogInfoln("RTMP server listening on: ", args.RtmpAddr)
common.LogInfoln("RoomAccess: ", settings.RoomAccess)
common.LogInfoln("RoomAccessPin: ", settings.RoomAccessPin)
common.LogInfoln("Admin password: ", settings.GetAdminPassword())
common.LogInfoln("HTTP server listening on: ", settings.GetAddr())
common.LogInfoln("RTMP server listening on: ", settings.GetRtmpAddr())
common.LogInfoln("RoomAccess: ", settings.GetRoomAccess())
common.LogInfoln("RoomAccessPin: ", settings.GetRoomAccessPin())

rtmpServer := &rtmp.Server{
HandlePlay: handlePlay,
HandlePublish: handlePublish,
Addr: args.RtmpAddr,
Addr: settings.GetRtmpAddr(),
}

router := http.NewServeMux()
Expand All @@ -155,7 +123,7 @@ func run(args args) {
router.HandleFunc("/", wrapAuth(handleDefault))

httpServer := &http.Server{
Addr: args.Addr,
Addr: settings.GetAddr(),
Handler: router,
}

Expand Down
35 changes: 22 additions & 13 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,21 +124,30 @@ and a chat only version at
http://your.domain.host:8089/chat
```

The default listen port is `:8089`. It can be changed by providing a new port
at startup:
Some configurations values can be provided by three ways environment variables, run args, settings.json file.

```text
Usage of .\MovieNight.exe:
-e bool
Whether or not to download approved emotes on startup (default "false")
-k string
Stream key, to protect your stream (default: "")
-l string
host:port of the MovieNight (default ":8089")
-r string
host:port of the RTMP server (default ":1935")
-f string
the settings file you want to use (default "./settings.json")
Usage: MovieNight.exe [--addr ADDR] [--rtmp RTMP] [--key KEY] [--admin ADMIN] [--config CONFIG] [--static STATIC] [--emotes EMOTES] [--write-static]

Options:
--addr ADDR, -l ADDR
host:port of the HTTP server [env: MN_ADDR]
--rtmp RTMP, -r RTMP
host:port of the RTMP server [env: MN_RTMP]
--key KEY, -k KEY
Stream key, to protect your stream [env: MN_STREAM_KEY]
--admin ADMIN, -a ADMIN
Set admin password. Overrides configuration in settings.json. This will not write the password to settings.json. [env: MN_ADMIN_PASS]
--config CONFIG, -f CONFIG
URI of the conf file [env: MN_CONFIG]
--static STATIC, -s STATIC
Directory to read static files from by default [env: MN_STATIC]
--emotes EMOTES, -e EMOTES
Directory to read emotes. By default it uses the executable directory [env: MN_EMOTES]
--write-static
write static files to the static dir
--help, -h
display this help and exit
```

## Configuration
Expand Down
79 changes: 67 additions & 12 deletions settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"math/big"
"os"
"strings"
Expand All @@ -14,15 +15,17 @@ import (

"github.com/gorilla/sessions"
"github.com/zorchenhimer/MovieNight/common"
"github.com/zorchenhimer/MovieNight/files"
)

var settings *Settings
var sstore *sessions.CookieStore

type Settings struct {
// Non-Saved settings
filename string
cmdLineKey string // stream key from the command line
filename string
// the argument from the command line
args args

// Saved settings
AdminPassword string
Expand Down Expand Up @@ -74,7 +77,8 @@ type BanInfo struct {
//go:embed settings_example.json
var settingsExampleFS []byte

func LoadSettings(filename string) (*Settings, error) {
func LoadSettings(args args) (*Settings, error) {
var filename = files.JoinRunPath(args.ConfigFile)
raw, err := os.ReadFile(filename)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
Expand All @@ -89,6 +93,7 @@ func LoadSettings(filename string) (*Settings, error) {
return nil, fmt.Errorf("error unmarshaling: %w", err)
}
s.filename = filename
s.args = args // Keep an eye on the args from the command line

var logFileDir string = s.LogFile
fmt.Printf("Log file: %s\n", logFileDir)
Expand Down Expand Up @@ -280,20 +285,18 @@ func (s *Settings) IsBanned(host string) (bool, []string) {
return false, nil
}

func (s *Settings) SetTempKey(key string) {
defer s.lock.Unlock()
s.lock.Lock()

s.cmdLineKey = key
}

func (s *Settings) GetStreamKey() string {
defer s.lock.RUnlock()
s.lock.RLock()

if len(s.cmdLineKey) > 0 {
return s.cmdLineKey
if s.args.StreamKey != "" {
return s.args.StreamKey
}

if s.StreamKey == "" {
panic("Missing stream key, add it in settings.json, or use --streamKey at runtime")
}

return s.StreamKey
}

Expand All @@ -311,3 +314,55 @@ func (s *Settings) generateNewPin() (string, error) {
}
return s.RoomAccessPin, nil
}

func (s *Settings) GetAdminPassword() string {
if s.args.AdminPass != "" {
common.LogInfoln("Password provided at runtime; ignoring password in set in settings.")
return s.args.AdminPass
}
return s.AdminPassword
}

func (s *Settings) GetAddr() string {
if s.args.Addr != "" {
return s.args.Addr
}
return s.ListenAddress
}

func (s *Settings) GetRtmpAddr() string {
if s.args.RtmpAddr != "" {
return s.args.RtmpAddr
}
return s.RtmpListenAddress
}

func (s *Settings) GetRoomAccess() AccessMode {
return s.RoomAccess
}

func (s *Settings) GetRoomAccessPin() string {
return s.RoomAccessPin
}

func (s *Settings) GetEmotesDir() string {
return files.JoinRunPath(s.args.EmotesDir)
}

func (s *Settings) GetStaticDir() string {
return s.args.StaticDir
}

func (s *Settings) GetStaticFsys() files.FileSystem {
fSys, err := files.FS(staticFS, settings.GetStaticDir(), "static")
if err != nil {
log.Fatalf("Error creating static FS: %v\n", err)
return nil
}

return fSys
}

func (s *Settings) GetWriteStatic() bool {
return s.args.WriteStatic
}