-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(matchmake-extension): Implement NotificationData methods
The NotificationData methods are used by games to send notifications to friends about user activity, among others. These notifications are created or updated using `UpdateNotificationData`, which the server will register and send to the connected friends (as seen on Mario Tennis Open). The lifetime of these notifications is the same as the connection of the user who sends them. That is, when a user sends a notification and then disconnects, the notifications will be discarded. All notifications sent over `UpdateNotificationData` are logged inside the `tracking.notification_data` table to prevent abuse. The type of these notifications is also constrained to a range of specific values reserved for game-specific purposes (from 101 to 108).
- Loading branch information
1 parent
bcc53de
commit 21b019a
Showing
8 changed files
with
395 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package database | ||
|
||
import ( | ||
"github.com/PretendoNetwork/nex-go/v2" | ||
"github.com/PretendoNetwork/nex-go/v2/types" | ||
common_globals "github.com/PretendoNetwork/nex-protocols-common-go/v2/globals" | ||
notifications_types "github.com/PretendoNetwork/nex-protocols-go/v2/notifications/types" | ||
pqextended "github.com/PretendoNetwork/pq-extended" | ||
) | ||
|
||
// GetNotificationDatas gets the notification datas that belong to friends of the user and match with any of the given types | ||
func GetNotificationDatas(manager *common_globals.MatchmakingManager, sourcePID types.PID, notificationTypes []uint32) ([]notifications_types.NotificationEvent, *nex.Error) { | ||
dataList := make([]notifications_types.NotificationEvent, 0) | ||
|
||
var friendList []uint32 | ||
if manager.GetUserFriendPIDs != nil { | ||
friendList = manager.GetUserFriendPIDs(uint32(sourcePID)) | ||
} | ||
|
||
rows, err := manager.Database.Query(`SELECT | ||
source_pid, | ||
type, | ||
param_1, | ||
param_2, | ||
param_str | ||
FROM matchmaking.notifications WHERE active=true AND source_pid=ANY($1) AND type=ANY($2) | ||
`, pqextended.Array(friendList), pqextended.Array(notificationTypes)) | ||
if err != nil { | ||
return nil, nex.NewError(nex.ResultCodes.Core.Unknown, err.Error()) | ||
} | ||
|
||
for rows.Next() { | ||
notificationData := notifications_types.NewNotificationEvent() | ||
|
||
err = rows.Scan( | ||
¬ificationData.PIDSource, | ||
¬ificationData.Type, | ||
¬ificationData.Param1, | ||
¬ificationData.Param2, | ||
¬ificationData.StrParam, | ||
) | ||
if err != nil { | ||
common_globals.Logger.Critical(err.Error()) | ||
continue | ||
} | ||
|
||
dataList = append(dataList, notificationData) | ||
} | ||
|
||
rows.Close() | ||
|
||
return dataList, nil | ||
} |
17 changes: 17 additions & 0 deletions
17
matchmake-extension/database/inactivate_notification_datas.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package database | ||
|
||
import ( | ||
"github.com/PretendoNetwork/nex-go/v2" | ||
"github.com/PretendoNetwork/nex-go/v2/types" | ||
common_globals "github.com/PretendoNetwork/nex-protocols-common-go/v2/globals" | ||
) | ||
|
||
// InactivateNotificationDatas marks the notifications of a given user as inactive | ||
func InactivateNotificationDatas(manager *common_globals.MatchmakingManager, sourcePID types.PID) *nex.Error { | ||
_, err := manager.Database.Exec(`UPDATE matchmaking.notifications SET active=false WHERE source_pid=$1`, sourcePID) | ||
if err != nil { | ||
return nex.NewError(nex.ResultCodes.Core.Unknown, err.Error()) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package database | ||
|
||
import ( | ||
"github.com/PretendoNetwork/nex-go/v2" | ||
notifications_types "github.com/PretendoNetwork/nex-protocols-go/v2/notifications/types" | ||
common_globals "github.com/PretendoNetwork/nex-protocols-common-go/v2/globals" | ||
) | ||
|
||
// UpdateNotificationData updates the notification data of the specified user and type | ||
func UpdateNotificationData(manager *common_globals.MatchmakingManager, notificationData notifications_types.NotificationEvent) *nex.Error { | ||
_, err := manager.Database.Exec(`INSERT INTO matchmaking.notifications ( | ||
source_pid, | ||
type, | ||
param_1, | ||
param_2, | ||
param_str | ||
) VALUES ( | ||
$1, | ||
$2, | ||
$3, | ||
$4, | ||
$5 | ||
) ON CONFLICT (source_pid, type) DO UPDATE SET | ||
param_1=$3, param_2=$4, param_str=$5, active=true WHERE source_pid=$1 AND type=$2`, | ||
notificationData.PIDSource, | ||
notificationData.Type, | ||
notificationData.Param1, | ||
notificationData.Param2, | ||
notificationData.StrParam, | ||
) | ||
if err != nil { | ||
return nex.NewError(nex.ResultCodes.Core.Unknown, err.Error()) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package matchmake_extension | ||
|
||
import ( | ||
"github.com/PretendoNetwork/nex-go/v2" | ||
"github.com/PretendoNetwork/nex-go/v2/types" | ||
common_globals "github.com/PretendoNetwork/nex-protocols-common-go/v2/globals" | ||
"github.com/PretendoNetwork/nex-protocols-common-go/v2/matchmake-extension/database" | ||
matchmake_extension "github.com/PretendoNetwork/nex-protocols-go/v2/matchmake-extension" | ||
notifications_types "github.com/PretendoNetwork/nex-protocols-go/v2/notifications/types" | ||
) | ||
|
||
func (commonProtocol *CommonProtocol) getFriendNotificationData(err error, packet nex.PacketInterface, callID uint32, uiType types.Int32) (*nex.RMCMessage, *nex.Error) { | ||
if err != nil { | ||
common_globals.Logger.Error(err.Error()) | ||
return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, err.Error()) | ||
} | ||
|
||
// * This method can only receive notifications within the range 101-108, which are reserved for game-specific notifications | ||
if uiType < 101 || uiType > 108 { | ||
return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") | ||
} | ||
|
||
connection := packet.Sender().(*nex.PRUDPConnection) | ||
endpoint := connection.Endpoint().(*nex.PRUDPEndPoint) | ||
|
||
commonProtocol.manager.Mutex.RLock() | ||
|
||
notificationDatas, nexError := database.GetNotificationDatas(commonProtocol.manager, connection.PID(), []uint32{uint32(uiType)}) | ||
if nexError != nil { | ||
commonProtocol.manager.Mutex.RUnlock() | ||
return nil, nexError | ||
} | ||
|
||
commonProtocol.manager.Mutex.RUnlock() | ||
|
||
dataList := types.NewList[notifications_types.NotificationEvent]() | ||
dataList = notificationDatas | ||
|
||
rmcResponseStream := nex.NewByteStreamOut(endpoint.LibraryVersions(), endpoint.ByteStreamSettings()) | ||
|
||
dataList.WriteTo(rmcResponseStream) | ||
|
||
rmcResponseBody := rmcResponseStream.Bytes() | ||
|
||
rmcResponse := nex.NewRMCSuccess(endpoint, rmcResponseBody) | ||
rmcResponse.ProtocolID = matchmake_extension.ProtocolID | ||
rmcResponse.MethodID = matchmake_extension.MethodGetFriendNotificationData | ||
rmcResponse.CallID = callID | ||
|
||
if commonProtocol.OnAfterUpdateNotificationData != nil { | ||
go commonProtocol.OnAfterGetFriendNotificationData(packet, uiType) | ||
} | ||
|
||
return rmcResponse, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package matchmake_extension | ||
|
||
import ( | ||
"github.com/PretendoNetwork/nex-go/v2" | ||
"github.com/PretendoNetwork/nex-go/v2/types" | ||
matchmake_extension "github.com/PretendoNetwork/nex-protocols-go/v2/matchmake-extension" | ||
notifications_types "github.com/PretendoNetwork/nex-protocols-go/v2/notifications/types" | ||
common_globals "github.com/PretendoNetwork/nex-protocols-common-go/v2/globals" | ||
"github.com/PretendoNetwork/nex-protocols-common-go/v2/matchmake-extension/database" | ||
) | ||
|
||
func (commonProtocol *CommonProtocol) getlstFriendNotificationData(err error, packet nex.PacketInterface, callID uint32, lstTypes types.List[types.UInt32]) (*nex.RMCMessage, *nex.Error) { | ||
if err != nil { | ||
common_globals.Logger.Error(err.Error()) | ||
return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, err.Error()) | ||
} | ||
|
||
connection := packet.Sender().(*nex.PRUDPConnection) | ||
endpoint := connection.Endpoint().(*nex.PRUDPEndPoint) | ||
|
||
notificationTypes := make([]uint32, len(lstTypes)) | ||
for i, notificationType := range lstTypes { | ||
// * This method can only receive notifications within the range 101-108, which are reserved for game-specific notifications | ||
if notificationType < 101 || notificationType > 108 { | ||
return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") | ||
} | ||
|
||
notificationTypes[i] = uint32(notificationType) | ||
} | ||
|
||
commonProtocol.manager.Mutex.RLock() | ||
|
||
notificationDatas, nexError := database.GetNotificationDatas(commonProtocol.manager, connection.PID(), notificationTypes) | ||
if nexError != nil { | ||
commonProtocol.manager.Mutex.RUnlock() | ||
return nil, nexError | ||
} | ||
|
||
commonProtocol.manager.Mutex.RUnlock() | ||
|
||
dataList := types.NewList[notifications_types.NotificationEvent]() | ||
dataList = notificationDatas | ||
|
||
rmcResponseStream := nex.NewByteStreamOut(endpoint.LibraryVersions(), endpoint.ByteStreamSettings()) | ||
|
||
dataList.WriteTo(rmcResponseStream) | ||
|
||
rmcResponseBody := rmcResponseStream.Bytes() | ||
|
||
rmcResponse := nex.NewRMCSuccess(endpoint, rmcResponseBody) | ||
rmcResponse.ProtocolID = matchmake_extension.ProtocolID | ||
rmcResponse.MethodID = matchmake_extension.MethodGetlstFriendNotificationData | ||
rmcResponse.CallID = callID | ||
|
||
if commonProtocol.OnAfterUpdateNotificationData != nil { | ||
go commonProtocol.OnAfterGetlstFriendNotificationData(packet, lstTypes) | ||
} | ||
|
||
return rmcResponse, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package tracking | ||
|
||
import ( | ||
"database/sql" | ||
"time" | ||
|
||
"github.com/PretendoNetwork/nex-go/v2" | ||
notifications_types "github.com/PretendoNetwork/nex-protocols-go/v2/notifications/types" | ||
) | ||
|
||
// LogNotificationData logs the update of the notification data of a user with UpdateNotificationData | ||
func LogNotificationData(db *sql.DB, notificationData notifications_types.NotificationEvent) *nex.Error { | ||
eventTime := time.Now().UTC() | ||
|
||
_, err := db.Exec(`INSERT INTO tracking.notification_data ( | ||
date, | ||
source_pid, | ||
type, | ||
param_1, | ||
param_2, | ||
param_str | ||
) VALUES ( | ||
$1, | ||
$2, | ||
$3, | ||
$4, | ||
$5, | ||
$6 | ||
)`, | ||
eventTime, | ||
notificationData.PIDSource, | ||
notificationData.Type, | ||
notificationData.Param1, | ||
notificationData.Param2, | ||
notificationData.StrParam, | ||
) | ||
if err != nil { | ||
return nex.NewError(nex.ResultCodes.Core.Unknown, err.Error()) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.