Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ws and rpc server handlers #8

Merged
merged 4 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ dist/
node_modules/
**/.DS_Store
coverage
.env
.env
protoc3
30 changes: 30 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
PROTOBUF_VERSION = 3.19.1
PROTOC ?= protoc
UNAME := $(shell uname)
PROTO_FILES := $(wildcard src/*.proto)
export PATH := ts-server/node_modules/.bin:/usr/local/include/:protoc3/bin:$(PATH)

ifeq ($(UNAME),Darwin)
PROTOBUF_ZIP = protoc-$(PROTOBUF_VERSION)-osx-x86_64.zip
else
PROTOBUF_ZIP = protoc-$(PROTOBUF_VERSION)-linux-x86_64.zip
endif

# for ts
install_compiler:
@# remove local folder
rm -rf protoc3 || true

@# Make sure you grab the latest version
curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOBUF_VERSION)/$(PROTOBUF_ZIP)

@# Unzip
unzip $(PROTOBUF_ZIP) -d protoc3
@# delete the files
rm $(PROTOBUF_ZIP)

@# move protoc to /usr/local/bin/
chmod +x protoc3/bin/protoc

build: install_compiler
@./build-local-proto.sh
5 changes: 5 additions & 0 deletions build-local-proto.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
./protoc3/bin/protoc \
--plugin=./node_modules/.bin/protoc-gen-ts_proto \
--ts_proto_opt=esModuleInterop=true,returnObservable=false,outputServices=generic-definitions \
--ts_proto_out="$(pwd)/src" -I="$(pwd)" \
"$(pwd)/friendships_ea.proto"
158 changes: 158 additions & 0 deletions friendships_ea.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// THIS LIVES HERE FOR NOW, BUT IT SHOULD BE MOVED TO @dcl/protcol when release

syntax = "proto3";
package decentraland.social.friendships_ea;

import "google/protobuf/empty.proto";


// This message is a response that is sent from the server to the client
message FriendshipEventResponse {
oneof body {
RequestResponse request = 1;
AcceptResponse accept = 2;
RejectResponse reject = 4;
DeleteResponse delete = 5;
CancelResponse cancel = 6;
}
}

message FriendshipEventResponses {
repeated FriendshipEventResponse responses = 1;
}

message FriendshipEventPayload {
oneof body {
RequestPayload request = 1;
AcceptPayload accept = 2;
RejectPayload reject = 4;
DeletePayload delete = 5;
CancelPayload cancel = 6;
}
}

message User { string address = 1; }

message Users { repeated User users = 1; }

message RequestResponse {
User user = 1;
int64 created_at = 2;
optional string message = 3;
}

message RequestPayload {
User user = 1;
optional string message = 3;
}

message Requests {
int64 total = 1; // Total amount of friendship requests
repeated RequestResponse items = 2;
}

message RequestEvents {
Requests outgoing = 1; // Requests the authed user have sent to users
Requests incoming = 2; // Requests the authed user have received from users
}

message AcceptResponse { User user = 1; }

message AcceptPayload { User user = 1; }

message RejectResponse { User user = 1; }

message RejectPayload { User user = 1; }

message DeleteResponse { User user = 1; }

message DeletePayload { User user = 1; }

message CancelResponse { User user = 1; }

message CancelPayload { User user = 1; }

message UpdateFriendshipPayload {
FriendshipEventPayload event = 1;
}

message MutualFriendsPayload {
User user = 1;
}

message BadRequestError {
string message = 1;
}
message UnauthorizedError {
string message = 1;
}
message ForbiddenError {
string message = 1;
}
message TooManyRequestsError {
string message = 1;
}
message InternalServerError {
string message = 1;
}

message UsersResponse {
oneof response {
Users users = 1;
InternalServerError internal_server_error = 2;
UnauthorizedError unauthorized_error = 3;
ForbiddenError forbidden_error = 4;
TooManyRequestsError too_many_requests_error = 5;
BadRequestError bad_request_error = 6;
}
}

message RequestEventsResponse {
oneof response {
RequestEvents events = 1;
InternalServerError internal_server_error = 2;
UnauthorizedError unauthorized_error = 3;
ForbiddenError forbidden_error = 4;
TooManyRequestsError too_many_requests_error = 5;
}
}

message UpdateFriendshipResponse {
oneof response {
FriendshipEventResponse event = 1;
InternalServerError internal_server_error = 2;
UnauthorizedError unauthorized_error = 3;
ForbiddenError forbidden_error = 4;
TooManyRequestsError too_many_requests_error = 5;
BadRequestError bad_request_error = 6;
}
}

message SubscribeFriendshipEventsUpdatesResponse {
oneof response {
FriendshipEventResponses events = 1;
InternalServerError internal_server_error = 2;
UnauthorizedError unauthorized_error = 3;
ForbiddenError forbidden_error = 4;
TooManyRequestsError too_many_requests_error = 5;
}
}

service FriendshipsService {
// Get the list of friends for the authenticated user
rpc GetFriends(google.protobuf.Empty) returns (stream UsersResponse) {}

// Get the list of mutual friends between the authenticated user and the one in the parameter
rpc GetMutualFriends(MutualFriendsPayload) returns (stream UsersResponse) {}

// Get the list of request events for the authenticated user
rpc GetRequestEvents(google.protobuf.Empty) returns (RequestEventsResponse) {}

// Update friendship status: REQUEST, ACCEPT, REJECT, CANCEL, DELETE
rpc UpdateFriendshipEvent(UpdateFriendshipPayload)
returns (UpdateFriendshipResponse) {}

// Subscribe to updates of friendship status: REQUEST, ACCEPT, REJECT, CANCEL, DELETE
rpc SubscribeFriendshipEventsUpdates(google.protobuf.Empty)
returns (stream SubscribeFriendshipEventsUpdatesResponse) {}
}
12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@
"scripts": {
"build": "tsc -p tsconfig.json",
"start": "node --trace-warnings --abort-on-uncaught-exception --unhandled-rejections=strict dist/index.js",
"dev": "nodemon --watch 'src/**' --ext 'ts,json' --ignore 'src/**/*.spec.ts' --ignore 'src/migrations' --exec 'ts-node src/index.ts'",
"test": "jest --forceExit --detectOpenHandles --coverage --verbose",
"migrate": "node-pg-migrate --database-url-var PG_COMPONENT_PSQL_CONNECTION_STRING --envPath .env -j ts --tsconfig tsconfig.json -m ./src/migrations",
"lint:check": "eslint '**/*.{js,ts}'",
"lint:fix": "eslint '**/*.{js,ts}' --fix"
},
"devDependencies": {
"@dcl/eslint-config": "^2.0.0",
"@protobuf-ts/protoc": "^2.9.4",
"@types/node": "^20.11.28",
"@types/ws": "^8.5.10",
"@well-known-components/test-helpers": "^1.5.6",
"nodemon": "^3.1.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.2"
},
Expand All @@ -24,12 +28,18 @@
"tabWidth": 2
},
"dependencies": {
"@dcl/platform-crypto-middleware": "^1.0.2",
"@dcl/protocol": "^1.0.0-2569677750.commit-6ce832a",
"@dcl/rpc": "^1.1.2",
"@well-known-components/env-config-provider": "^1.2.0",
"@well-known-components/fetch-component": "^2.0.2",
"@well-known-components/http-server": "^2.1.0",
"@well-known-components/interfaces": "^1.4.3",
"@well-known-components/logger": "^3.1.3",
"@well-known-components/metrics": "^2.1.0",
"@well-known-components/pg-component": "^0.2.2",
"@well-known-components/uws-http-server": "^0.0.1-20240314125425.commit-711dd8f"
"@well-known-components/uws-http-server": "^0.0.1-20240314125425.commit-711dd8f",
"fp-future": "^1.0.1",
"ws": "^8.16.0"
}
}
80 changes: 80 additions & 0 deletions src/adapters/rpcServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { createRpcServer } from '@dcl/rpc'
import { registerService } from '@dcl/rpc/dist/codegen'
import {
FriendshipsServiceDefinition,
UsersResponse,
SubscribeFriendshipEventsUpdatesResponse,
RequestEventsResponse,
UpdateFriendshipResponse
} from '../friendships_ea'
import { AppComponents, RpcServerContext } from '../types'

export default function createRpcServerComponent(components: Pick<AppComponents, 'logs'>) {
const { logs } = components

const server = createRpcServer<RpcServerContext>({
logger: logs.getLogger('rpc-server')
})

const _logger = logs.getLogger('rpc-server-handler')
// Mocked server until we get the new service definition & db queries done
server.setHandler(async function handler(port) {
registerService(port, FriendshipsServiceDefinition, async () => ({
getFriends(_request, _context) {
const generator = async function* () {
const response: UsersResponse = {
users: { users: [] }
}
yield response
}

return generator()
},
getMutualFriends(_request, _context) {
const generator = async function* () {
const response: UsersResponse = {
users: { users: [] }
}
yield response
}

return generator()
},
async getRequestEvents(_request, _context) {
const res: RequestEventsResponse = {
events: {
outgoing: { items: [], total: 0 },
incoming: { items: [], total: 0 }
}
}
return res
},
async updateFriendshipEvent(_request, _context) {
const res: UpdateFriendshipResponse = {
event: {
accept: {
user: {
address: '0xa'
}
}
}
}
return res
},
subscribeFriendshipEventsUpdates(_request, _context) {
const generator = async function* () {
const response: SubscribeFriendshipEventsUpdatesResponse = {
events: {
responses: []
}
}
yield response
}

return generator()
}
}))
})

return server
}
25 changes: 25 additions & 0 deletions src/adapters/ws.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { WebSocketServer } from 'ws'
import { IWebSocketComponent } from '../types'

export async function createWsComponent(): Promise<IWebSocketComponent> {
let wss: WebSocketServer | undefined

async function start() {
if (wss) return

wss = new WebSocketServer({ noServer: true })
}

async function stop() {
wss?.close()
wss = undefined
}

await start()

return {
start,
stop,
ws: wss!
}
}
15 changes: 13 additions & 2 deletions src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,22 @@ import { AppComponents, GlobalContext } from './types'
import { metricDeclarations } from './metrics'
import { createPgComponent } from '@well-known-components/pg-component'
import { createDBComponent } from './adapters/db'
import { createWsComponent } from './adapters/ws'
import createRpcServerComponent from './adapters/rpcServer'
import { createFetchComponent } from '@well-known-components/fetch-component'

// Initialize all the components of the app
export async function initComponents(): Promise<AppComponents> {
const config = await createDotEnvConfigComponent({ path: ['.env.default', '.env'] })
const metrics = await createMetricsComponent(metricDeclarations, { config })
const logs = await createLogComponent({ metrics })
const server = await createServerComponent<GlobalContext>({ config, logs }, {})

const ws = await createWsComponent()
const server = await createServerComponent<GlobalContext>({ config, logs, ws: ws.ws }, {})
const statusChecks = await createStatusCheckComponent({ server, config })
const rpcServer = createRpcServerComponent({ logs })

const fetcher = createFetchComponent()

let databaseUrl: string | undefined = await config.getString('PG_COMPONENT_PSQL_CONNECTION_STRING')
if (!databaseUrl) {
Expand Down Expand Up @@ -54,6 +62,9 @@ export async function initComponents(): Promise<AppComponents> {
statusChecks,
metrics,
pg,
db
db,
ws,
rpcServer,
fetcher
}
}
Loading
Loading