Friends rereimplemented + add mutex to stop concurrent writes to webscoket

This commit is contained in:
Eccentric 2024-01-31 00:16:57 +00:00
parent 9275e8fcd4
commit 1ebe963b2d
10 changed files with 142 additions and 65 deletions

View File

@ -44,3 +44,15 @@ func (s *GenericSyncMap[T]) Has(key string) bool {
_, ok := s.Get(key)
return ok
}
// change the key of a value in the map
func (s *GenericSyncMap[T]) ChangeKey(oldKey, newKey string) {
v, ok := s.Get(oldKey)
if !ok {
return
}
s.Set(newKey, v)
s.Delete(oldKey)
}

View File

@ -7,6 +7,7 @@ import (
"github.com/ectrc/snow/aid"
p "github.com/ectrc/snow/person"
"github.com/ectrc/snow/storage"
"github.com/google/uuid"
)
var (
@ -24,7 +25,35 @@ var (
)
func NewFortnitePerson(displayName string, everything bool) *p.Person {
person := p.NewPerson()
return NewFortnitePersonWithId(uuid.New().String(), displayName, everything)
}
func GiveEverything(person *p.Person) {
items := make([]storage.DB_Item, 0)
for _, item := range Cosmetics.Items {
if strings.Contains(strings.ToLower(item.ID), "random") {
continue
}
has := person.AthenaProfile.Items.GetItemByTemplateID(item.ID)
if has != nil {
continue
}
item := p.NewItem(item.Type.BackendValue + ":" + item.ID, 1)
item.HasSeen = true
person.AthenaProfile.Items.AddItem(item)
items = append(items, *item.ToDatabase(person.AthenaProfile.ID))
}
storage.Repo.BulkCreateItems(&items)
person.Save()
}
func NewFortnitePersonWithId(id string, displayName string, everything bool) *p.Person {
person := p.NewPersonWithCustomID(id)
person.DisplayName = displayName
for _, item := range defaultAthenaItems {
@ -123,27 +152,3 @@ func NewFortnitePerson(displayName string, everything bool) *p.Person {
return person
}
func GiveEverything(person *p.Person) {
items := make([]storage.DB_Item, 0)
for _, item := range Cosmetics.Items {
if strings.Contains(strings.ToLower(item.ID), "random") {
continue
}
has := person.AthenaProfile.Items.GetItemByTemplateID(item.ID)
if has != nil {
continue
}
item := p.NewItem(item.Type.BackendValue + ":" + item.ID, 1)
item.HasSeen = true
person.AthenaProfile.Items.AddItem(item)
items = append(items, *item.ToDatabase(person.AthenaProfile.ID))
}
storage.Repo.BulkCreateItems(&items)
person.Save()
}

View File

@ -10,7 +10,7 @@ import (
var (
Rarities = map[string]map[string]int{
"EFortRarity::Legendary": map[string]int{
"EFortRarity::Legendary": {
"AthenaCharacter": 2000,
"AthenaBackpack": 1500,
"AthenaPickaxe": 1500,
@ -18,7 +18,7 @@ var (
"AthenaDance": 500,
"AthenaItemWrap": 800,
},
"EFortRarity::Epic": map[string]int{
"EFortRarity::Epic": {
"AthenaCharacter": 1500,
"AthenaBackpack": 1200,
"AthenaPickaxe": 1200,
@ -26,7 +26,7 @@ var (
"AthenaDance": 800,
"AthenaItemWrap": 800,
},
"EFortRarity::Rare": map[string]int{
"EFortRarity::Rare": {
"AthenaCharacter": 1200,
"AthenaBackpack": 800,
"AthenaPickaxe": 800,
@ -34,7 +34,7 @@ var (
"AthenaDance": 500,
"AthenaItemWrap": 600,
},
"EFortRarity::Uncommon": map[string]int{
"EFortRarity::Uncommon": {
"AthenaCharacter": 800,
"AthenaBackpack": 200,
"AthenaPickaxe": 500,
@ -42,7 +42,7 @@ var (
"AthenaDance": 200,
"AthenaItemWrap": 300,
},
"EFortRarity::Common": map[string]int{
"EFortRarity::Common": {
"AthenaCharacter": 500,
"AthenaBackpack": 200,
"AthenaPickaxe": 500,

View File

@ -34,22 +34,24 @@ func PostCreateFriend(c *fiber.Ctx) error {
return c.Status(400).JSON(aid.ErrorBadRequest(err.Error()))
}
from, found := socket.GetJabberSocketByPersonID(relationship.From.ID)
from, found := socket.JabberSockets.Get(relationship.From.ID)
if found {
from.JabberSendMessageToPerson(aid.JSON{
"type": "com.epicgames.friends.core.apiobjects.Friend",
"timestamp": time.Now().Format(time.RFC3339),
"payload": relationship.GenerateFortniteFriendEntry(p.GenerateTypeFromPerson),
})
from.JabberNotifyFriends()
}
towards, found := socket.GetJabberSocketByPersonID(relationship.Towards.ID)
towards, found := socket.JabberSockets.Get(relationship.Towards.ID)
if found {
towards.JabberSendMessageToPerson(aid.JSON{
"type": "com.epicgames.friends.core.apiobjects.Friend",
"timestamp": time.Now().Format(time.RFC3339),
"payload": relationship.GenerateFortniteFriendEntry(p.GenerateTypeTowardsPerson),
})
towards.JabberNotifyFriends()
}
return c.SendStatus(204)

View File

@ -44,9 +44,9 @@ func WebsocketConnection(c *websocket.Conn) {
}
func GetConnectedSockets(c *fiber.Ctx) error {
jabber := []socket.Socket[socket.JabberData]{}
jabber := map[string]socket.Socket[socket.JabberData]{}
socket.JabberSockets.Range(func(key string, value *socket.Socket[socket.JabberData]) bool {
jabber = append(jabber, *value)
jabber[key] = *value
return true
})

View File

@ -46,9 +46,13 @@ func init() {
fortnite.GeneratePlaylistImages()
if found := person.FindByDisplay("god"); found == nil {
god := fortnite.NewFortnitePerson("god", true)
god := fortnite.NewFortnitePersonWithId("god", "god", true)
god.AddPermission("all")
angel := fortnite.NewFortnitePersonWithId("angel", "angel", true)
angel.AddPermission("all")
}
}
func main() {
r := fiber.New(fiber.Config{
@ -57,6 +61,7 @@ func main() {
JSONDecoder: json.Unmarshal,
})
r.Use(aid.FiberLogger())
r.Use(aid.FiberLimiter())
r.Use(aid.FiberCors())

View File

@ -84,7 +84,7 @@ func FindShallow(personId string) *Person {
return nil
}
return findHelper(person, true, true)
return findHelper(person, true, false)
}
func FindByDisplay(displayName string) *Person {
@ -120,7 +120,7 @@ func FindByDisplayShallow(displayName string) *Person {
return nil
}
return findHelper(person, true, true)
return findHelper(person, true, false)
}
func FindByDiscord(discordId string) *Person {

View File

@ -39,13 +39,15 @@ func (r *Relationship) GenerateFortniteFriendEntry(t RelationshipGenerateType) a
switch t {
case GenerateTypeFromPerson:
result["direction"] = "OUTBOUND"
result["direction"] = RelationshipOutboundDirection
result["accountId"] = r.Towards.ID
case GenerateTypeTowardsPerson:
result["direction"] = "INBOUND"
result["direction"] = RelationshipInboundDirection
result["accountId"] = r.From.ID
}
aid.PrintJSON(result)
return result
}
@ -65,7 +67,7 @@ func (p *Person) LoadRelationships() {
incoming := storage.Repo.Storage.GetIncomingRelationships(p.ID)
for _, entry := range incoming {
relationship := &Relationship{
From: Find(entry.FromPersonID),
From: FindShallow(entry.FromPersonID),
Towards: p,
Status: entry.Status,
Direction: RelationshipInboundDirection,
@ -73,6 +75,18 @@ func (p *Person) LoadRelationships() {
p.Relationships.Set(entry.FromPersonID, relationship)
}
outgoing := storage.Repo.Storage.GetOutgoingRelationships(p.ID)
for _, entry := range outgoing {
relationship := &Relationship{
From: p,
Towards: FindShallow(entry.TowardsPersonID),
Status: entry.Status,
Direction: RelationshipOutboundDirection,
}
p.Relationships.Set(entry.FromPersonID, relationship)
}
}
func (p *Person) CreateRelationship(personId string) (*Relationship, error) {
@ -95,7 +109,7 @@ func (p *Person) CreateRelationship(personId string) (*Relationship, error) {
func (p *Person) createOutboundRelationship(towards string) (*Relationship, error) {
relationship := &Relationship{
From: p,
Towards: Find(towards),
Towards: FindShallow(towards),
Status: "PENDING",
Direction: RelationshipOutboundDirection,
}
@ -104,7 +118,7 @@ func (p *Person) createOutboundRelationship(towards string) (*Relationship, erro
func (p *Person) createAcceptInboundRelationship(towards string) (*Relationship, error) {
relationship := &Relationship{
From: Find(towards),
From: FindShallow(towards),
Towards: p,
Status: "ACCEPTED",
Direction: RelationshipInboundDirection,

View File

@ -12,11 +12,14 @@ import (
type JabberData struct {
JabberID string
LastPresence string
}
var jabberHandlers = map[string]func(*Socket[JabberData], *etree.Document) error {
"open": jabberOpenHandler,
"iq": jabberIqRootHandler,
"presence": jabberPresenceHandler,
"message": jabberMessageHandler,
}
func HandleNewJabberSocket(identifier string) {
@ -24,7 +27,7 @@ func HandleNewJabberSocket(identifier string) {
if !ok {
return
}
defer JabberSockets.Delete(identifier)
defer JabberSockets.Delete(socket.ID)
for {
_, message, failed := socket.Connection.ReadMessage()
@ -49,8 +52,8 @@ func HandleNewJabberSocket(identifier string) {
}
func jabberOpenHandler(socket *Socket[JabberData], parsed *etree.Document) error {
socket.Connection.WriteMessage(websocket.TextMessage, []byte(`<open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="prod.ol.epicgames.com" version="1.0" id="`+ socket.ID +`" />`))
socket.Connection.WriteMessage(websocket.TextMessage, []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 +`" />`))
socket.Write([]byte(`<stream:features xmlns:stream="http://etherx.jabber.org/streams" />`))
return nil
}
@ -81,32 +84,30 @@ func jabberIqSetHandler(socket *Socket[JabberData], parsed *etree.Document) erro
return fmt.Errorf("person not found")
}
socket.Data.JabberID = snowId + "@prod.ol.epicgames.com/" + parsed.FindElement("/iq/query/resource").Text()
JabberSockets.ChangeKey(socket.ID, person.ID)
socket.ID = person.ID
socket.Person = person
socket.Data.JabberID = snowId + "@prod.ol.epicgames.com/" + parsed.FindElement("/iq/query/resource").Text()
socket.Connection.WriteMessage(websocket.TextMessage, []byte(`<iq xmlns="jabber:client" type="result" id="_xmpp_auth1" from="prod.ol.epicgames.com" to="`+ socket.Data.JabberID +`" />`))
socket.Write([]byte(`<iq xmlns="jabber:client" type="result" id="_xmpp_auth1" from="prod.ol.epicgames.com" to="`+ socket.Data.JabberID +`" />`))
return nil
}
func jabberIqGetHandler(socket *Socket[JabberData], parsed *etree.Document) error {
socket.Connection.WriteMessage(websocket.TextMessage, []byte(`<iq xmlns="jabber:client" type="result" id="`+ parsed.Root().SelectAttr("id").Value +`" from="prod.ol.epicgames.com" to="`+ socket.Data.JabberID +`" />`))
socket.Write([]byte(`<iq xmlns="jabber:client" type="result" id="`+ parsed.Root().SelectAttr("id").Value +`" from="prod.ol.epicgames.com" to="`+ socket.Data.JabberID +`" />`))
socket.JabberNotifyFriends()
return nil
}
func GetJabberSocketByPersonID(id string) (*Socket[JabberData], bool) {
var found *Socket[JabberData]
JabberSockets.Range(func(key string, socket *Socket[JabberData]) bool {
if socket.Person.ID == id {
found = socket
return false
func jabberPresenceHandler(socket *Socket[JabberData], parsed *etree.Document) error {
socket.Data.LastPresence = parsed.FindElement("/presence/status").Text()
socket.JabberNotifyFriends()
return nil
}
return true
})
func jabberMessageHandler(socket *Socket[JabberData], parsed *etree.Document) error {
return found, found != nil
return nil
}
func (s *Socket[T]) JabberSendMessageToPerson(data aid.JSON) {
@ -120,11 +121,39 @@ func (s *Socket[T]) JabberSendMessageToPerson(data aid.JSON) {
return
}
aid.Print(`<message xmlns="jabber:client" from="xmpp-admin@prod.ol.epicgames.com" to="`+ jabberSocket.Data.JabberID +`">
<body>`+ string(data.ToBytes()) +`</body>
</message>`)
s.Connection.WriteMessage(1, []byte(`<message xmlns="jabber:client" from="xmpp-admin@prod.ol.epicgames.com" to="`+ jabberSocket.Data.JabberID +`">
s.Write([]byte(`<message xmlns="jabber:client" from="xmpp-admin@prod.ol.epicgames.com" to="`+ jabberSocket.Data.JabberID +`">
<body>`+ string(data.ToBytes()) +`</body>
</message>`))
}
func (s *Socket[T]) JabberNotifyFriends() {
if reflect.TypeOf(s.Data) != reflect.TypeOf(&JabberData{}) {
return
}
jabberSocket, ok := JabberSockets.Get(s.ID)
if !ok {
aid.Print("jabber socket not found even though it should be")
return
}
s.Person.Relationships.Range(func(key string, value *person.Relationship) bool {
friendSocket, found := JabberSockets.Get(value.From.ID)
if value.Direction == person.RelationshipOutboundDirection {
friendSocket, found = JabberSockets.Get(value.Towards.ID)
}
if !found {
return true
}
friendSocket.Write([]byte(`<presence xmlns="jabber:client" type="available" from="`+ jabberSocket.Data.JabberID +`" to="`+ friendSocket.Data.JabberID +`">
<status>`+ jabberSocket.Data.LastPresence +`</status>
</presence>`))
jabberSocket.Write([]byte(`<presence xmlns="jabber:client" type="available" from="`+ friendSocket.Data.JabberID +`" to="`+ jabberSocket.Data.JabberID +`">
<status>`+ friendSocket.Data.LastPresence +`</status>
</presence>`))
return true
})
}

View File

@ -1,6 +1,8 @@
package socket
import (
"sync"
"github.com/ectrc/snow/aid"
"github.com/ectrc/snow/person"
"github.com/gofiber/contrib/websocket"
@ -17,6 +19,14 @@ type Socket[T JabberData | MatchmakerData] struct {
Connection *websocket.Conn
Data *T
Person *person.Person
mutex sync.Mutex
}
func (s *Socket[T]) Write(payload []byte) {
s.mutex.Lock()
defer s.mutex.Unlock()
s.Connection.WriteMessage(websocket.TextMessage, payload)
}
func newSocket[T JabberData | MatchmakerData](conn *websocket.Conn, data ...T) *Socket[T] {