Finished basic XMPP functions!
This commit is contained in:
parent
d9e4aa0b2d
commit
586dcc22f9
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module github.com/ectrc/snow
|
||||||
go 1.21.3
|
go 1.21.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/beevik/etree v1.3.0
|
||||||
github.com/bwmarrin/discordgo v0.27.1
|
github.com/bwmarrin/discordgo v0.27.1
|
||||||
github.com/goccy/go-json v0.10.2
|
github.com/goccy/go-json v0.10.2
|
||||||
github.com/gofiber/contrib/websocket v1.3.0
|
github.com/gofiber/contrib/websocket v1.3.0
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -1,5 +1,7 @@
|
||||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
|
github.com/beevik/etree v1.3.0 h1:hQTc+pylzIKDb23yYprodCWWTt+ojFfUZyzU09a/hmU=
|
||||||
|
github.com/beevik/etree v1.3.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc=
|
||||||
github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY=
|
github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY=
|
||||||
github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/beevik/etree"
|
||||||
"github.com/ectrc/snow/aid"
|
"github.com/ectrc/snow/aid"
|
||||||
"github.com/ectrc/snow/person"
|
"github.com/ectrc/snow/person"
|
||||||
"github.com/gofiber/contrib/websocket"
|
"github.com/gofiber/contrib/websocket"
|
||||||
|
@ -16,13 +17,39 @@ var (
|
||||||
|
|
||||||
type Socket struct {
|
type Socket struct {
|
||||||
ID string
|
ID string
|
||||||
|
JID string
|
||||||
Type SocketType
|
Type SocketType
|
||||||
Connection *websocket.Conn
|
Connection *websocket.Conn
|
||||||
Person *person.Person
|
Person *person.Person
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MessageToWrite struct {
|
||||||
|
Socket *Socket
|
||||||
|
Message []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socket) Write(message []byte) {
|
||||||
|
socketWriteQueue <- MessageToWrite{
|
||||||
|
Socket: s,
|
||||||
|
Message: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socket) WriteTree(message *etree.Document) {
|
||||||
|
bytes, err := message.WriteToBytes()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
socketWriteQueue <- MessageToWrite{
|
||||||
|
Socket: s,
|
||||||
|
Message: bytes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
handles = map[SocketType]func(string) {
|
socketWriteQueue = make(chan MessageToWrite, 1000)
|
||||||
|
socketHandlers = map[SocketType]func(string) {
|
||||||
SocketTypeXmpp: handlePresenceSocket,
|
SocketTypeXmpp: handlePresenceSocket,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,19 +83,35 @@ func WebsocketConnection(c *websocket.Conn) {
|
||||||
Type: protocol,
|
Type: protocol,
|
||||||
Connection: c,
|
Connection: c,
|
||||||
})
|
})
|
||||||
defer close(uuid)
|
defer func() {
|
||||||
|
socket, ok := sockets.Get(uuid)
|
||||||
if handle, ok := handles[protocol]; ok {
|
|
||||||
handle(uuid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func close(id string) {
|
|
||||||
socket, ok := sockets.Get(id)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
socket.Connection.Close()
|
socket.Connection.Close()
|
||||||
sockets.Delete(id)
|
sockets.Delete(uuid)
|
||||||
aid.Print("(xmpp) connection closed", id)
|
aid.Print("(xmpp) connection closed", uuid)
|
||||||
|
}()
|
||||||
|
|
||||||
|
if handle, ok := socketHandlers[protocol]; ok {
|
||||||
|
handle(uuid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
if aid.Config != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aid.Print("(socket) write queue started")
|
||||||
|
|
||||||
|
for {
|
||||||
|
message := <-socketWriteQueue
|
||||||
|
aid.Print("(socket) message sent", message.Socket.ID, string(message.Message))
|
||||||
|
message.Socket.Connection.WriteMessage(websocket.TextMessage, message.Message)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
151
handlers/xmpp.go
151
handlers/xmpp.go
|
@ -1,6 +1,22 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import "github.com/ectrc/snow/aid"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/beevik/etree"
|
||||||
|
"github.com/ectrc/snow/aid"
|
||||||
|
p "github.com/ectrc/snow/person"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
socketXmppMessageHandlers = map[string]func(*Socket, *etree.Document) error {
|
||||||
|
"open": presenceSocketOpenEvent,
|
||||||
|
"iq": presenceSocketIqRootEvent,
|
||||||
|
"close": presenceSocketCloseEvent,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func handlePresenceSocket(id string) {
|
func handlePresenceSocket(id string) {
|
||||||
aid.Print("(xmpp) connection opened", id)
|
aid.Print("(xmpp) connection opened", id)
|
||||||
|
@ -10,11 +26,138 @@ func handlePresenceSocket(id string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
_, msg, err := socket.Connection.ReadMessage()
|
_, message, err := socket.Connection.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
aid.Print("(xmpp) error reading message", err)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
aid.Print("(xmpp) message received", string(msg))
|
|
||||||
|
parsed := etree.NewDocument()
|
||||||
|
if err := parsed.ReadFromBytes(message); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
aid.Print("(xmpp) message received", string(message))
|
||||||
|
|
||||||
|
if handler, ok := socketXmppMessageHandlers[parsed.Root().Tag]; ok {
|
||||||
|
if err := handler(socket, parsed); err != nil {
|
||||||
|
aid.Print("(xmpp) connection closed", id, err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func presenceSocketOpenEvent(socket *Socket, tree *etree.Document) error {
|
||||||
|
document := etree.NewDocument()
|
||||||
|
open := document.CreateElement("open")
|
||||||
|
open.Attr = append(open.Attr, etree.Attr{Key: "xmlns", Value: "urn:ietf:params:xml:ns:xmpp-framing"})
|
||||||
|
open.Attr = append(open.Attr, etree.Attr{Key: "from", Value: "prod.ol.epicgames.com"})
|
||||||
|
open.Attr = append(open.Attr, etree.Attr{Key: "version", Value: "1.0"})
|
||||||
|
open.Attr = append(open.Attr, etree.Attr{Key: "id", Value: socket.ID})
|
||||||
|
|
||||||
|
socket.WriteTree(document)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func presenceSocketCloseEvent(socket *Socket, tree *etree.Document) error {
|
||||||
|
return fmt.Errorf("safe exit")
|
||||||
|
}
|
||||||
|
|
||||||
|
func presenceSocketIqRootEvent(socket *Socket, tree *etree.Document) error {
|
||||||
|
redirect := map[string]func(*Socket, *etree.Document) error{
|
||||||
|
"set": presenceSocketIqSetEvent,
|
||||||
|
"get": presenceSocketIqGetEvent,
|
||||||
|
}
|
||||||
|
|
||||||
|
if handler, ok := redirect[tree.Root().SelectAttr("type").Value]; ok {
|
||||||
|
if err := handler(socket, tree); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func presenceSocketIqSetEvent(socket *Socket, tree *etree.Document) error {
|
||||||
|
token := tree.Root().SelectElement("query").SelectElement("password")
|
||||||
|
if token == nil || token.Text() == "" {
|
||||||
|
return fmt.Errorf("invalid token")
|
||||||
|
}
|
||||||
|
real := strings.ReplaceAll(token.Text(), "eg1~", "")
|
||||||
|
|
||||||
|
claims, err := aid.JWTVerify(real)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid token")
|
||||||
|
}
|
||||||
|
|
||||||
|
if claims["snow_id"] == nil {
|
||||||
|
return fmt.Errorf("invalid token")
|
||||||
|
}
|
||||||
|
|
||||||
|
snowId, ok := claims["snow_id"].(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("invalid token")
|
||||||
|
}
|
||||||
|
|
||||||
|
person := p.Find(snowId)
|
||||||
|
if person == nil {
|
||||||
|
return fmt.Errorf("invalid token")
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.Person = person
|
||||||
|
socket.JID = person.ID + "@prod.ol.epicgames.com/" + tree.Root().SelectElement("query").SelectElement("resource").Text()
|
||||||
|
|
||||||
|
document := etree.NewDocument()
|
||||||
|
iq := document.CreateElement("iq")
|
||||||
|
iq.Attr = append(iq.Attr, etree.Attr{Key: "type", Value: "result"})
|
||||||
|
iq.Attr = append(iq.Attr, etree.Attr{Key: "id", Value: "_xmpp_auth1"})
|
||||||
|
iq.Attr = append(iq.Attr, etree.Attr{Key: "from", Value: "prod.ol.epicgames.com"})
|
||||||
|
|
||||||
|
socket.WriteTree(document)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func presenceSocketIqGetEvent(socket *Socket, tree *etree.Document) error {
|
||||||
|
document := etree.NewDocument()
|
||||||
|
iq := document.CreateElement("iq")
|
||||||
|
iq.Attr = append(iq.Attr, etree.Attr{Key: "type", Value: "result"})
|
||||||
|
iq.Attr = append(iq.Attr, etree.Attr{Key: "id", Value: tree.Root().SelectAttr("id").Value})
|
||||||
|
iq.Attr = append(iq.Attr, etree.Attr{Key: "to", Value: tree.Root().SelectAttr("from").Value})
|
||||||
|
iq.Attr = append(iq.Attr, etree.Attr{Key: "from", Value: "prod.ol.epicgames.com"})
|
||||||
|
ping := iq.CreateElement("ping")
|
||||||
|
ping.Attr = append(ping.Attr, etree.Attr{Key: "xmlns", Value: "urn:xmpp:ping"})
|
||||||
|
|
||||||
|
socket.WriteTree(document)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
if aid.Config != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timer := time.NewTicker(30 * time.Second)
|
||||||
|
for {
|
||||||
|
<-timer.C
|
||||||
|
sockets.Range(func(key string, socket *Socket) bool {
|
||||||
|
if socket.Type != SocketTypeXmpp || socket.Person == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
document := etree.NewDocument()
|
||||||
|
iq := document.CreateElement("iq")
|
||||||
|
iq.Attr = append(iq.Attr, etree.Attr{Key: "id", Value: "_xmpp_auth1"})
|
||||||
|
iq.Attr = append(iq.Attr, etree.Attr{Key: "type", Value: "get"})
|
||||||
|
iq.Attr = append(iq.Attr, etree.Attr{Key: "from", Value: "prod.ol.epicgames.com"})
|
||||||
|
ping := iq.CreateElement("ping")
|
||||||
|
ping.Attr = append(iq.Attr, etree.Attr{Key: "xmlns", Value: "urn:xmpp:ping"})
|
||||||
|
|
||||||
|
socket.WriteTree(document)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user