Common code for implementing Twitch bots.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
3.4 KiB

package bot
import (
"net/http"
"raccatta.cc/bot/unstable/webservice"
"github.com/VictoriaMetrics/metrics"
)
type ServiceImpl interface {
SendRaw(raw string)
ExternalSay(login string, frags []string, command bool) bool
ExternalSayID(id string, frags []string, command bool) bool
RemoveTargetLogin(login string) error
SetTargetConfig(id, login string, config map[string]string) (string, error)
TargetConfig(login string) map[string]string
}
type existsResp struct {
Exists bool `json:"exists"`
}
func notFound(ctx *webservice.Context) error {
return ctx.Error(404, "NOT_FOUND", "The requested path was not found")
}
func botService(b ServiceImpl) *webservice.Server {
ws := webservice.New()
ws.Router.NotFoundHandler = webservice.Handler(notFound)
r := ws.Router
r.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
metrics.WritePrometheus(w, true)
})
r.HandleFunc("/raw", webservice.Handler(func(ctx *webservice.Context) error {
var req struct {
Raw string `json:"raw"`
}
if err := ctx.Decode(&req); err != nil || req.Raw == "" {
return ctx.Error(400, "BAD_REQUEST", err)
}
b.SendRaw(req.Raw)
return nil
}))
r.HandleFunc("/channels/{login}/config", webservice.Handler(func(ctx *webservice.Context) error {
login := ctx.Vars()["login"]
return ctx.Respond(b.TargetConfig(login))
})).Methods("GET")
r.HandleFunc("/channels/{login}/config", webservice.Handler(func(ctx *webservice.Context) error {
var req map[string]string
if err := ctx.Decode(&req); err != nil {
return ctx.Error(400, "BAD_REQUEST", err)
}
login := ctx.Vars()["login"]
id := ctx.Req.Header.Get("Twitch-ID") // Required to support renaming
if id == "" {
// Temp
return ctx.Error(400, "MISSING_ID", "Missing user-id!")
}
prev, err := b.SetTargetConfig(id, login, req)
if err != nil {
return err
}
return ctx.Respond(struct {
PrevLogin string `json:"prevlogin"`
}{prev})
})).Methods("POST")
r.HandleFunc("/channels/{login}/remove", webservice.Handler(func(ctx *webservice.Context) error {
var req struct{}
if err := ctx.Decode(&req); err != nil {
return ctx.Error(400, "BAD_REQUEST", err)
}
login := ctx.Vars()["login"]
return b.RemoveTargetLogin(login)
})).Methods("POST")
// Send a message to the channel (auto rate-limited)
r.HandleFunc("/channels/{login}/message", webservice.Handler(func(ctx *webservice.Context) error {
var req struct {
Msg string `json:"msg"`
Fragments []string `json:"frags"`
Command bool `json:"cmd"`
}
if err := ctx.Decode(&req); err != nil {
return ctx.Error(400, "BAD_REQUEST", err)
}
login := ctx.Vars()["login"]
frags := req.Fragments
if len(frags) == 0 {
frags = []string{req.Msg}
}
return ctx.Respond(existsResp{
b.ExternalSay(login, frags, req.Command),
})
})).Methods("POST")
// Send a message to the channel (by ID) (auto rate-limited)
r.HandleFunc("/users/{id}/message", webservice.Handler(func(ctx *webservice.Context) error {
var req struct {
Msg string `json:"msg"`
Fragments []string `json:"frags"`
Command bool `json:"cmd"`
}
if err := ctx.Decode(&req); err != nil {
return ctx.Error(400, "BAD_REQUEST", err)
}
id := ctx.Vars()["id"]
frags := req.Fragments
if len(frags) == 0 {
frags = []string{req.Msg}
}
return ctx.Respond(existsResp{
b.ExternalSayID(id, frags, req.Command),
})
})).Methods("POST")
return ws
}