This commit is contained in:
Hri7566 2024-04-18 07:45:29 -04:00
commit 79a2e631e6
5 changed files with 418 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.env
*.db

33
data.go Normal file
View File

@ -0,0 +1,33 @@
package main
import (
"log"
"strconv"
"github.com/syndtr/goleveldb/leveldb"
)
var db leveldb.DB
func SetupDb() {
db, err := leveldb.OpenFile("./bot2024.db", nil)
if err != nil {
log.Fatal(err)
}
defer db.Close()
}
func GetBalance(uid string) (float64, error) {
s, err := db.Get([]byte("userbal~" + uid), nil)
log.Println("here")
bal, _ := strconv.ParseFloat(string(s), 64)
return bal, err
}
func SetBalance(uid string, bal float64) (error) {
s := strconv.FormatFloat(bal, 'f', -1, 64)
err := db.Put([]byte("userbal~" + uid), []byte(s), nil)
return err
}

13
go.mod Normal file
View File

@ -0,0 +1,13 @@
module github.com/Hri7566/mpp-client-go
go 1.22.2
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/kataras/go-events v0.0.3 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
golang.org/x/net v0.17.0 // indirect
)

28
go.sum Normal file
View File

@ -0,0 +1,28 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kataras/go-events v0.0.3 h1:o5YK53uURXtrlg7qE/vovxd/yKOJcLuFtPQbf1rYMC4=
github.com/kataras/go-events v0.0.3/go.mod h1:bFBgtzwwzrag7kQmGuU1ZaVxhK2qseYPQomXoVEMsj4=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

342
main.go Normal file
View File

@ -0,0 +1,342 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"net/url"
"os"
"os/signal"
"strconv"
"strings"
"time"
"github.com/gorilla/websocket"
"github.com/joho/godotenv"
)
var addr = flag.String("addr", "mppclone.com:8443", "websocket address")
type User struct {
Uid string `json:"_id"`
Name string `json:"name"`
Color string `json:"color"`
}
type Participant struct {
User
Id string `json:"id"`
}
type MppMessage struct {
Type string `json:"m"`
}
type HiMessage struct {
MppMessage
Timestamp json.Number `json:"t"`
User User `json:"u"`
Motd string `json:"motd"`
}
type NqMessage struct {
MppMessage
Allowance json.Number `json:"allowance"`
Max json.Number `json:"max"`
MaxHistLen json.Number `json:"maxHistLen"`
}
type ChatMessage struct {
MppMessage
Message string `json:"a"`
Part Participant `json:"p"`
Timestamp json.Number `json:"t"`
}
type TMessage struct {
MppMessage
Timestamp json.Number `json:"t"`
Echo json.Number `json:"e"`
}
type Channel struct {
Id string `json:"_id"`
Id2 string `json:"id"`
}
type ChMessage struct {
MppMessage
Channel Channel `json:"ch"`
Participants []Participant `json:"ppl"`
}
type AnyMppMessage []interface{}
var token string
func main() {
helpCommands = commands
SetupDb()
flag.Parse()
log.SetFlags(0)
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
token = os.Getenv("MPPNET_TOKEN")
StartSocket(addr)
}
func StartSocket(address *string) {
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
url := url.URL{Scheme: "wss", Host: *addr}
ws, _, err := websocket.DefaultDialer.Dial(url.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer ws.Close()
done := make(chan struct{})
serverTicker := time.NewTicker(15 * time.Second)
serverTickerQuit := make(chan struct{})
go func() {
for {
select {
case <- serverTicker.C:
SendTimeMessage(ws)
case <- serverTickerQuit:
serverTicker.Stop()
}
}
}()
go func() {
defer close(done)
for {
_, message, err := ws.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
// log.Printf("recv: %s", message)
go ReceiveMessage(ws, message)
// if (!sentHi) {
// // histr := "[{\"m\":\"hi\"},{\"m\":\"ch\",\"_id\":\"✧𝓓𝓔𝓥 𝓡𝓸𝓸𝓶✧\"}]"
// histr := "[{\"m\":\"hi\",\"token\":\"" + *token + "\"}]"
// println("Sending hi message: " + histr)
// err := ws.WriteMessage(1, []byte(histr))
// if err != nil {
// log.Println(err)
// }
// SendTimeMessage(ws)
// sentHi = true
// }
}
}()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-done:
return
case <-interrupt:
log.Println("interrupt")
err := ws.WriteMessage(
websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""),
)
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}
}
func ReceiveMessage(ws *websocket.Conn, data []byte) {
var tmp []json.RawMessage
err := json.Unmarshal(data, &tmp)
if err != nil {
log.Fatal(err)
return
}
var header struct {
Type string `json:"m"`
}
for _, raw := range tmp {
_ = json.Unmarshal(raw, &header)
switch header.Type {
case "hi":
msg := HiMessage{}
_ = json.Unmarshal(raw, &msg)
ReceiveHiMessage(ws, &msg)
case "nq":
msg := NqMessage{}
_ = json.Unmarshal(raw, &msg)
ReceiveNqMessage(&msg)
case "t":
msg := TMessage{}
_ = json.Unmarshal(raw, &msg)
case "a":
msg := ChatMessage{}
_ = json.Unmarshal(raw, &msg)
ReceiveChatMessage(ws, &msg)
case "b":
ReceiveBMessage(ws)
default:
return
}
}
// println("Correctly deserialized JSON")
// spew.Dump(tmp)
// for _, msg := range msgs {
// println(msg.Type)
// }
}
func ReceiveNqMessage(msg *NqMessage) {
// println(msg.MaxHistLen)
}
func ReceiveBMessage(ws *websocket.Conn) {
// histr := "[{\"m\":\"hi\"},{\"m\":\"ch\",\"_id\":\"✧𝓓𝓔𝓥 𝓡𝓸𝓸𝓶✧\"}]"
histr := "[{\"m\":\"hi\",\"token\":\"" + token + "\"}]"
// println("Sending hi message: " + histr)
err := ws.WriteMessage(1, []byte(histr))
if err != nil {
log.Println(err)
}
SendTimeMessage(ws)
// sentHi = true
}
func ReceiveHiMessage(ws *websocket.Conn, msg *HiMessage) {
println("I am " + msg.User.Name)
chstr := "[{\"m\":\"ch\",\"_id\":\"✧𝓓𝓔𝓥 𝓡𝓸𝓸𝓶✧\"}]"
// println("Sending ch message: " + chstr)
err2 := ws.WriteMessage(1, []byte(chstr))
if err2 != nil {
log.Println(err2)
}
}
type CommandData struct {
ChatMessage
Args []string
Cmd string
}
type Command struct {
Id string
Callback func(ws *websocket.Conn, data *CommandData) string
}
var helpCommands []Command
var commands []Command = []Command{
{
Id: "help",
Callback: func (ws *websocket.Conn, data *CommandData) string {
output := "Commands: "
for _, cmd := range helpCommands {
output += cmd.Id + ", "
}
return strings.Trim(output[:len(output) - 2], " ")
},
},
{
Id: "about",
Callback: func (ws *websocket.Conn, data *CommandData) string {
return "written in go version go1.22.2 linux/amd64"
},
},
{
Id: "me",
Callback: func(ws *websocket.Conn, data *CommandData) string {
bal, err := GetBalance(data.Part.Uid)
if err != nil {
log.Println(err)
return "An error has occurred."
}
return "Your balance: " + strconv.FormatFloat(bal, 'f', -1, 64)
},
},
}
var botPrefix string = "g"
func ReceiveChatMessage(ws *websocket.Conn, msg *ChatMessage) {
log.Println(msg.Part.Uid[0:6] + " <" + msg.Part.Name + ">: " + msg.Message)
if strings.HasPrefix(msg.Message, botPrefix) {
args := strings.Split(msg.Message, " ")
cmd := args[0][1:]
var data CommandData = CommandData{
ChatMessage: *msg,
Args: args,
Cmd: cmd,
}
for _, command := range commands {
if data.Cmd == command.Id {
message := command.Callback(ws, &data)
if message != "" {
SendChat(ws, message)
}
break
}
}
// switch data.Cmd {
// case "help":
// SendChat(ws, "golang test");
// }
}
}
func SendTimeMessage(ws *websocket.Conn) {
unixtime := fmt.Sprintf("%d", time.Now().Unix())
tstr := "[{\"m\": \"t\", \"t\": " + unixtime + "}]"
// println("Sending t message: " + tstr)
ws.WriteMessage(1, []byte(tstr))
}
func SendChat(ws *websocket.Conn, message string) {
ws.WriteMessage(1, []byte("[{\"m\":\"a\",\"message\":\"\u034f" + message + "\"}]"))
}