Multi-channel support and deployment for webserver.
continuous-integration/drone/tag Build is passing Details
continuous-integration/drone/push Build is passing Details

Signed-off-by: Martyn Ranyard <m@rtyn.berlin>
This commit is contained in:
Martyn 2020-02-14 15:56:10 +01:00
parent deb12318b6
commit a9dc6db0a4
6 changed files with 62 additions and 29 deletions

View File

@ -10,4 +10,6 @@ FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /go/src/git.martyn.berlin/martyn/karaokards /app/
COPY strings.json /app/strings.json
COPY web/ /app/web/
WORKDIR /app
CMD ["/app/karaokards"]

View File

@ -21,9 +21,9 @@ const PSTFormat = "Jan 2 15:04:05 PST"
// Regex for parsing PRIVMSG strings.
//
// First matched group is the user's name and the second matched group is the content of the
// First matched group is the user's name, second is the channel? and the third matched group is the content of the
// user's message.
var MsgRegex *regexp.Regexp = regexp.MustCompile(`^:(\w+)!\w+@\w+\.tmi\.twitch\.tv (PRIVMSG) #\w+(?: :(.*))?$`)
var MsgRegex *regexp.Regexp = regexp.MustCompile(`^:(\w+)!\w+@\w+\.tmi\.twitch\.tv (PRIVMSG) #(\w+)(?: :(.*))?$`)
// Regex for parsing user commands, from already parsed PRIVMSG strings.
//
@ -38,6 +38,9 @@ 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 {
@ -111,10 +114,11 @@ func (bb *KardBot) HandleChat() error {
if nil != matches {
userName := matches[1]
msgType := matches[2]
channel := matches[3]
switch msgType {
case "PRIVMSG":
msg := matches[3]
msg := matches[4]
rgb.GPrintf("[%s] %s: %s\n", TimeStamp(), userName, msg)
// parse commands from user message
@ -124,9 +128,9 @@ func (bb *KardBot) HandleChat() error {
switch cmd {
case "card":
rgb.CPrintf("[%s] Card asked for!\n", TimeStamp())
rgb.CPrintf("[%s] Card asked for by %s on %s' channel!\n", TimeStamp(), userName, channel)
bb.Say("Your prompt is : " + bb.Prompts[rand.Intn(len(bb.Prompts))])
bb.Say("Your prompt is : "+bb.Prompts[rand.Intn(len(bb.Prompts))], channel)
}
// channel-owner specific commands
@ -147,6 +151,7 @@ func (bb *KardBot) HandleChat() error {
}
default:
// do nothing
rgb.YPrintf("[%s] unknown IRC message : %s\n", TimeStamp(), line)
}
}
}
@ -154,14 +159,24 @@ func (bb *KardBot) HandleChat() error {
}
}
// Makes the bot join its pre-specified channel.
func (bb *KardBot) JoinChannel() {
rgb.YPrintf("[%s] Joining #%s...\n", TimeStamp(), bb.Channel)
// Login to the IRC server
func (bb *KardBot) Login() {
rgb.YPrintf("[%s] Logging into #%s...\n", TimeStamp(), bb.Channel)
bb.conn.Write([]byte("PASS " + bb.Credentials.Password + "\r\n"))
bb.conn.Write([]byte("NICK " + bb.Name + "\r\n"))
bb.conn.Write([]byte("JOIN #" + bb.Channel + "\r\n"))
}
rgb.YPrintf("[%s] Joined #%s as @%s!\n", TimeStamp(), bb.Channel, bb.Name)
// Makes the bot join its pre-specified channel.
func (bb *KardBot) JoinChannel(channels ...string) {
if len(channels) == 0 {
channels = append(channels, bb.Channel)
}
for _, channel := range channels {
rgb.YPrintf("[%s] Joining #%s...\n", TimeStamp(), channel)
bb.conn.Write([]byte("JOIN #" + channel + "\r\n"))
rgb.YPrintf("[%s] Joined #%s as @%s!\n", TimeStamp(), channel, bb.Name)
}
}
// Reads from the private credentials file and stores the data in the bot's Credentials field.
@ -185,7 +200,7 @@ func (bb *KardBot) ReadCredentials() error {
}
// Makes the bot send a message to the chat channel.
func (bb *KardBot) Say(msg string) error {
func (bb *KardBot) Say(msg string, channels ...string) error {
if "" == msg {
return errors.New("BasicBot.Say: msg was empty.")
}
@ -195,10 +210,18 @@ func (bb *KardBot) Say(msg string) error {
return errors.New("BasicBot.Say: msg exceeded 512 bytes")
}
_, err := bb.conn.Write([]byte(fmt.Sprintf("PRIVMSG #%s :%s\r\n", bb.Channel, msg)))
if len(channels) == 0 {
channels = append(channels, bb.Channel)
}
rgb.YPrintf("[%s] sending %s to channels %v as @%s!\n", TimeStamp(), msg, channels, bb.Name)
for _, channel := range channels {
_, err := bb.conn.Write([]byte(fmt.Sprintf("PRIVMSG #%s :%s\r\n", channel, msg)))
rgb.YPrintf("[%s] PRIVMSG #%s :%s\r\n", TimeStamp(), channel, msg)
if nil != err {
return err
}
}
return nil
}
@ -215,7 +238,12 @@ func (bb *KardBot) Start() {
for {
bb.Connect()
bb.Login()
if len(bb.Credentials.Channels) > 0 {
bb.JoinChannel(bb.Credentials.Channels...)
} else {
bb.JoinChannel()
}
err = bb.HandleChat()
if nil != err {

View File

@ -1,9 +1,11 @@
package webserver
import (
"math/rand"
irc "git.martyn.berlin/martyn/karaokards/internal/irc"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
"fmt"
"html/template"
@ -15,7 +17,7 @@ import (
//var store = sessions.NewCookieStore(os.Getenv("SESSION_KEY"))
var store = sessions.NewCookieStore([]byte("GO_SESS"))
var ircBot irc.KardBot
func HealthHandler(response http.ResponseWriter, request *http.Request) {
response.Header().Add("Content-type", "text/plain")
@ -44,6 +46,8 @@ func TemplateHandler(response http.ResponseWriter, request *http.Request) {
type TemplateData struct {
Prompt string
AvailCount int
ChannelCount int
MessageCount int
}
// tmpl, err := template.New("html"+request.URL.Path).Funcs(template.FuncMap{
// "ToUpper": strings.ToUpper,
@ -68,7 +72,7 @@ func TemplateHandler(response http.ResponseWriter, request *http.Request) {
// NotFoundHandler(response, request)
// return
}
var td = TemplateData{"Hello", 1}
var td = TemplateData{ircBot.Prompts[rand.Intn(len(ircBot.Prompts))], len(ircBot.Prompts), len(ircBot.Credentials.Channels), 0}
err = tmpl.Execute(response, td)
if err != nil {
http.Error(response, err.Error(), http.StatusInternalServerError)
@ -76,7 +80,8 @@ func TemplateHandler(response http.ResponseWriter, request *http.Request) {
}
}
func HandleHTTP() {
func HandleHTTP(passedIrcBot irc.KardBot) {
ircBot = passedIrcBot
r := mux.NewRouter()
loggedRouter := handlers.LoggingHandler(os.Stdout, r)
r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)

View File

@ -86,7 +86,7 @@ func main() {
}
go func() {
rgb.YPrintf("[%s] Starting webserver on port %s\n", irc.TimeStamp(), "5353")
webserver.HandleHTTP()
webserver.HandleHTTP(myBot)
}()
myBot.Start()
}

View File

@ -4,9 +4,9 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Templates files for the workshop">
<meta name="description" content="Karaokards">
<meta name="author" content="Martyn Ranyard">
<title>The k8s zoo</title>
<title>The great unknown!</title>
<!-- Bootstrap core CSS -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
@ -47,7 +47,6 @@
a{
text-decoration-line: underline;
}
</style>
</head>
<body class="text-center">
@ -64,8 +63,7 @@
<h1 class="cover-heading">Ooops!</h1>
<p>It seems you've gone somewhere you shouldn't! 404 NOT FOUND!</p>
<p/>
<p>This can happen if you enter the spotify id wrong and search, go back and check it!</p>
<p class="lead">Spotify IDs look like this : 37i9dQZF1DX4UtSsGT1Sbe - 22 characters and can be got by clicking share and "Copy (Playlist|Album) Link".</p>
<p>I'm not quite sure how you got here to be honest, if it was via a link on the site, let me know via twitch DM, if it was from someone else, let them know.</p>
<p>Shameless self-promotion : Follow me on twitch - <a href="https://www.twitch.tv/iMartynOnTwitch">iMartynOnTwitch</a>, oddly enough, I do a lot of twitchsings!</p>
</main>
<footer class="mastfoot mt-auto">

View File

@ -54,7 +54,7 @@
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
<header class="masthead mb-auto">
<div class="inner">
<h3 class="masthead-brand">k8s-zoo</h3>
<h3 class="masthead-brand">Karaokards</h3>
<nav class="nav nav-masthead justify-content-center">
<a class="nav-link active" href="/">Home</a>
</nav>
@ -63,7 +63,7 @@
<main role="main" class="inner cover">
<h1 class="cover-heading">Karaokards!!!</h1>
<p>Random prompt for you : {{.Prompt}}</p>
<p>There are a total of {{.AvailCount}} prompts available.</p>
<p>There are a total of {{.AvailCount}} prompts available. This bot is hanging out in {{.ChannelCount}} channels and has served {{.MessageCount}} prompts via twitch chat!</p>
</main>
<footer class="mastfoot mt-auto">
<div class="inner">