214 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
		
			Executable file
		
	
	
	
	
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"io/ioutil"
 | 
						|
	"math/rand"
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"time"
 | 
						|
 | 
						|
	builtins "git.martyn.berlin/martyn/karaokards/internal/builtins"
 | 
						|
	irc "git.martyn.berlin/martyn/karaokards/internal/irc"
 | 
						|
	webserver "git.martyn.berlin/martyn/karaokards/internal/webserver"
 | 
						|
	rgb "github.com/foresthoffman/rgblog"
 | 
						|
	scribble "github.com/nanobox-io/golang-scribble"
 | 
						|
)
 | 
						|
 | 
						|
type configStruct struct {
 | 
						|
	InitialChannels []string `json:"channels"`
 | 
						|
	OAuthPath       string   `json:"oauthpath,omitempty"`
 | 
						|
	StringPath      string   `json:"authpath,omitempty"`
 | 
						|
	DataPath        string   `json:"datapath,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
type customStringsStruct struct {
 | 
						|
	Strings []string `json:"strings,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
var selectablePrompts []string
 | 
						|
 | 
						|
var customStrings customStringsStruct
 | 
						|
 | 
						|
var config configStruct
 | 
						|
 | 
						|
func readConfig() {
 | 
						|
	var data []byte
 | 
						|
	var err error
 | 
						|
	configFile := ""
 | 
						|
	if os.Getenv("KARAOKARDS_CONFIGFILE") != "" {
 | 
						|
		if _, err := os.Stat(os.Getenv("KARAOKARDS_CONFIGFILE")); os.IsNotExist(err) {
 | 
						|
			rgb.RPrintf("[%s] Error, KARAOKARDS_CONFIGFILE env var set and '%s' doesn't exist!\n", irc.TimeStamp(), os.Getenv("KARAOKARDS_CONFIGFILE"))
 | 
						|
			os.Exit(1)
 | 
						|
		}
 | 
						|
		configFile = os.Getenv("KARAOKARDS_CONFIGFILE")
 | 
						|
	} else {
 | 
						|
		ex, err := os.Executable()
 | 
						|
		if err != nil {
 | 
						|
			rgb.YPrintf("[%s] Warning, KARAOKARDS_CONFIGFILE env var unset and cannot find executable!\n", irc.TimeStamp())
 | 
						|
		}
 | 
						|
		exPath := filepath.Dir(ex)
 | 
						|
		if _, err := os.Stat(exPath + "/config.json"); os.IsNotExist(err) {
 | 
						|
			rgb.YPrintf("[%s] Warning, KARAOKARDS_CONFIGFILE env var unset and `config.json` not alongside executable!\n", irc.TimeStamp())
 | 
						|
			if _, err := os.Stat("/etc/karaokards/config.json"); os.IsNotExist(err) {
 | 
						|
				rgb.RPrintf("[%s] Error, KARAOKARDS_CONFIGFILE env var unset and neither '%s' nor '%s' exist!\n", irc.TimeStamp(), exPath + "/config.json", "/etc/karaokards/config.json")
 | 
						|
				os.Exit(1)
 | 
						|
			} else {
 | 
						|
				configFile = "/etc/karaokards/config.json"
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			configFile = exPath + "/config.json"
 | 
						|
		}
 | 
						|
	}
 | 
						|
	data, err = ioutil.ReadFile(configFile)
 | 
						|
	if err != nil {
 | 
						|
		rgb.RPrintf("[%s] Could not read `%s`. File reading error: %s\n", irc.TimeStamp(), configFile, err)
 | 
						|
		os.Exit(1)
 | 
						|
	}
 | 
						|
	err = json.Unmarshal(data, &customStrings)
 | 
						|
	if err != nil {
 | 
						|
		rgb.RPrintf("[%s] Could not unmarshal `%s`. Unmarshal error: %s\n", irc.TimeStamp(), configFile, err)
 | 
						|
		os.Exit(1)
 | 
						|
	}
 | 
						|
	rgb.YPrintf("[%s] Read config file from `%s`\n", irc.TimeStamp(), configFile)
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
//openDatabase "database" in this sense being a scribble db
 | 
						|
func openDatabase() *scribble.Driver {
 | 
						|
	dataPath := ""
 | 
						|
	if config.DataPath == "" {
 | 
						|
		if os.Getenv("KARAOKARDS_DATA_FOLDER") != "" {
 | 
						|
			if _, err := os.Stat(os.Getenv("KARAOKARDS_DATA_FOLDER")); os.IsNotExist(err) {
 | 
						|
				rgb.RPrintf("[%s] Error, KARAOKARDS_DATA_FOLDER env var set and '%s' doesn't exist!\n", irc.TimeStamp(), os.Getenv("KARAOKARDS_DATA_FOLDER"))
 | 
						|
				os.Exit(1)
 | 
						|
			}
 | 
						|
			dataPath = os.Getenv("KARAOKARDS_DATA_FOLDER")
 | 
						|
		} else {
 | 
						|
			ex, err := os.Executable()
 | 
						|
			if err != nil {
 | 
						|
				rgb.RPrintf("[%s] Error, KARAOKARDS_DATA_FOLDER env var unset and cannot find executable!\n", irc.TimeStamp())
 | 
						|
				os.Exit(1)
 | 
						|
			}
 | 
						|
			exPath := filepath.Dir(ex)
 | 
						|
			if _, err := os.Stat(exPath + "/data"); os.IsNotExist(err) {
 | 
						|
				rgb.YPrintf("[%s] Warning %s doesn't exist, trying to create it.\n", irc.TimeStamp(), exPath + "/data")
 | 
						|
				err = os.Mkdir(exPath + "/data", 0770)
 | 
						|
				if err != nil {
 | 
						|
					rgb.RPrintf("[%s] Error cannot create %s: %s!\n", irc.TimeStamp(), exPath + "/data", err)
 | 
						|
					os.Exit(1)
 | 
						|
				}
 | 
						|
			}
 | 
						|
			dataPath = exPath + "/data"
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		if _, err := os.Stat(config.OAuthPath); os.IsNotExist(err) {
 | 
						|
			rgb.RPrintf("[%s] Error, config-specified path '%s' doesn't exist!\n", irc.TimeStamp(), os.Getenv("KARAOKARDS_DATA_FOLDER"))
 | 
						|
			os.Exit(1)
 | 
						|
		}
 | 
						|
		dataPath = config.DataPath
 | 
						|
	}
 | 
						|
	db, err := scribble.New(dataPath, nil)
 | 
						|
	if err != nil {
 | 
						|
		rgb.RPrintf("[%s] Error opening database in '%s' : %s\n", irc.TimeStamp(), dataPath, err)
 | 
						|
		os.Exit(1)
 | 
						|
	}
 | 
						|
	return db
 | 
						|
}
 | 
						|
 | 
						|
func readBonusStrings() []string {
 | 
						|
	var data []byte
 | 
						|
	var err error
 | 
						|
	if config.StringPath == "" {
 | 
						|
		ex, err := os.Executable()
 | 
						|
		if err != nil {
 | 
						|
			rgb.YPrintf("[%s] Could not read `strings.json`, will only have builtin prompts. File reading error: %s\n", irc.TimeStamp(), err)
 | 
						|
			return []string{}
 | 
						|
		}
 | 
						|
		exPath := filepath.Dir(ex)
 | 
						|
		data, err = ioutil.ReadFile(exPath + "/strings.json")
 | 
						|
		if err != nil {
 | 
						|
			rgb.YPrintf("[%s] Could not read `strings.json`, will only have builtin prompts. File reading error: %s\n", irc.TimeStamp(), err)
 | 
						|
			return []string{}
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		data, err = ioutil.ReadFile(config.StringPath)
 | 
						|
		if err != nil {
 | 
						|
			rgb.YPrintf("[%s] Could not read `strings.json`, will only have builtin prompts. File reading error: %s\n", irc.TimeStamp(), err)
 | 
						|
			return []string{}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	err = json.Unmarshal(data, &customStrings)
 | 
						|
	if err != nil {
 | 
						|
		rgb.YPrintf("[%s] Could not unmarshal `strings.json`, will only have builtin prompts. Unmarshal error: %s\n", irc.TimeStamp(), err)
 | 
						|
		return []string{}
 | 
						|
	}
 | 
						|
	rgb.YPrintf("[%s] Read %d prompts from `strings.json`\n", irc.TimeStamp(), len(customStrings.Strings))
 | 
						|
	return customStrings.Strings
 | 
						|
}
 | 
						|
 | 
						|
var buildDate string
 | 
						|
 | 
						|
func main() {
 | 
						|
	rgb.YPrintf("[%s] starting karaokard bot build %s\n", irc.TimeStamp(), buildDate)
 | 
						|
	readConfig()
 | 
						|
	rand.Seed(time.Now().UnixNano())
 | 
						|
	for _, val := range builtins.Karaokards {
 | 
						|
		selectablePrompts = append(selectablePrompts, val)
 | 
						|
	}
 | 
						|
	for _, val := range readBonusStrings() {
 | 
						|
		selectablePrompts = append(selectablePrompts, val)
 | 
						|
	}
 | 
						|
	persistentData := openDatabase()
 | 
						|
	var dbGlobalPrompts []string
 | 
						|
	if err := persistentData.Read("prompts", "global", &dbGlobalPrompts); err != nil {
 | 
						|
		persistentData.Write("prompts", "common", dbGlobalPrompts)
 | 
						|
	}
 | 
						|
	selectablePrompts := append(selectablePrompts, dbGlobalPrompts...)
 | 
						|
 | 
						|
	rgb.YPrintf("[%s] %d prompts available.\n", irc.TimeStamp(), len(selectablePrompts))
 | 
						|
	oauthPath := ""
 | 
						|
	if config.OAuthPath == "" {
 | 
						|
		if os.Getenv("TWITCH_OAUTH_JSON") != "" {
 | 
						|
			if _, err := os.Stat(os.Getenv("TWITCH_OAUTH_JSON")); os.IsNotExist(err) {
 | 
						|
				os.Exit(1)
 | 
						|
			}
 | 
						|
			oauthPath = os.Getenv("TWITCH_OAUTH_JSON")
 | 
						|
		} else {
 | 
						|
			if _, err := os.Stat(os.Getenv("HOME") + "/.twitch/oauth.json"); os.IsNotExist(err) {
 | 
						|
				rgb.YPrintf("[%s] Warning %s doesn't exist, trying %s next!\n", irc.TimeStamp(), os.Getenv("HOME")+"/.twitch/oauth.json", "/etc/twitch/oauth.json")
 | 
						|
				if _, err := os.Stat("/etc/twitch/oauth.json"); os.IsNotExist(err) {
 | 
						|
					rgb.YPrintf("[%s] Error %s doesn't exist either, bailing!\n", irc.TimeStamp(), "/etc/twitch/oauth.json")
 | 
						|
					os.Exit(1)
 | 
						|
				}
 | 
						|
				oauthPath = "/etc/twitch/oauth.json"
 | 
						|
			} else {
 | 
						|
				oauthPath = os.Getenv("HOME") + "/.twitch/oauth.json"
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		if _, err := os.Stat(config.OAuthPath); os.IsNotExist(err) {
 | 
						|
			rgb.YPrintf("[%s] Error config-specified oauth file %s doesn't exist, bailing!\n", irc.TimeStamp(), config.OAuthPath)
 | 
						|
			os.Exit(1)
 | 
						|
		}
 | 
						|
		oauthPath = config.OAuthPath
 | 
						|
	}
 | 
						|
 | 
						|
	// Replace the channel name, bot name, and the path to the private directory with your respective
 | 
						|
	// values.
 | 
						|
	myBot := irc.KardBot{
 | 
						|
		Channel:     "imartynontwitch",
 | 
						|
		MsgRate:     time.Duration(20/30) * time.Millisecond,
 | 
						|
		Name:        "Karaokards",
 | 
						|
		Port:        "6667",
 | 
						|
		PrivatePath: oauthPath,
 | 
						|
		Server:      "irc.chat.twitch.tv",
 | 
						|
		Prompts:     selectablePrompts,
 | 
						|
		Database:    *persistentData,
 | 
						|
	}
 | 
						|
	go func() {
 | 
						|
		rgb.YPrintf("[%s] Starting webserver on port %s\n", irc.TimeStamp(), "5353")
 | 
						|
		webserver.HandleHTTP(&myBot)
 | 
						|
	}()
 | 
						|
	myBot.Start()
 | 
						|
}
 |