ADR-137: Technical Assessment for the new Friend Request

More details about this document
Latest published version:
https://adr.decentraland.org/adr/ADR-137
Authors:
sandrade-dcl
lorux0
Feedback:
GitHub decentraland/adr (pull requests, new issue, open issues)
Edit this documentation:
GitHub View commits View commits on githistory.xyz

Need

This is a technical proposal for the needs described here: PRD: New Friend Requests

The intention of this document is:

Involved teams

This initiative will require a cross team effort that will include the following teams:

The different responsibilities will be covered in more detail in the analysis of each part of the feature. A tag to the respective team will be placed next to each functionality.

Approach

For this to work we need to synchronize the information between the Renderer, Kernel and Matrix servers.

Due to the current architecture implemented in the backend side, the idea would be to use always Kernel as a bridge between the Renderer and the Matrix server. So any communication needed between both sides will be done through messages in Kernel↔Renderer and the message exchange is defined by RPC calls.

In terms of needed communications, we have identified the next main dependencies between Client and Backend:

Send a Friend Request

sequenceDiagram
  participant renderer
  participant kernel
  
note left of renderer: The user sends a friend request from the pop-up.
renderer->kernel: SendFriendRequest(SendFriendRequestPayload{ userId:'0x...', messageBody='hello!' })
note right of kernel: Ask the server to create the friend request.
kernel-->renderer: AddUserProfilesToCatalog(addUserProfilesPayload)
kernel-->renderer: SendFriendRequestReply({ message: { reply: SendFriendRequestReplyOk | error: int }})
note left of renderer: In case of success, create a new entry in the SENT requests list.
note left of renderer: In case of error, show the error.
SendFriendRequestPayload {
  string user_id = 1;
  string message_body = 2;
}
SendFriendRequestReplyOk {
  FriendRequestInfo friend_request = 1; // Friend request info on the request you've sent to a user
}
SendFriendRequestReply {
  oneof message {
    SendFriendRequestReplyOk reply = 1;
    FriendshipErrorCode error = 2;
  }
}

Cancel a Friend Request

sequenceDiagram
  participant renderer
  participant kernel
  
note left of renderer: The user cancels a friend request from the list.
renderer->kernel: CancelFriendRequest(CancelFriendRequestPayload{ friendRequestId: '<id>' })
note right of kernel: Ask the server to cancel the friend request.
kernel-->renderer: CancelFriendRequestReply({ message: { reply: CancelFriendRequestReplyOk | error: int }})
note left of renderer: In case of success, remove the entry from the SENT requests list.
note left of renderer: In case of error, show the error.
CancelFriendRequestPayload {
  string friend_request_id = 1;
}
CancelFriendRequestReplyOk {
  FriendRequestInfo friend_request = 1; // Friend request info on the request you've canceled
}
CancelFriendRequestReply {
  oneof message {
    CancelFriendRequestReplyOk reply = 1;
    FriendshipErrorCode error = 2;
  }
}

Accept a Friend Request

sequenceDiagram
  participant renderer
  participant kernel
  
note left of renderer: The user accepts a friend request from the pop-up.
renderer->kernel: AcceptFriendRequest(AcceptFriendRequestPayload{ friendRequestId: '<id>'})
note right of kernel: Ask the server to accept the friend request.
kernel-->renderer: AcceptFriendRequestReply({ message: { reply: AcceptFriendRequestReplyOk | error: int }})
note left of renderer: In case of success, add a new entry in the notifications panel and remove the new entry from the RECEIVED requests list.
note left of renderer: In case of error, show the error.
note right of kernel: In case of success, if the friend request has a non-empty message body, it must be registered as part of the messages history of that user.
kernel-->renderer: Add the chat message and increase the unseen notifications counter for that specific user.
note left of renderer: Display the unseen message as usual.
AcceptFriendRequestPayload {
  string friend_request_id = 1;
}
AcceptFriendRequestReplyOk {
  FriendRequestInfo friend_request = 1;
}
AcceptFriendRequestReply {
  oneof message {
    AcceptFriendRequestReplyOk reply = 1;
    FriendshipErrorCode error = 2;
  }
}

Reject a Friend Request

sequenceDiagram
  participant renderer
  participant kernel
  
note left of renderer: The user rejects a friend request from the pop-up.
renderer->kernel: RejectFriendRequest(RejectFriendRequestPayload{ friendRequestId: '<id>'})
note right of kernel: Ask the server to reject the friend request.
kernel-->renderer: RejectFriendRequestReply({ message: { reply: RejectFriendRequestReplyOk | error: int }})
note left of renderer: In case of success, remove the new entry from the RECEIVED requests list.
note left of renderer: In case of error, show the error.
RejectFriendRequestPayload {
  string friend_request_id = 1;
}
RejectFriendRequestReplyOk {
  FriendRequestInfo friend_request = 1;
}
RejectFriendRequestReply {
  oneof message {
    RejectFriendRequestReplyOk reply = 1;
    FriendshipErrorCode error = 2;
  }
}

Received Friend Request (push notifications)

sequenceDiagram
  participant renderer
  participant kernel
  
note left of renderer: During the session.
note right of kernel: An user sends us a friend request.
kernel-->renderer: AddUserProfilesToCatalog(addUserProfilesPayload)
kernel->renderer: ReceiveFriendRequest(RendererReceiveFriendRequestPayload{ friend_request: {...}} )
note left of renderer: Create a new entry in the RECEIVED requests list.
note left of renderer: Add a new entry in the notifications panel.
RendererReceiveFriendRequestPayload {
    FriendRequestInfo friend_request = 1;
}

Canceled Friend Request (push notifications)

sequenceDiagram
  participant renderer
  participant kernel
  
note left of renderer: During the session.
note right of kernel: An user cancels us a friend request.
kernel-->renderer: AddUserProfilesToCatalog(addUserProfilesPayload)
kernel->renderer: CancelFriendRequest(RendererCancelFriendRequestPayload{ <'id'> } )
RendererCancelFriendRequestPayload {
    string user_id = 1;
}

Rejected Friend Request (push notifications)

sequenceDiagram
  participant renderer
  participant kernel

note left of renderer: During the session.
note right of kernel: An user rejects us a friend request.
kernel-->renderer: AddUserProfilesToCatalog(addUserProfilesPayload)
kernel->renderer: RejectFriendRequest(RendererRejectFriendRequestPayload{ <'id'> } )
RendererRejectFriendRequestPayload {
    string user_id = 1;
}

Approved Friend Request (push notifications)

sequenceDiagram
  participant renderer
  participant kernel

note left of renderer: During the session.
note right of kernel: An user approves us a friend request.
kernel-->renderer: AddUserProfilesToCatalog(addUserProfilesPayload)
kernel->renderer: ApproveFriendRequest(RendererApproveFriendRequestPayload{ <'id'> } )
RendererApproveFriendRequestPayload {
    string user_id = 1;
}

Get Friend Request List

sequenceDiagram
  participant renderer
  participant kernel
  
renderer->kernel: GetFriendRequests(GetFriendRequestsPayload{ sentLimit: 50, sentSkip: 0, receivedLimit: 50, receivedSkip: 0 })
note right of kernel: Request the first (50) sent/received requests to the server.
kernel-->renderer: AddUserProfilesToCatalog(addUserProfilesPayload)
note left of renderer: Needed to fill in the UI info later.
kernel-->renderer: GetFriendRequestsReply({ message: { reply: GetFriendRequestsReplyOk | error: int }})
kernel-->renderer: UpdateUserPresence(userPresencePayload)
note left of renderer: Show online/offline status of each request.
note left of renderer: The user clicks on "show more requests".
renderer->kernel: GetFriendRequests(GetFriendRequestsPayload{sentLimit: 30, sentSkip: 50, receivedLimit: 30, receivedSkip: 50})
note right of kernel: Requests the next 30 friend requests to server.
kernel-->renderer: AddUserProfilesToCatalog(addUserProfilesPayload)
kernel-->renderer: GetFriendRequestsReply({ message: { reply: GetFriendRequestsReplyOk | error: int }})
kernel-->renderer: UpdateUserPresence(userPresencePayload)
GetFriendRequestsPayload {
  int32 sent_limit = 1; // Max amount of entries of sent friend requests to request
  int32 sent_skip = 2; // The amount of entries of sent friend requests to skip
  int32 received_limit = 3; // Max amount of entries of received friend requests to request
  int32 received_skip = 4; // The amount of entries of received friend requests to skip
}
GetFriendRequestsReplyOk {
  repeated FriendRequestInfo requested_to = 1; // Friend request info on the requests you've sent to users
  repeated FriendRequestInfo requested_from = 2; // Friend request info on the requests you've received from users
  int32 total_received_friend_requests = 3; // Total amount of friend requests received
  int32 total_sent_friend_requests = 4; // Total amount of friend requests sent
}
GetFriendRequestsReply {
  oneof message {
    GetFriendRequestsReplyOk reply = 1;
    FriendshipErrorCode error = 2;
  }
}

Common Payloads

FriendRequestInfo {
  string friend_request_id = 1;
  uint64 timestamp = 2;
  string from = 3;
  string to = 4;
  optional string message_body = 5;
}
FriendshipErrorCode {
  FEC_TOO_MANY_REQUESTS_SENT = 0; // Any uncategorized friend request related error
  FEC_NOT_ENOUGH_TIME_PASSED = 1;
  FEC_BLOCKED_USER = 2;
  FEC_NON_EXISTING_USER = 3;
  FEC_INVALID_REQUEST = 4;
  FEC_UNKNOWN = 5;
}

License

Copyright and related rights waived via CC0-1.0. Review