Start on tcp xmpp for seasons 2 <=

This commit is contained in:
Eccentric 2024-02-16 01:14:14 +00:00
parent a179961138
commit 36fc5f9f5d
8 changed files with 241 additions and 34 deletions

1
go.mod
View File

@ -15,7 +15,6 @@ require (
github.com/golang-jwt/jwt/v5 v5.2.0
github.com/google/uuid v1.5.0
github.com/lib/pq v1.10.9
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/r3labs/diff/v3 v3.0.1
gopkg.in/ini.v1 v1.67.0
gorm.io/driver/postgres v1.5.3

View File

@ -5,7 +5,6 @@ import (
"github.com/ectrc/snow/socket"
"github.com/gofiber/contrib/websocket"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
)
func MiddlewareWebsocket(c *fiber.Ctx) error {
@ -22,7 +21,7 @@ func MiddlewareWebsocket(c *fiber.Ctx) error {
protocol = "matchmaking"
}
c.Locals("identifier", uuid.New().String())
c.Locals("identifier", "ws-"+aid.RandomString(8))
c.Locals("protocol", protocol)
return c.Next()

112
handlers/tcp.go Normal file
View File

@ -0,0 +1,112 @@
package handlers
import (
"fmt"
"net"
"strconv"
"github.com/ectrc/snow/aid"
"github.com/ectrc/snow/socket"
)
type tcpClient struct {
c *net.Conn
buffer []byte
jabber *socket.Socket[socket.JabberData]
}
func (t *tcpClient) WriteMessage(messageType int, data []byte) error {
_, err := (*t.c).Write(data)
if err != nil {
return err
}
return nil
}
func (t *tcpClient) ReadMessage() (messageType int, p []byte, err error) {
n, err := (*t.c).Read(t.buffer)
if err != nil {
return 0, nil, err
}
return 1, t.buffer[:n], nil
}
func (t *tcpClient) loop() {
defer t.close()
for {
_, p, err := t.ReadMessage()
if err != nil {
return
}
aid.Print("(tcp) received: " + string(p))
socket.JabberSocketOnMessage(t.jabber, p)
}
}
func (t *tcpClient) close() error {
socket.JabberSockets.Delete(t.jabber.ID)
(*t.c).Close()
return nil
}
type tcpServer struct {
ln net.Listener
port string
nope chan string
}
func NewServer() (*tcpServer) {
portNumber, err := strconv.Atoi(aid.Config.API.Port[1:])
if err != nil {
return nil
}
portNumber++
ln, err := net.Listen("tcp", fmt.Sprintf(":%d", portNumber))
if err != nil {
return nil
}
return &tcpServer{
ln: ln,
port: fmt.Sprintf(":%d", portNumber),
}
}
func (t *tcpServer) Listen() error {
defer t.ln.Close()
aid.Print("(tcp) listening on " + aid.Config.API.Host + t.port)
go t.accept()
<-t.nope
return nil
}
func (t *tcpServer) accept() {
for {
conn, err := t.ln.Accept()
if err != nil {
return
}
aid.Print("(tcp) new connection from " + conn.RemoteAddr().String())
go t.handle(conn)
}
}
func (t *tcpServer) handle(conn net.Conn) {
tcpClient := &tcpClient{
c: &conn,
buffer: make([]byte, 1024),
}
tcpClient.jabber = socket.NewJabberSocket(tcpClient, "tcp-"+aid.RandomString(8), socket.JabberData{})
socket.JabberSockets.Set(tcpClient.jabber.ID, tcpClient.jabber)
tcpClient.loop()
}

View File

@ -192,11 +192,16 @@ func main() {
aid.Print("(fiber) listening on " + aid.Config.API.Host + ":" + ld.Port)
return nil
})
r.All("*", func(c *fiber.Ctx) error { return c.Status(fiber.StatusNotFound).JSON(aid.ErrorNotFound) })
if aid.Config.Fortnite.Season <= 2 {
t := handlers.NewServer()
go t.Listen()
}
err := r.Listen("0.0.0.0" + aid.Config.API.Port)
if err != nil {
panic(fmt.Sprintf("(fiber) ailed to listen: %v", err))
panic(fmt.Sprintf("(fiber) failed to listen: %v", err))
}
}

View File

@ -22,6 +22,19 @@ And once battle royale is completed ...
- **Save The World**
## Feature List
- **XMPP** From builds 3.6 onwards, season 1 and 2 are planned.
- **Friends** On every builds with the ability to add and remove friends.
- **Party System V2** This replaces the legacy xmpp driven party system.
- **Gifting** Of any item shop entry to any friend.
- **Locker Loadouts** On seasons 12 onwards, this allows for the saving and loading of multiple locker presets.
- **Item Refunding** Of previous shop purchases, will use a refund ticket if refunded in time.
- **Universal Item Shop** Works on all builds and will be updated every 24 hours.
- **Client Settings Storage** Uses amazon buckets to store client settings.
- **Support A Creator 5%** Use any display name and each purchase will give them 5% of the vbucks spent.
- **Discord Bot** Very useful to control players, their inventory and their settings
## Supported MCP Actions
`QueryProfile`, `ClientQuestLogin`, `MarkItemSeen`, `SetItemFavoriteStatusBatch`, `EquipBattleRoyaleCustomization`, `SetBattleRoyaleBanner`, `SetCosmeticLockerSlot`, `SetCosmeticLockerBanner`, `SetCosmeticLockerName`, `CopyCosmeticLoadout`, `DeleteCosmeticLoadout`, `PurchaseCatalogEntry`, `GiftCatalogEntry`, `RemoveGiftBox`, `RefundMtxPurchase`, `SetAffiliateName`, `SetReceiveGiftsEnabled`

View File

@ -3,6 +3,7 @@ package socket
import (
"fmt"
"reflect"
"strings"
"github.com/beevik/etree"
"github.com/ectrc/snow/aid"
@ -17,6 +18,7 @@ type JabberData struct {
}
var jabberHandlers = map[string]func(*Socket[JabberData], *etree.Document) error {
"stream": jabberStreamHandler,
"open": jabberOpenHandler,
"iq": jabberIqRootHandler,
"presence": jabberPresenceRootHandler,
@ -24,8 +26,11 @@ var jabberHandlers = map[string]func(*Socket[JabberData], *etree.Document) error
}
func HandleNewJabberSocket(identifier string) {
aid.Print("new jabber handle: " + identifier)
socket, ok := JabberSockets.Get(identifier)
if !ok {
aid.Print("socket not found", identifier)
return
}
defer JabberSockets.Delete(socket.ID)
@ -33,11 +38,23 @@ func HandleNewJabberSocket(identifier string) {
for {
_, message, failed := socket.Connection.ReadMessage()
if failed != nil {
aid.Print("jabber message failed", failed)
break
}
JabberSocketOnMessage(socket, message)
}
}
func JabberSocketOnMessage(socket *Socket[JabberData], message []byte) {
if strings.Contains(string(message), `">`) {
message = []byte(strings.ReplaceAll(string(message), `">`, `"/>`))
}
aid.Print("jabber message", string(message))
parsed := etree.NewDocument()
if err := parsed.ReadFromBytes(message); err != nil {
if err := parsed.ReadFromString(string(message)); err != nil {
aid.Print("jabber message failed to parse", err)
return
}
@ -46,14 +63,22 @@ func HandleNewJabberSocket(identifier string) {
socket.Connection.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, err.Error()))
return
}
return
}
}
aid.Print("jabber message not handled", parsed.Root().Tag)
}
func jabberStreamHandler(socket *Socket[JabberData], parsed *etree.Document) error {
socket.Write([]byte(`<stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" to="prod.ol.epicgames.com" id="`+ socket.ID +`" version="1.0" xml:lang="en">`))
socket.Write([]byte(`<stream:features xmlns:stream="http://etherx.jabber.org/streams" />`))
socket.Write([]byte(`<open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="prod.ol.epicgames.com" version="1.0" id="`+ socket.ID +`" />`))
return nil
}
func jabberOpenHandler(socket *Socket[JabberData], parsed *etree.Document) error {
socket.Write([]byte(`<open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="prod.ol.epicgames.com" version="1.0" id="`+ socket.ID +`" />`))
socket.Write([]byte(`<stream:features xmlns:stream="http://etherx.jabber.org/streams" />`))
return nil
}

View File

@ -14,9 +14,14 @@ type MatchmakerData struct {
Region string
}
type WebSocket interface {
WriteMessage(messageType int, data []byte) error
ReadMessage() (messageType int, p []byte, err error)
}
type Socket[T JabberData | MatchmakerData] struct {
ID string
Connection *websocket.Conn
Connection WebSocket
Data *T
Person *person.Person
M sync.Mutex
@ -29,7 +34,7 @@ func (s *Socket[T]) Write(payload []byte) {
s.Connection.WriteMessage(websocket.TextMessage, payload)
}
func newSocket[T JabberData | MatchmakerData](conn *websocket.Conn, data ...T) *Socket[T] {
func newSocket[T JabberData | MatchmakerData](conn WebSocket, data ...T) *Socket[T] {
additional := data[0]
return &Socket[T]{
@ -39,7 +44,7 @@ func newSocket[T JabberData | MatchmakerData](conn *websocket.Conn, data ...T) *
}
}
func NewJabberSocket(conn *websocket.Conn, id string, data JabberData) *Socket[JabberData] {
func NewJabberSocket(conn WebSocket, id string, data JabberData) *Socket[JabberData] {
socket := newSocket[JabberData](conn, data)
socket.ID = id
return socket

View File

@ -1,29 +1,49 @@
package storage
import (
"fmt"
"strconv"
"github.com/ectrc/snow/aid"
)
func GetDefaultEngine() []byte {
/*[OnlineSubsystemMcp]
bUsePartySystemV2=true
[OnlineSubsystemMcp.OnlinePartySystemMcpAdapter]
bUsePartySystemV2=true*/
return []byte(`
[OnlineSubsystemMcp.Xmpp]
bUseSSL=false
Protocol=ws
ServerAddr="ws://`+ aid.Config.API.Host + aid.Config.API.Port +`/?"
[OnlineSubsystemMcp.Xmpp Prod]
bUseSSL=false
Protocol=ws
ServerAddr="ws://`+ aid.Config.API.Host + aid.Config.API.Port +`/?"
portNumber, err := strconv.Atoi(aid.Config.API.Port[1:])
if err != nil {
return nil
}
portNumber++
realPort := fmt.Sprintf("%d", portNumber)
str := `
[XMPP]
bEnableWebsockets=true
[OnlineSubsystem]
bHasVoiceEnabled=true
[Core.Log]
LogHttp=VeryVerbose
LogXmpp=VeryVerbose
LogBeacon=VeryVerbose
LogQos=VeryVerbose
LogOnline=VeryVerbose
LogOnlineGame=VeryVerbose
LogOnlineParty=VeryVerbose
LogParty=VeryVerbose
LogOnlineChat=VeryVerbose
LogGarbage=VeryVerbose
LogTemp=VeryVerbose
LogSourceControl=VeryVerbose
LogLootTables=VeryVerbose
LogMatchmakingServiceClient=VeryVerbose
LogMatchmakingServiceDedicatedServer=VeryVerbose
LogUAC=VeryVerbose
LogBattlEye=VeryVerbose
LogEasyAntiCheatServer=VeryVerbose
LogEasyAntiCheatClient=VeryVerbose
LogEasyAntiCheatNetComponent=VeryVerbose
[ConsoleVariables]
n.VerifyPeer=0
FortMatchmakingV2.ContentBeaconFailureCancelsMatchmaking=0
@ -32,7 +52,36 @@ FortMatchmakingV2.EnableContentBeacon=0
[/Script/Qos.QosRegionManager]
NumTestsPerRegion=5
PingTimeout=3.0`)
PingTimeout=3.0`
if aid.Config.Fortnite.Season <= 2 {
str += `
[OnlineSubsystemMcp.Xmpp]
bUseSSL=false
Protocol=tcp
ServerAddr="`+ aid.Config.API.Host + `"
ServerPort=`+ realPort + `
[OnlineSubsystemMcp.Xmpp Prod]
bUseSSL=false
Protocol=tcp
ServerAddr="`+ aid.Config.API.Host + `"
ServerPort=`+ realPort
} else {
str += `
[OnlineSubsystemMcp.Xmpp]
bUseSSL=false
Protocol=ws
ServerAddr="ws://`+ aid.Config.API.Host + aid.Config.API.Port +`/?"
[OnlineSubsystemMcp.Xmpp Prod]
bUseSSL=false
Protocol=ws
ServerAddr="ws://`+ aid.Config.API.Host + aid.Config.API.Port +`/?"`
}
return []byte(str)
}
func GetDefaultGame() []byte {