Merge branch 'improvements' of martyn/karaokards into master
This commit is contained in:
commit
3950f8b672
|
@ -0,0 +1,14 @@
|
|||
BUILD=`date +%FT%T%z`
|
||||
|
||||
LDFLAGS=-ldflags "-X main.buildDate=${BUILD}"
|
||||
|
||||
.PHONY: build deps static
|
||||
|
||||
build:
|
||||
go build ${LDFLAGS}
|
||||
|
||||
deps:
|
||||
go get
|
||||
|
||||
static:
|
||||
CGO_ENABLED=0 GOOS=linux go build ${LDFLAGS} -a -installsuffix cgo -o karaokards .
|
|
@ -2,9 +2,8 @@ FROM golang@sha256:cee6f4b901543e8e3f20da3a4f7caac6ea643fd5a46201c3c2387183a332d
|
|||
RUN apk update && apk add --no-cache git make ca-certificates && update-ca-certificates
|
||||
COPY main.go /go/src/git.martyn.berlin/martyn/karaokards/
|
||||
COPY internal/ /go/src/git.martyn.berlin/martyn/karaokards/internal/
|
||||
RUN cd /go/src/git.martyn.berlin/martyn/karaokards/; go get; CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o karaokards .
|
||||
#RUN ls /go/src/github.com/karaokards/ -l
|
||||
|
||||
COPY Makefile /go/src/git.martyn.berlin/martyn/karaokards/
|
||||
RUN cd /go/src/git.martyn.berlin/martyn/karaokards/; make deps ; make static
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"channels": ["iMartynOnTwitch"]
|
||||
"channels": ["iMartynOnTwitch"],
|
||||
"externalUrl": "karaokards.ing.martyn.berlin"
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
apiVersion: v1
|
||||
data:
|
||||
strings.json: "{\r\n \"strings\": [\r\n\t \"Let Pineboy choose!\",\r\n\t \"They're
|
||||
from the North\",\r\n \"Refers to food\"\r\n ]\r\n}"
|
||||
config.json: |
|
||||
{
|
||||
"channels": ["iMartynOnTwitch"],
|
||||
"externalUrl": "karaokards.ing.martyn.berlin"
|
||||
}
|
||||
strings.json: "{\r\n \"strings\": [\r\n\t \"They're from the North\",\r\n
|
||||
\ \"Refers to food\"\r\n ]\r\n}\n"
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
creationTimestamp: "2020-01-27T20:04:58Z"
|
||||
name: extracards
|
||||
namespace: karaokards
|
||||
resourceVersion: "48537355"
|
||||
selfLink: /api/v1/namespaces/karaokards/configmaps/extracards
|
||||
uid: 4b1d73b0-4140-11ea-94d8-9cb6540931b5
|
||||
name: kardconfig
|
||||
|
|
|
@ -24,7 +24,7 @@ spec:
|
|||
run: kardbot
|
||||
spec:
|
||||
containers:
|
||||
- image: imartyn/karaokardbot:0.0.3-linux-amd64
|
||||
- image: imartyn/karaokardbot:devel
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: kardbot
|
||||
ports:
|
||||
|
@ -39,6 +39,9 @@ spec:
|
|||
- mountPath: /app/strings.json
|
||||
name: extracards
|
||||
subPath: strings.json
|
||||
- mountPath: /app/config.json
|
||||
name: config
|
||||
subPath: config.json
|
||||
- mountPath: /data
|
||||
name: data
|
||||
dnsPolicy: ClusterFirst
|
||||
|
@ -56,8 +59,15 @@ spec:
|
|||
items:
|
||||
- key: strings.json
|
||||
path: strings.json
|
||||
name: kardconfig
|
||||
name: extracards
|
||||
name: extracards
|
||||
- configMap:
|
||||
defaultMode: 420
|
||||
items:
|
||||
- key: config.json
|
||||
path: config.json
|
||||
name: kardconfig
|
||||
name: config
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: kkard-data
|
|
@ -3,6 +3,7 @@ package irc
|
|||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -15,6 +16,8 @@ import (
|
|||
"time"
|
||||
|
||||
rgb "github.com/foresthoffman/rgblog"
|
||||
scribble "github.com/nanobox-io/golang-scribble"
|
||||
uuid "github.com/google/uuid"
|
||||
)
|
||||
|
||||
const PSTFormat = "Jan 2 15:04:05 PST"
|
||||
|
@ -38,9 +41,6 @@ type OAuthCred struct {
|
|||
|
||||
// The developer application client ID. Used for API calls to Twitch.
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
|
||||
// List of Channels to join
|
||||
Channels []string `json:"channels,omitempty"`
|
||||
}
|
||||
|
||||
type KardBot struct {
|
||||
|
@ -54,6 +54,16 @@ type KardBot struct {
|
|||
Server string
|
||||
startTime time.Time
|
||||
Prompts []string
|
||||
Database scribble.Driver
|
||||
channelData map[string]ChannelData
|
||||
}
|
||||
|
||||
type ChannelData struct {
|
||||
Name string `json:"name"`
|
||||
AdminKey string `json:"value,omitempty"`
|
||||
CustomCommand string `json:"customcommand,omitempty"`
|
||||
ExtraStrings string `json:"extrastrings,omitempty"`
|
||||
JoinTime time.Time `json:"jointime"`
|
||||
}
|
||||
|
||||
// Connects the bot to the Twitch IRC server. The bot will continue to try to connect until it
|
||||
|
@ -134,7 +144,7 @@ func (bb *KardBot) HandleChat() error {
|
|||
}
|
||||
|
||||
// channel-owner specific commands
|
||||
if userName == bb.Channel {
|
||||
if userName == channel {
|
||||
switch cmd {
|
||||
case "tbdown":
|
||||
rgb.CPrintf(
|
||||
|
@ -144,6 +154,14 @@ func (bb *KardBot) HandleChat() error {
|
|||
|
||||
bb.Disconnect()
|
||||
return nil
|
||||
case "wat":
|
||||
magicCode := bb.readOrCreateChannelKey(channel)
|
||||
rgb.CPrintf(
|
||||
"[%s] Magic code is %s - https://karaokards.ing.martyn.berlin/admin/%s/%s\n",
|
||||
TimeStamp(),
|
||||
magicCode, userName, magicCode,
|
||||
)
|
||||
bb.Say("Ack.")
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
|
@ -232,15 +250,24 @@ func (bb *KardBot) Start() {
|
|||
err := bb.ReadCredentials()
|
||||
if nil != err {
|
||||
fmt.Println(err)
|
||||
fmt.Println("Aborting...")
|
||||
fmt.Println("Aborting!")
|
||||
return
|
||||
}
|
||||
|
||||
err = bb.readChannelData()
|
||||
if nil != err {
|
||||
fmt.Println(err)
|
||||
fmt.Println("Aborting!")
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
bb.Connect()
|
||||
bb.Login()
|
||||
if len(bb.Credentials.Channels) > 0 {
|
||||
bb.JoinChannel(bb.Credentials.Channels...)
|
||||
if len(bb.channelData) > 0 {
|
||||
for channelName := range(bb.channelData) {
|
||||
bb.JoinChannel(channelName)
|
||||
}
|
||||
} else {
|
||||
bb.JoinChannel()
|
||||
}
|
||||
|
@ -257,6 +284,63 @@ func (bb *KardBot) Start() {
|
|||
}
|
||||
}
|
||||
|
||||
func (bb *KardBot) readChannelData() error {
|
||||
records, err := bb.Database.ReadAll("channelData")
|
||||
if err != nil {
|
||||
// no db? initialise one?
|
||||
record := ChannelData{Name: bb.Channel, JoinTime: time.Now()}
|
||||
rgb.YPrintf("[%s] No channel data for #%s exists, creating...\n", TimeStamp(), bb.Channel)
|
||||
if err := bb.Database.Write("channelData", bb.Channel, record); err != nil {
|
||||
return err
|
||||
}
|
||||
bb.channelData = make(map[string]ChannelData)
|
||||
bb.channelData[bb.Channel] = record;
|
||||
} else {
|
||||
bb.channelData = make(map[string]ChannelData)
|
||||
}
|
||||
for _, data := range records {
|
||||
record := ChannelData{}
|
||||
err := json.Unmarshal([]byte(data), &record);
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bb.channelData[record.Name] = record
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bb *KardBot) readOrCreateChannelKey(channel string) string {
|
||||
magicCode := ""
|
||||
var err error
|
||||
var record ChannelData
|
||||
if record, ok := bb.channelData[channel]; !ok {
|
||||
rgb.YPrintf("[%s] No channel data for #%s exists, creating\n", TimeStamp(), channel)
|
||||
err = bb.Database.Read("channelData", channel, &record);
|
||||
if err == nil {
|
||||
bb.channelData[channel] = record
|
||||
}
|
||||
}
|
||||
record = bb.channelData[channel]
|
||||
if err != nil || record.AdminKey == "" {
|
||||
rgb.YPrintf("[%s] No channel key for #%s exists, creating one\n", TimeStamp(), channel)
|
||||
newuu, _ := uuid.NewRandom()
|
||||
magicCode = base64.StdEncoding.EncodeToString([]byte(newuu.String()))
|
||||
record.AdminKey = magicCode
|
||||
if record.Name == "" {
|
||||
record.Name = channel
|
||||
}
|
||||
if err := bb.Database.Write("channelData", channel, record); err != nil {
|
||||
rgb.RPrintf("[%s] Error writing channel data for #%s\n", TimeStamp(), channel)
|
||||
}
|
||||
bb.channelData[record.Name] = record
|
||||
rgb.YPrintf("[%s] Cached channel key for #%s\n", TimeStamp(), record.Name)
|
||||
} else {
|
||||
magicCode = record.AdminKey
|
||||
rgb.YPrintf("[%s] Loaded data for #%s\n", TimeStamp(), channel)
|
||||
}
|
||||
return magicCode
|
||||
}
|
||||
|
||||
func TimeStamp() string {
|
||||
return TimeStampFmt(PSTFormat)
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ func HealthHandler(response http.ResponseWriter, request *http.Request) {
|
|||
|
||||
func NotFoundHandler(response http.ResponseWriter, request *http.Request) {
|
||||
response.Header().Add("X-Template-File", "html"+request.URL.Path)
|
||||
response.WriteHeader(404)
|
||||
tmpl := template.Must(template.ParseFiles("web/404.html"))
|
||||
tmpl.Execute(response, nil)
|
||||
}
|
||||
|
@ -72,7 +73,7 @@ func TemplateHandler(response http.ResponseWriter, request *http.Request) {
|
|||
// NotFoundHandler(response, request)
|
||||
// return
|
||||
}
|
||||
var td = TemplateData{ircBot.Prompts[rand.Intn(len(ircBot.Prompts))], len(ircBot.Prompts), len(ircBot.Credentials.Channels), 0}
|
||||
var td = TemplateData{ircBot.Prompts[rand.Intn(len(ircBot.Prompts))], len(ircBot.Prompts), 0, 0}
|
||||
err = tmpl.Execute(response, td)
|
||||
if err != nil {
|
||||
http.Error(response, err.Error(), http.StatusInternalServerError)
|
||||
|
@ -80,6 +81,11 @@ func TemplateHandler(response http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func AdminHandler(response http.ResponseWriter, request *http.Request) {
|
||||
request.URL.Path = "/index.html"
|
||||
TemplateHandler(response, request)
|
||||
}
|
||||
|
||||
func HandleHTTP(passedIrcBot irc.KardBot) {
|
||||
ircBot = passedIrcBot
|
||||
r := mux.NewRouter()
|
||||
|
@ -89,6 +95,7 @@ func HandleHTTP(passedIrcBot irc.KardBot) {
|
|||
r.HandleFunc("/healthz", HealthHandler)
|
||||
r.HandleFunc("/example/{.*}", TemplateHandler)
|
||||
r.HandleFunc("/cover.css", CSSHandler)
|
||||
r.HandleFunc("/admin/{channel}/{key}", AdminHandler)
|
||||
http.Handle("/", r)
|
||||
srv := &http.Server{
|
||||
Handler: loggedRouter,
|
||||
|
|
15
main.go
15
main.go
|
@ -70,7 +70,7 @@ func readConfig() {
|
|||
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] Read config file from `%s`\n", irc.TimeStamp(), configFile)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,10 @@ func readBonusStrings() []string {
|
|||
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 {
|
||||
|
@ -156,6 +159,13 @@ func main() {
|
|||
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 == "" {
|
||||
|
@ -183,8 +193,6 @@ func main() {
|
|||
}
|
||||
oauthPath = config.OAuthPath
|
||||
}
|
||||
persistentData := openDatabase()
|
||||
persistentData.Write("prompts", "common", selectablePrompts)
|
||||
|
||||
// Replace the channel name, bot name, and the path to the private directory with your respective
|
||||
// values.
|
||||
|
@ -196,6 +204,7 @@ func main() {
|
|||
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")
|
||||
|
|
Loading…
Reference in New Issue