2020-07-14 18:56:20 +00:00
package main
import (
"encoding/json"
2020-09-05 16:14:56 +00:00
"fmt"
2020-07-14 18:56:20 +00:00
"io/ioutil"
"math/rand"
"os"
"path/filepath"
"time"
builtins "git.martyn.berlin/martyn/twitchsingstools/internal/builtins"
2020-09-05 16:14:56 +00:00
data "git.martyn.berlin/martyn/twitchsingstools/internal/data"
2020-07-14 18:56:20 +00:00
irc "git.martyn.berlin/martyn/twitchsingstools/internal/irc"
webserver "git.martyn.berlin/martyn/twitchsingstools/internal/webserver"
rgb "github.com/foresthoffman/rgblog"
scribble "github.com/nanobox-io/golang-scribble"
)
type customStringsStruct struct {
Strings [ ] string ` json:"strings,omitempty" `
}
var selectablePrompts [ ] string
var customStrings customStringsStruct
2020-09-05 16:14:56 +00:00
var config data . ConfigStruct
2020-07-14 18:56:20 +00:00
func readConfig ( ) {
var data [ ] byte
var err error
configFile := ""
if os . Getenv ( "TSTOOLS_CONFIGFILE" ) != "" {
if _ , err := os . Stat ( os . Getenv ( "TSTOOLS_CONFIGFILE" ) ) ; os . IsNotExist ( err ) {
rgb . RPrintf ( "[%s] Error, TSTOOLS_CONFIGFILE env var set and '%s' doesn't exist!\n" , irc . TimeStamp ( ) , os . Getenv ( "TSTOOLS_CONFIGFILE" ) )
os . Exit ( 1 )
}
configFile = os . Getenv ( "TSTOOLS_CONFIGFILE" )
} else {
ex , err := os . Executable ( )
if err != nil {
rgb . YPrintf ( "[%s] Warning, TSTOOLS_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, TSTOOLS_CONFIGFILE env var unset and `config.json` not alongside executable!\n" , irc . TimeStamp ( ) )
if _ , err := os . Stat ( "/etc/tstools/config.json" ) ; os . IsNotExist ( err ) {
rgb . RPrintf ( "[%s] Error, TSTOOLS_CONFIGFILE env var unset and neither '%s' nor '%s' exist!\n" , irc . TimeStamp ( ) , exPath + "/config.json" , "/etc/tstools/config.json" )
os . Exit ( 1 )
} else {
configFile = "/etc/tstools/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 , & config )
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 )
rgb . YPrintf ( "[%s] config %v\n" , irc . TimeStamp ( ) , config )
return
}
//openDatabase "database" in this sense being a scribble db
func openDatabase ( ) * scribble . Driver {
dataPath := ""
if config . DataPath == "" {
if os . Getenv ( "TSTOOLS_DATA_FOLDER" ) != "" {
if _ , err := os . Stat ( os . Getenv ( "TSTOOLS_DATA_FOLDER" ) ) ; os . IsNotExist ( err ) {
rgb . RPrintf ( "[%s] Error, TSTOOLS_DATA_FOLDER env var set and '%s' doesn't exist!\n" , irc . TimeStamp ( ) , os . Getenv ( "TSTOOLS_DATA_FOLDER" ) )
os . Exit ( 1 )
}
dataPath = os . Getenv ( "TSTOOLS_DATA_FOLDER" )
} else {
ex , err := os . Executable ( )
if err != nil {
rgb . RPrintf ( "[%s] Error, TSTOOLS_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 . DataPath ) ; os . IsNotExist ( err ) {
rgb . RPrintf ( "[%s] Error, config-specified path '%s' doesn't exist!\n" , irc . TimeStamp ( ) , config . DataPath )
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
}
var buildDate string
func main ( ) {
rgb . YPrintf ( "[%s] starting twitchsingstools bot build %s\n" , irc . TimeStamp ( ) , buildDate )
readConfig ( )
rand . Seed ( time . Now ( ) . UnixNano ( ) )
for _ , val := range builtins . Karaokards {
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 ) )
ircOauthPath := ""
if config . IrcOAuthPath == "" {
if os . Getenv ( "TSTOOLS_OAUTH_JSON" ) != "" {
if _ , err := os . Stat ( os . Getenv ( "TSTOOLS_OAUTH_JSON" ) ) ; os . IsNotExist ( err ) {
os . Exit ( 1 )
}
ircOauthPath = os . Getenv ( "TSTOOLS_OAUTH_JSON" )
} else {
if _ , err := os . Stat ( os . Getenv ( "HOME" ) + "/.tstools/ircoauth.json" ) ; os . IsNotExist ( err ) {
rgb . YPrintf ( "[%s] Warning %s doesn't exist, trying %s next!\n" , irc . TimeStamp ( ) , os . Getenv ( "HOME" ) + "/.tstools/ircoauth.json" , "/etc/tstools/ircoauth.json" )
if _ , err := os . Stat ( "/etc/tstools/ircoauth.json" ) ; os . IsNotExist ( err ) {
rgb . YPrintf ( "[%s] Error %s doesn't exist either, cannot connect to irc!\n" , irc . TimeStamp ( ) , "/etc/tstools/ircoauth.json" )
} else {
ircOauthPath = "/etc/tstools/ircoauth.json"
}
} else {
ircOauthPath = os . Getenv ( "HOME" ) + "/.tstools/ircoauth.json"
}
}
} else {
if _ , err := os . Stat ( config . IrcOAuthPath ) ; os . IsNotExist ( err ) {
rgb . YPrintf ( "[%s] Error config-specified oauth file %s doesn't exist, cannot connect to irc!\n" , irc . TimeStamp ( ) , config . IrcOAuthPath )
} else {
ircOauthPath = config . IrcOAuthPath
}
}
appOauthPath := ""
if config . AppOAuthPath == "" {
if os . Getenv ( "TSTOOLS_OAUTH_JSON" ) != "" {
if _ , err := os . Stat ( os . Getenv ( "TSTOOLS_OAUTH_JSON" ) ) ; os . IsNotExist ( err ) {
os . Exit ( 1 )
}
appOauthPath = os . Getenv ( "TSTOOLS_OAUTH_JSON" )
} else {
if _ , err := os . Stat ( os . Getenv ( "HOME" ) + "/.tstools/appoauth.json" ) ; os . IsNotExist ( err ) {
rgb . YPrintf ( "[%s] Warning %s doesn't exist, trying %s next!\n" , irc . TimeStamp ( ) , os . Getenv ( "HOME" ) + "/.tstools/appoauth.json" , "/etc/tstools/appoauth.json" )
if _ , err := os . Stat ( "/etc/tstools/appoauth.json" ) ; os . IsNotExist ( err ) {
rgb . YPrintf ( "[%s] Error %s doesn't exist either, bailing!\n" , irc . TimeStamp ( ) , "/etc/tstools/appoauth.json" )
os . Exit ( 1 )
}
appOauthPath = "/etc/tstools/appoauth.json"
} else {
appOauthPath = os . Getenv ( "HOME" ) + "/.tstools/appoauth.json"
}
}
} else {
if _ , err := os . Stat ( config . AppOAuthPath ) ; os . IsNotExist ( err ) {
2020-09-05 16:14:56 +00:00
rgb . RPrintf ( "[%s] Error config-specified oauth file %s doesn't exist, bailing!\n" , irc . TimeStamp ( ) , config . AppOAuthPath )
2020-07-14 18:56:20 +00:00
os . Exit ( 1 )
}
appOauthPath = config . AppOAuthPath
}
2020-09-05 16:14:56 +00:00
rgb . YPrintf ( "[%s] Starting connection to redis...\n" , irc . TimeStamp ( ) )
//TODO: unhardcode this
if os . Getenv ( "TSTOOLS_REDIS_HOST" ) != "" {
config . DatabaseSVC = os . Getenv ( "TSTOOLS_REDIS_HOST" )
} else {
// assume localhost, which should fail.
config . DatabaseSVC = "localhost"
}
var globalData data . GlobalData
globalData . Config = config
globalData . ConnectDatabase ( )
defer globalData . Database . Close ( )
rgb . GPrintf ( "[%s] Connected to \"redis\" %s\n" , irc . TimeStamp ( ) , "config.DatabaseSVC" )
err := globalData . ReadChannelData ( )
if nil != err {
fmt . Println ( err )
fmt . Println ( "Aborting!" )
os . Exit ( 1 )
}
rgb . GPrintf ( "[%s] Read the channel data from \"redis\" successfully, now have %d records\n" , irc . TimeStamp ( ) , len ( globalData . ChannelData ) )
2020-07-14 18:56:20 +00:00
// Replace the channel name, bot name, and the path to the private directory with your respective
// values.
var myBot irc . KardBot
if ircOauthPath != "" {
myBot = irc . KardBot {
Channel : "twitchsingstools" ,
MsgRate : time . Duration ( 20 / 30 ) * time . Millisecond ,
Name : "twitchsingstools" ,
Port : "6667" ,
IrcPrivatePath : ircOauthPath ,
AppPrivatePath : appOauthPath ,
Server : "irc.chat.twitch.tv" ,
Prompts : selectablePrompts ,
2020-09-05 16:14:56 +00:00
GlobalData : globalData ,
2020-07-14 18:56:20 +00:00
}
}
go func ( ) {
rgb . YPrintf ( "[%s] Starting webserver on port %s\n" , irc . TimeStamp ( ) , "5353" )
2020-09-05 16:14:56 +00:00
webserver . HandleHTTP ( & myBot , & globalData )
2020-07-14 18:56:20 +00:00
} ( )
2020-07-14 19:52:33 +00:00
if ircOauthPath != "" {
myBot . Start ( )
}
2020-07-14 18:56:20 +00:00
}