Friends rereimplemented + add mutex to stop concurrent writes to webscoket
This commit is contained in:
parent
9275e8fcd4
commit
1ebe963b2d
|
@ -43,4 +43,16 @@ func (s *GenericSyncMap[T]) Range(f func(key string, value *T) bool) {
|
|||
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)
|
||||
}
|
|
@ -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 {
|
||||
|
@ -122,28 +151,4 @@ func NewFortnitePerson(displayName string, everything bool) *p.Person {
|
|||
person.Save()
|
||||
|
||||
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()
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
})
|
||||
|
||||
|
|
7
main.go
7
main.go
|
@ -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())
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]
|
||||
func jabberPresenceHandler(socket *Socket[JabberData], parsed *etree.Document) error {
|
||||
socket.Data.LastPresence = parsed.FindElement("/presence/status").Text()
|
||||
socket.JabberNotifyFriends()
|
||||
return nil
|
||||
}
|
||||
|
||||
JabberSockets.Range(func(key string, socket *Socket[JabberData]) bool {
|
||||
if socket.Person.ID == id {
|
||||
found = socket
|
||||
return false
|
||||
}
|
||||
func jabberMessageHandler(socket *Socket[JabberData], parsed *etree.Document) error {
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
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
|
||||
})
|
||||
}
|
|
@ -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] {
|
||||
|
|
Loading…
Reference in New Issue
Block a user