Merge branch 'improvements' of martyn/karaokards into master
continuous-integration/drone/tag Build is passing Details
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Martyn 2020-02-21 19:56:31 +00:00 committed by Gitea
commit 3950f8b672
9 changed files with 150 additions and 26 deletions

14
Makefile Executable file
View File

@ -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 .

View File

@ -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/

View File

@ -1,3 +1,4 @@
{
"channels": ["iMartynOnTwitch"]
"channels": ["iMartynOnTwitch"],
"externalUrl": "karaokards.ing.martyn.berlin"
}

View File

@ -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

View File

@ -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: extracards
name: kardconfig
name: extracards
- configMap:
defaultMode: 420
items:
- key: config.json
path: config.json
name: kardconfig
name: config
- name: data
persistentVolumeClaim:
claimName: kkard-data

0
deployments/kubernetes/pvc.yaml Executable file → Normal file
View File

View File

@ -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,10 +284,67 @@ 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)
}
func TimeStampFmt(format string) string {
return time.Now().Format(format)
}
}

View File

@ -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
View File

@ -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")