mirror of
https://github.com/PretendoNetwork/friends.git
synced 2026-03-21 18:04:11 -05:00
571 lines
20 KiB
Go
571 lines
20 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"math/rand"
|
|
"os"
|
|
"time"
|
|
|
|
nex "github.com/PretendoNetwork/nex-go"
|
|
nexproto "github.com/PretendoNetwork/nex-protocols-go"
|
|
"github.com/gocql/gocql"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
)
|
|
|
|
var cluster *gocql.ClusterConfig
|
|
var cassandraClusterSession *gocql.Session
|
|
|
|
var mongoClient *mongo.Client
|
|
var mongoContext context.Context
|
|
var mongoDatabase *mongo.Database
|
|
var mongoCollection *mongo.Collection
|
|
|
|
func connectMongo() {
|
|
mongoClient, _ = mongo.NewClient(options.Client().ApplyURI(os.Getenv("MONGO_URI")))
|
|
mongoContext, _ = context.WithTimeout(context.Background(), 10*time.Second)
|
|
_ = mongoClient.Connect(mongoContext)
|
|
|
|
mongoDatabase = mongoClient.Database("pretendo")
|
|
mongoCollection = mongoDatabase.Collection("pnids")
|
|
}
|
|
|
|
func connectCassandra() {
|
|
// Connect to Cassandra
|
|
|
|
var err error
|
|
|
|
cluster = gocql.NewCluster("127.0.0.1")
|
|
cluster.Timeout = 30 * time.Second
|
|
|
|
createKeyspace("pretendo_friends")
|
|
|
|
cluster.Keyspace = "pretendo_friends"
|
|
|
|
cassandraClusterSession, err = cluster.CreateSession()
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Create tables if missing
|
|
|
|
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.preferences (
|
|
pid int PRIMARY KEY,
|
|
show_online boolean,
|
|
show_current_game boolean,
|
|
block_friend_requests boolean
|
|
)`).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.blocks (
|
|
id text PRIMARY KEY,
|
|
blocker_pid int,
|
|
blocked_pid int,
|
|
date bigint
|
|
)`).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.friend_requests (
|
|
id bigint PRIMARY KEY,
|
|
sender_pid int,
|
|
recipient_pid int,
|
|
sent_on bigint,
|
|
expires_on bigint,
|
|
message text,
|
|
received boolean,
|
|
accepted boolean,
|
|
denied boolean
|
|
)`).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.friendships (
|
|
id bigint PRIMARY KEY,
|
|
user1_pid int,
|
|
user2_pid int,
|
|
date bigint
|
|
)`).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.comments (
|
|
pid int PRIMARY KEY,
|
|
message text,
|
|
changed bigint
|
|
)`).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.last_online (
|
|
pid int PRIMARY KEY,
|
|
time bigint
|
|
)`).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Println("Connected to Cassandra")
|
|
}
|
|
|
|
// Adapted from gocql common_test.go
|
|
func createKeyspace(keyspace string) {
|
|
flagRF := flag.Int("rf", 1, "replication factor for pretendo_friends keyspace")
|
|
|
|
c := *cluster
|
|
c.Keyspace = "system"
|
|
c.Timeout = 30 * time.Second
|
|
|
|
s, err := c.CreateSession()
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
defer s.Close()
|
|
|
|
if err := s.Query(fmt.Sprintf(`CREATE KEYSPACE IF NOT EXISTS %s
|
|
WITH replication = {
|
|
'class' : 'SimpleStrategy',
|
|
'replication_factor' : %d
|
|
}`, keyspace, *flagRF)).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
////////////////////////////////
|
|
// //
|
|
// Cassandra database methods //
|
|
// //
|
|
////////////////////////////////
|
|
|
|
func updateUserLastOnlineTime(pid uint32, lastOnline *nex.DateTime) {
|
|
if err := cassandraClusterSession.Query(`UPDATE pretendo_friends.last_online SET time=? WHERE pid=?`, lastOnline.Value(), pid).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// Get a users comment
|
|
func getUserComment(pid uint32) *nexproto.Comment {
|
|
comment := nexproto.NewComment()
|
|
comment.Unknown = 0
|
|
|
|
var changed uint64 = 0
|
|
|
|
if err := cassandraClusterSession.Query(`SELECT message, changed FROM pretendo_friends.comments WHERE pid=?`,
|
|
pid).Consistency(gocql.One).Scan(&comment.Contents, &changed); err != nil {
|
|
if err == gocql.ErrNotFound {
|
|
comment.Contents = ""
|
|
} else {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
comment.LastChanged = nex.NewDateTime(changed)
|
|
|
|
return comment
|
|
}
|
|
|
|
// Update a users comment
|
|
func updateUserComment(pid uint32, message string) uint64 {
|
|
changed := nex.NewDateTime(0).Now()
|
|
|
|
if err := cassandraClusterSession.Query(`UPDATE pretendo_friends.comments SET message=?, changed=? WHERE pid=?`, message, changed, pid).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
return changed
|
|
}
|
|
|
|
// Get a users friend list
|
|
func getUserFriendList(pid uint32) []*nexproto.FriendInfo {
|
|
var sliceMap []map[string]interface{}
|
|
var err error
|
|
|
|
if sliceMap, err = cassandraClusterSession.Query(`SELECT user2_pid, date FROM pretendo_friends.friendships WHERE user1_pid=? ALLOW FILTERING`, pid).Iter().SliceMap(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
friendList := make([]*nexproto.FriendInfo, 0)
|
|
|
|
for i := 0; i < len(sliceMap); i++ {
|
|
friendPID := uint32(sliceMap[i]["user2_pid"].(int))
|
|
|
|
friendInfo := nexproto.NewFriendInfo()
|
|
connectedUser := connectedUsers[friendPID]
|
|
var lastOnline *nex.DateTime
|
|
|
|
if connectedUser != nil {
|
|
// Online
|
|
friendInfo.NNAInfo = connectedUser.NNAInfo
|
|
friendInfo.Presence = connectedUser.Presence
|
|
|
|
if friendInfo.NNAInfo == nil || friendInfo.NNAInfo.PrincipalBasicInfo == nil {
|
|
// TODO: Fix this
|
|
fmt.Printf("\nPID %d has friend with bad presence data database.go line 211\n", pid)
|
|
if friendInfo.NNAInfo == nil {
|
|
fmt.Println("friendInfo.NNAInfo is nil")
|
|
} else {
|
|
fmt.Println("friendInfo.NNAInfo.PrincipalBasicInfo is nil")
|
|
}
|
|
fmt.Printf("Bad friend PID: %d\n\n", friendPID)
|
|
|
|
continue
|
|
}
|
|
|
|
lastOnline = nex.NewDateTime(0)
|
|
lastOnline.FromTimestamp(time.Now())
|
|
} else {
|
|
// Offline
|
|
friendUserInforation := getUserInfoByPID(friendPID)
|
|
encodedMiiData := friendUserInforation["mii"].(bson.M)["data"].(string)
|
|
decodedMiiData, _ := base64.StdEncoding.DecodeString(encodedMiiData)
|
|
|
|
friendInfo.NNAInfo = nexproto.NewNNAInfo()
|
|
friendInfo.NNAInfo.PrincipalBasicInfo = nexproto.NewPrincipalBasicInfo()
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.PID = friendPID
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.NNID = friendUserInforation["username"].(string)
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii = nexproto.NewMiiV2()
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Name = friendUserInforation["mii"].(bson.M)["name"].(string)
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Unknown1 = 0
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Unknown2 = 0
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Data = decodedMiiData
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Datetime = nex.NewDateTime(0)
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Unknown = 0
|
|
friendInfo.NNAInfo.Unknown1 = 0
|
|
friendInfo.NNAInfo.Unknown2 = 0
|
|
|
|
friendInfo.Presence = nexproto.NewNintendoPresenceV2()
|
|
friendInfo.Presence.ChangedFlags = 0
|
|
friendInfo.Presence.Online = false
|
|
friendInfo.Presence.GameKey = nexproto.NewGameKey()
|
|
friendInfo.Presence.GameKey.TitleID = 0
|
|
friendInfo.Presence.GameKey.TitleVersion = 0
|
|
friendInfo.Presence.Unknown1 = 0
|
|
friendInfo.Presence.Message = ""
|
|
friendInfo.Presence.Unknown2 = 0
|
|
friendInfo.Presence.Unknown3 = 0
|
|
friendInfo.Presence.GameServerID = 0
|
|
friendInfo.Presence.Unknown4 = 0
|
|
friendInfo.Presence.PID = 0
|
|
friendInfo.Presence.GatheringID = 0
|
|
friendInfo.Presence.ApplicationData = []byte{0x00}
|
|
friendInfo.Presence.Unknown5 = 0
|
|
friendInfo.Presence.Unknown6 = 0
|
|
friendInfo.Presence.Unknown7 = 0
|
|
|
|
var lastOnlineTime uint64
|
|
if err := cassandraClusterSession.Query(`SELECT time FROM pretendo_friends.last_online WHERE pid=?`, friendPID).Scan(&lastOnlineTime); err != nil {
|
|
if err == gocql.ErrNotFound {
|
|
lastOnlineTime = nex.NewDateTime(0).Now()
|
|
} else {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
lastOnline = nex.NewDateTime(lastOnlineTime) // TODO: Change this
|
|
}
|
|
|
|
friendInfo.Status = getUserComment(friendPID)
|
|
friendInfo.BecameFriend = nex.NewDateTime(uint64(sliceMap[i]["date"].(int64)))
|
|
friendInfo.LastOnline = lastOnline
|
|
friendInfo.Unknown = 0
|
|
|
|
friendList = append(friendList, friendInfo)
|
|
}
|
|
|
|
return friendList
|
|
}
|
|
|
|
// Get a users sent friend requests
|
|
func getUserFriendRequestsOut(pid uint32) []*nexproto.FriendRequest {
|
|
var sliceMap []map[string]interface{}
|
|
var err error
|
|
|
|
if sliceMap, err = cassandraClusterSession.Query(`SELECT id, recipient_pid, sent_on, expires_on, message, received FROM pretendo_friends.friend_requests WHERE sender_pid=? AND accepted=false AND denied=false ALLOW FILTERING`, pid).Iter().SliceMap(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
friendRequestsOut := make([]*nexproto.FriendRequest, 0)
|
|
|
|
for i := 0; i < len(sliceMap); i++ {
|
|
recipientPID := uint32(sliceMap[i]["recipient_pid"].(int))
|
|
|
|
recipientUserInforation := getUserInfoByPID(recipientPID)
|
|
encodedMiiData := recipientUserInforation["mii"].(bson.M)["data"].(string)
|
|
decodedMiiData, _ := base64.StdEncoding.DecodeString(encodedMiiData)
|
|
|
|
friendRequest := nexproto.NewFriendRequest()
|
|
|
|
friendRequest.PrincipalInfo = nexproto.NewPrincipalBasicInfo()
|
|
friendRequest.PrincipalInfo.PID = recipientPID
|
|
friendRequest.PrincipalInfo.NNID = recipientUserInforation["username"].(string)
|
|
friendRequest.PrincipalInfo.Mii = nexproto.NewMiiV2()
|
|
friendRequest.PrincipalInfo.Mii.Name = recipientUserInforation["mii"].(bson.M)["name"].(string)
|
|
friendRequest.PrincipalInfo.Mii.Unknown1 = 0 // replaying from real server
|
|
friendRequest.PrincipalInfo.Mii.Unknown2 = 0 // replaying from real server
|
|
friendRequest.PrincipalInfo.Mii.Data = decodedMiiData
|
|
friendRequest.PrincipalInfo.Mii.Datetime = nex.NewDateTime(0)
|
|
friendRequest.PrincipalInfo.Unknown = 2 // replaying from real server
|
|
|
|
friendRequest.Message = nexproto.NewFriendRequestMessage()
|
|
friendRequest.Message.FriendRequestID = uint64(sliceMap[i]["id"].(int64))
|
|
friendRequest.Message.Received = sliceMap[i]["received"].(bool)
|
|
friendRequest.Message.Unknown2 = 1
|
|
friendRequest.Message.Message = sliceMap[i]["message"].(string)
|
|
friendRequest.Message.Unknown3 = 0
|
|
friendRequest.Message.Unknown4 = ""
|
|
friendRequest.Message.GameKey = nexproto.NewGameKey()
|
|
friendRequest.Message.GameKey.TitleID = 0
|
|
friendRequest.Message.GameKey.TitleVersion = 0
|
|
friendRequest.Message.Unknown5 = nex.NewDateTime(134222053376) // idk what this value means but its always this
|
|
friendRequest.Message.ExpiresOn = nex.NewDateTime(uint64(sliceMap[i]["expires_on"].(int64)))
|
|
friendRequest.SentOn = nex.NewDateTime(uint64(sliceMap[i]["sent_on"].(int64)))
|
|
|
|
friendRequestsOut = append(friendRequestsOut, friendRequest)
|
|
}
|
|
|
|
return friendRequestsOut
|
|
}
|
|
|
|
// Get a users received friend requests
|
|
func getUserFriendRequestsIn(pid uint32) []*nexproto.FriendRequest {
|
|
var sliceMap []map[string]interface{}
|
|
var err error
|
|
|
|
if sliceMap, err = cassandraClusterSession.Query(`SELECT id, sender_pid, sent_on, expires_on, message, received FROM pretendo_friends.friend_requests WHERE recipient_pid=? AND accepted=false AND denied=false ALLOW FILTERING`, pid).Iter().SliceMap(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
friendRequestsOut := make([]*nexproto.FriendRequest, 0)
|
|
|
|
for i := 0; i < len(sliceMap); i++ {
|
|
senderPID := uint32(sliceMap[i]["sender_pid"].(int))
|
|
|
|
senderUserInforation := getUserInfoByPID(senderPID)
|
|
encodedMiiData := senderUserInforation["mii"].(bson.M)["data"].(string)
|
|
decodedMiiData, _ := base64.StdEncoding.DecodeString(encodedMiiData)
|
|
|
|
friendRequest := nexproto.NewFriendRequest()
|
|
|
|
friendRequest.PrincipalInfo = nexproto.NewPrincipalBasicInfo()
|
|
friendRequest.PrincipalInfo.PID = senderPID
|
|
friendRequest.PrincipalInfo.NNID = senderUserInforation["username"].(string)
|
|
friendRequest.PrincipalInfo.Mii = nexproto.NewMiiV2()
|
|
friendRequest.PrincipalInfo.Mii.Name = senderUserInforation["mii"].(bson.M)["name"].(string)
|
|
friendRequest.PrincipalInfo.Mii.Unknown1 = 0 // replaying from real server
|
|
friendRequest.PrincipalInfo.Mii.Unknown2 = 0 // replaying from real server
|
|
friendRequest.PrincipalInfo.Mii.Data = decodedMiiData
|
|
friendRequest.PrincipalInfo.Mii.Datetime = nex.NewDateTime(0)
|
|
friendRequest.PrincipalInfo.Unknown = 2 // replaying from real server
|
|
|
|
friendRequest.Message = nexproto.NewFriendRequestMessage()
|
|
friendRequest.Message.FriendRequestID = uint64(sliceMap[i]["id"].(int64))
|
|
friendRequest.Message.Received = sliceMap[i]["received"].(bool)
|
|
friendRequest.Message.Unknown2 = 1
|
|
friendRequest.Message.Message = sliceMap[i]["message"].(string)
|
|
friendRequest.Message.Unknown3 = 0
|
|
friendRequest.Message.Unknown4 = ""
|
|
friendRequest.Message.GameKey = nexproto.NewGameKey()
|
|
friendRequest.Message.GameKey.TitleID = 0
|
|
friendRequest.Message.GameKey.TitleVersion = 0
|
|
friendRequest.Message.Unknown5 = nex.NewDateTime(134222053376) // idk what this value means but its always this
|
|
friendRequest.Message.ExpiresOn = nex.NewDateTime(uint64(sliceMap[i]["expires_on"].(int64)))
|
|
friendRequest.SentOn = nex.NewDateTime(uint64(sliceMap[i]["sent_on"].(int64)))
|
|
|
|
friendRequestsOut = append(friendRequestsOut, friendRequest)
|
|
}
|
|
|
|
return friendRequestsOut
|
|
}
|
|
|
|
// Get a users blacklist
|
|
func getUserBlockList(pid uint32) []*nexproto.BlacklistedPrincipal {
|
|
return make([]*nexproto.BlacklistedPrincipal, 0)
|
|
}
|
|
|
|
// Get notifications for a user
|
|
func getUserNotifications(pid uint32) []*nexproto.PersistentNotification {
|
|
return make([]*nexproto.PersistentNotification, 0)
|
|
}
|
|
|
|
func updateUserPrincipalPreference(pid uint32, principalPreference *nexproto.PrincipalPreference) {
|
|
if err := cassandraClusterSession.Query(`UPDATE pretendo_friends.preferences SET
|
|
show_online=?,
|
|
show_current_game=?,
|
|
block_friend_requests=?
|
|
WHERE pid=?`, principalPreference.ShowOnlinePresence, principalPreference.ShowCurrentTitle, principalPreference.BlockFriendRequests, pid).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func getUserPrincipalPreference(pid uint32) *nexproto.PrincipalPreference {
|
|
preference := nexproto.NewPrincipalPreference()
|
|
|
|
_ = cassandraClusterSession.Query(`SELECT show_online, show_current_game, block_friend_requests FROM pretendo_friends.preferences WHERE pid=?`, pid).Scan(&preference.ShowOnlinePresence, &preference.ShowCurrentTitle, &preference.BlockFriendRequests)
|
|
|
|
return preference
|
|
}
|
|
|
|
func isFriendRequestBlocked(requesterPID uint32, requestedPID uint32) bool {
|
|
if err := cassandraClusterSession.Query(`SELECT id FROM pretendo_friends.blocks WHERE blocker_pid=? AND blocked_pid=? LIMIT 1 ALLOW FILTERING`, requestedPID, requesterPID).Scan(); err != nil {
|
|
if err == gocql.ErrNotFound {
|
|
// Assume no block record was found
|
|
return false
|
|
}
|
|
|
|
// TODO: Error handling
|
|
}
|
|
|
|
// Assume a block record was found
|
|
return true
|
|
}
|
|
|
|
func saveFriendRequest(friendRequestID uint64, senderPID uint32, recipientPID uint32, sentTime uint64, expireTime uint64, message string) {
|
|
if err := cassandraClusterSession.Query(`INSERT INTO pretendo_friends.friend_requests (id, sender_pid, recipient_pid, sent_on, expires_on, message, received, accepted, denied) VALUES (?, ?, ?, ?, ?, ?, false, false, false) IF NOT EXISTS`, friendRequestID, senderPID, recipientPID, sentTime, expireTime, message).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func setFriendRequestReceived(friendRequestID uint64) {
|
|
if err := cassandraClusterSession.Query(`UPDATE pretendo_friends.friend_requests SET received=true WHERE id=?`, friendRequestID).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func setFriendRequestAccepted(friendRequestID uint64) {
|
|
if err := cassandraClusterSession.Query(`UPDATE pretendo_friends.friend_requests SET accepted=true WHERE id=?`, friendRequestID).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func acceptFriendshipAndReturnFriendInfo(friendRequestID uint64) *nexproto.FriendInfo {
|
|
var senderPID uint32
|
|
var recipientPID uint32
|
|
|
|
if err := cassandraClusterSession.Query(`SELECT sender_pid, recipient_pid FROM pretendo_friends.friend_requests WHERE id=?`, friendRequestID).Scan(&senderPID, &recipientPID); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
nodeID := rand.Intn(len(snowflakeNodes))
|
|
|
|
snowflakeNode := snowflakeNodes[nodeID]
|
|
|
|
friendshipID1 := uint64(snowflakeNode.Generate().Int64())
|
|
friendshipID2 := uint64(snowflakeNode.Generate().Int64())
|
|
|
|
acceptedTime := nex.NewDateTime(0)
|
|
acceptedTime.FromTimestamp(time.Now())
|
|
|
|
// Friendships are two-way relationships, not just one link between 2 entities
|
|
// "A" has friend "B" and "B" has friend "A", so store both relationships
|
|
|
|
if err := cassandraClusterSession.Query(`INSERT INTO pretendo_friends.friendships (id, user1_pid, user2_pid, date) VALUES (?, ?, ?, ?) IF NOT EXISTS`, friendshipID1, senderPID, recipientPID, acceptedTime.Value()).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if err := cassandraClusterSession.Query(`INSERT INTO pretendo_friends.friendships (id, user1_pid, user2_pid, date) VALUES (?, ?, ?, ?) IF NOT EXISTS`, friendshipID2, recipientPID, senderPID, acceptedTime.Value()).Exec(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
setFriendRequestAccepted(friendRequestID)
|
|
|
|
friendInfo := nexproto.NewFriendInfo()
|
|
connectedUser := connectedUsers[senderPID]
|
|
var lastOnline *nex.DateTime
|
|
|
|
if connectedUser != nil {
|
|
// Online
|
|
friendInfo.NNAInfo = connectedUser.NNAInfo
|
|
friendInfo.Presence = connectedUser.Presence
|
|
|
|
lastOnline = nex.NewDateTime(0)
|
|
lastOnline.FromTimestamp(time.Now())
|
|
} else {
|
|
// Offline
|
|
senderUserInforation := getUserInfoByPID(senderPID)
|
|
encodedMiiData := senderUserInforation["mii"].(bson.M)["data"].(string)
|
|
decodedMiiData, _ := base64.StdEncoding.DecodeString(encodedMiiData)
|
|
|
|
friendInfo.NNAInfo = nexproto.NewNNAInfo()
|
|
friendInfo.NNAInfo.PrincipalBasicInfo = nexproto.NewPrincipalBasicInfo()
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.PID = senderPID
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.NNID = senderUserInforation["username"].(string)
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii = nexproto.NewMiiV2()
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Name = senderUserInforation["mii"].(bson.M)["name"].(string)
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Unknown1 = 0
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Unknown2 = 0
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Data = decodedMiiData
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Datetime = nex.NewDateTime(0)
|
|
friendInfo.NNAInfo.PrincipalBasicInfo.Unknown = 0
|
|
friendInfo.NNAInfo.Unknown1 = 0
|
|
friendInfo.NNAInfo.Unknown2 = 0
|
|
|
|
friendInfo.Presence = nexproto.NewNintendoPresenceV2()
|
|
friendInfo.Presence.ChangedFlags = 0
|
|
friendInfo.Presence.Online = false
|
|
friendInfo.Presence.GameKey = nexproto.NewGameKey()
|
|
friendInfo.Presence.GameKey.TitleID = 0
|
|
friendInfo.Presence.GameKey.TitleVersion = 0
|
|
friendInfo.Presence.Unknown1 = 0
|
|
friendInfo.Presence.Message = ""
|
|
friendInfo.Presence.Unknown2 = 0
|
|
friendInfo.Presence.Unknown3 = 0
|
|
friendInfo.Presence.GameServerID = 0
|
|
friendInfo.Presence.Unknown4 = 0
|
|
friendInfo.Presence.PID = senderPID
|
|
friendInfo.Presence.GatheringID = 0
|
|
friendInfo.Presence.ApplicationData = []byte{0x00}
|
|
friendInfo.Presence.Unknown5 = 0
|
|
friendInfo.Presence.Unknown6 = 0
|
|
friendInfo.Presence.Unknown7 = 0
|
|
|
|
var lastOnlineTime uint64
|
|
if err := cassandraClusterSession.Query(`SELECT time FROM pretendo_friends.last_online WHERE pid=?`, senderPID).Scan(&lastOnlineTime); err != nil {
|
|
if err == gocql.ErrNotFound {
|
|
lastOnlineTime = nex.NewDateTime(0).Now()
|
|
} else {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
lastOnline = nex.NewDateTime(lastOnlineTime) // TODO: Change this
|
|
}
|
|
|
|
friendInfo.Status = getUserComment(senderPID)
|
|
friendInfo.BecameFriend = acceptedTime
|
|
friendInfo.LastOnline = lastOnline // TODO: Change this
|
|
friendInfo.Unknown = 0
|
|
|
|
return friendInfo
|
|
}
|
|
|
|
//////////////////////////////
|
|
// //
|
|
// MongoDB database methods //
|
|
// //
|
|
//////////////////////////////
|
|
|
|
func getUserInfoByPID(pid uint32) bson.M {
|
|
var result bson.M
|
|
|
|
err := mongoCollection.FindOne(context.TODO(), bson.D{{Key: "pid", Value: pid}}, options.FindOne()).Decode(&result)
|
|
|
|
if err != nil {
|
|
if err == mongo.ErrNoDocuments {
|
|
return nil
|
|
}
|
|
|
|
panic(err)
|
|
}
|
|
|
|
return result
|
|
}
|