Initial implementation
This commit is contained in:
parent
1a2a0196e5
commit
ba287dd2e8
210
main.go
210
main.go
|
|
@ -2,39 +2,146 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/diamondburned/arikawa/v3/api"
|
||||
"github.com/diamondburned/arikawa/v3/discord"
|
||||
"github.com/diamondburned/arikawa/v3/gateway"
|
||||
"github.com/diamondburned/arikawa/v3/session"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
const (
|
||||
writeWait = 10 * time.Second
|
||||
pingPeriod = 50 * time.Second
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{}
|
||||
|
||||
type mtag string
|
||||
|
||||
const (
|
||||
mtagOnDiscordChat mtag = "on_discord_chat"
|
||||
mtagOnMinecraftChat mtag = "on_minecraft_chat"
|
||||
mtagNothing mtag = "nothing"
|
||||
)
|
||||
|
||||
type message struct {
|
||||
Tag mtag
|
||||
OnDiscordChat *onDiscordChatMessage
|
||||
OnMinecraftChat *onMinecraftChatMessage
|
||||
}
|
||||
|
||||
type onDiscordChatMessage struct {
|
||||
SenderNickname string
|
||||
SenderUsername string
|
||||
Content string
|
||||
}
|
||||
|
||||
type onMinecraftChatMessage struct {
|
||||
Sender string
|
||||
Content string
|
||||
}
|
||||
|
||||
type skyBase struct {
|
||||
mu sync.RWMutex
|
||||
luaOutboxes []chan message
|
||||
goInbox chan message
|
||||
}
|
||||
|
||||
func (sb *skyBase) luaDispatch(m message) {
|
||||
sb.mu.RLock()
|
||||
defer sb.mu.RUnlock()
|
||||
for _, ch := range sb.luaOutboxes {
|
||||
ch <- m
|
||||
}
|
||||
}
|
||||
|
||||
var base *skyBase
|
||||
|
||||
func handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("hello from skybase"))
|
||||
}
|
||||
|
||||
func handleChat(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
ws, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
outbox := make(chan message, 10)
|
||||
base.mu.Lock()
|
||||
base.luaOutboxes = append(base.luaOutboxes, outbox)
|
||||
base.mu.Unlock()
|
||||
|
||||
defer func() {
|
||||
ws.Close()
|
||||
base.mu.Lock()
|
||||
for i, ch := range base.luaOutboxes {
|
||||
if ch != outbox {
|
||||
continue
|
||||
}
|
||||
base.luaOutboxes[i] = base.luaOutboxes[len(base.luaOutboxes)-1]
|
||||
base.luaOutboxes = base.luaOutboxes[:len(base.luaOutboxes)-1]
|
||||
close(ch)
|
||||
}
|
||||
base.mu.Unlock()
|
||||
}()
|
||||
|
||||
pingTicker := time.NewTicker(pingPeriod)
|
||||
defer pingTicker.Stop()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
go func() {
|
||||
defer cancel()
|
||||
for {
|
||||
_, data, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var msg message
|
||||
if err = json.Unmarshal(data, &msg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
base.goInbox <- msg
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
mt, message, err := c.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
select {
|
||||
case <-pingTicker.C:
|
||||
ws.SetWriteDeadline(time.Now().Add(writeWait))
|
||||
if err = ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
|
||||
return
|
||||
}
|
||||
case msg := <-outbox:
|
||||
data, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.WriteMessage(mt, message)
|
||||
if err != nil {
|
||||
break
|
||||
log.Println("sending", string(data))
|
||||
|
||||
ws.SetWriteDeadline(time.Now().Add(writeWait))
|
||||
if err = ws.WriteMessage(websocket.TextMessage, data); err != nil {
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -47,25 +154,95 @@ func main() {
|
|||
if token == "" {
|
||||
log.Fatal("missing bot token")
|
||||
}
|
||||
channelID, err := strconv.ParseUint(os.Getenv("CHANNEL_ID"), 10, 64)
|
||||
if err != nil {
|
||||
log.Fatal("missing channel ID")
|
||||
}
|
||||
httpListen := os.Getenv("HTTP_LISTEN")
|
||||
if httpListen == "" {
|
||||
log.Fatal("missing http listen address")
|
||||
}
|
||||
|
||||
// init base
|
||||
base = &skyBase{
|
||||
luaOutboxes: []chan message{},
|
||||
goInbox: make(chan message, 10),
|
||||
}
|
||||
|
||||
// init session
|
||||
s := session.New("Bot " + token)
|
||||
id := gateway.DefaultIdentifier("Bot " + token)
|
||||
id.Presence = &gateway.UpdatePresenceCommand{
|
||||
Status: discord.DoNotDisturbStatus,
|
||||
Activities: []discord.Activity{{
|
||||
Type: discord.CustomActivity,
|
||||
Name: "whatever",
|
||||
State: "PQJDfhkjldalsljkfhasd",
|
||||
}},
|
||||
}
|
||||
s := session.NewWithIdentifier(id)
|
||||
s.AddHandler(func(c *gateway.ReadyEvent) {
|
||||
u, err := s.Me()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("started as", u.Username)
|
||||
|
||||
channelID := discord.ChannelID(channelID)
|
||||
|
||||
for msg := range base.goInbox {
|
||||
switch msg.Tag {
|
||||
case mtagOnMinecraftChat:
|
||||
p := msg.OnMinecraftChat
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if p.Content == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
filtered := strings.ReplaceAll(p.Content, "`", "\\`")
|
||||
filtered = strings.ReplaceAll(filtered, "|", "\\|")
|
||||
filtered = strings.ReplaceAll(filtered, "*", "\\*")
|
||||
filtered = strings.ReplaceAll(filtered, "_", "\\_")
|
||||
filtered = strings.ReplaceAll(filtered, "#", "\\#")
|
||||
filtered = strings.ReplaceAll(filtered, "[", "\\[")
|
||||
filtered = strings.ReplaceAll(filtered, "-", "\\-")
|
||||
filtered = strings.ReplaceAll(filtered, ".", "\\.")
|
||||
filtered = strings.ReplaceAll(filtered, ">", "\\>")
|
||||
log.Printf("<%s> %s\n", p.Sender, p.Content)
|
||||
|
||||
r, _ := utf8.DecodeRuneInString(p.Content)
|
||||
isAlphanumeric := unicode.IsLetter(r) || unicode.IsNumber(r)
|
||||
if !isAlphanumeric {
|
||||
continue
|
||||
}
|
||||
|
||||
s.SendMessageComplex(channelID, api.SendMessageData{
|
||||
Content: fmt.Sprintf("<%s> %s", p.Sender, filtered),
|
||||
AllowedMentions: &api.AllowedMentions{},
|
||||
Flags: discord.SuppressEmbeds | discord.SuppressNotifications,
|
||||
})
|
||||
case mtagNothing:
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
s.AddHandler(func(c *gateway.MessageCreateEvent) {
|
||||
if c.Author.Bot {
|
||||
return
|
||||
}
|
||||
log.Println(c.Author.Username, "sent", c.Content)
|
||||
|
||||
log.Printf("[@%s] %s\n", c.Author.DisplayName, c.Content)
|
||||
base.luaDispatch(message{
|
||||
Tag: mtagOnDiscordChat,
|
||||
OnDiscordChat: &onDiscordChatMessage{
|
||||
SenderUsername: c.Author.Username,
|
||||
SenderNickname: c.Author.DisplayName,
|
||||
Content: c.Content,
|
||||
},
|
||||
})
|
||||
})
|
||||
s.AddIntents(gateway.IntentGuildMessages)
|
||||
|
||||
|
|
@ -74,17 +251,16 @@ func main() {
|
|||
http.HandleFunc("/chat", handleChat)
|
||||
|
||||
// begin
|
||||
var wg sync.WaitGroup
|
||||
wg.Go(func() {
|
||||
go func() {
|
||||
if err := s.Connect(context.Background()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
})
|
||||
wg.Go(func() {
|
||||
}()
|
||||
go func() {
|
||||
http.ListenAndServe(httpListen, nil)
|
||||
})
|
||||
}()
|
||||
|
||||
// wait
|
||||
wg.Wait()
|
||||
select {}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue