feat: add realtime with socket.io
This commit is contained in:
parent
97b1d04261
commit
5643ab420f
@ -12,7 +12,10 @@
|
|||||||
"prettier/prettier": "error",
|
"prettier/prettier": "error",
|
||||||
"import/order": [
|
"import/order": [
|
||||||
"error",
|
"error",
|
||||||
{ "groups": ["builtin", "external", "internal"] }
|
{
|
||||||
|
"groups": ["builtin", "external", "internal"],
|
||||||
|
"newlines-between": "always"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"import/extensions": ["error", "always"],
|
"import/extensions": ["error", "always"],
|
||||||
"unicorn/prefer-node-protocol": "error",
|
"unicorn/prefer-node-protocol": "error",
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@ node_modules
|
|||||||
|
|
||||||
# production
|
# production
|
||||||
build
|
build
|
||||||
|
.swc
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
coverage
|
coverage
|
||||||
|
721
package-lock.json
generated
721
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
25
package.json
25
package.json
@ -18,7 +18,7 @@
|
|||||||
"generate": "plop",
|
"generate": "plop",
|
||||||
"lint:commit": "commitlint",
|
"lint:commit": "commitlint",
|
||||||
"lint:editorconfig": "editorconfig-checker",
|
"lint:editorconfig": "editorconfig-checker",
|
||||||
"lint:markdown": "markdownlint '**/*.md' --dot --ignore 'node_modules'",
|
"lint:markdown": "markdownlint '**/*.md' --dot --ignore-path '.gitignore'",
|
||||||
"lint:typescript": "eslint '**/*.{js,ts,jsx,tsx}'",
|
"lint:typescript": "eslint '**/*.{js,ts,jsx,tsx}'",
|
||||||
"lint:prettier": "prettier '.' --check",
|
"lint:prettier": "prettier '.' --check",
|
||||||
"lint:staged": "lint-staged",
|
"lint:staged": "lint-staged",
|
||||||
@ -31,21 +31,22 @@
|
|||||||
"postinstall": "husky install"
|
"postinstall": "husky install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "3.7.0",
|
"@prisma/client": "3.8.0",
|
||||||
"@sinclair/typebox": "0.23.2",
|
"@sinclair/typebox": "0.23.2",
|
||||||
|
"@thream/socketio-jwt": "2.1.1",
|
||||||
"axios": "0.24.0",
|
"axios": "0.24.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"dotenv": "10.0.0",
|
"dotenv": "11.0.0",
|
||||||
"ejs": "3.1.6",
|
"ejs": "3.1.6",
|
||||||
"fastify": "3.25.3",
|
"fastify": "3.25.3",
|
||||||
"fastify-cors": "6.0.2",
|
"fastify-cors": "6.0.2",
|
||||||
"fastify-helmet": "5.3.2",
|
"fastify-helmet": "6.0.0",
|
||||||
"fastify-multipart": "5.2.1",
|
"fastify-multipart": "5.2.1",
|
||||||
"fastify-plugin": "3.0.0",
|
"fastify-plugin": "3.0.0",
|
||||||
"fastify-rate-limit": "5.7.0",
|
"fastify-rate-limit": "5.7.0",
|
||||||
"fastify-sensible": "3.1.2",
|
"fastify-sensible": "3.1.2",
|
||||||
"fastify-static": "4.5.0",
|
"fastify-static": "4.5.0",
|
||||||
"fastify-swagger": "4.13.0",
|
"fastify-swagger": "4.13.1",
|
||||||
"fastify-url-data": "3.0.3",
|
"fastify-url-data": "3.0.3",
|
||||||
"http-errors": "2.0.0",
|
"http-errors": "2.0.0",
|
||||||
"jsonwebtoken": "8.5.1",
|
"jsonwebtoken": "8.5.1",
|
||||||
@ -55,18 +56,18 @@
|
|||||||
"socket.io": "4.4.1"
|
"socket.io": "4.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "16.0.1",
|
"@commitlint/cli": "16.0.2",
|
||||||
"@commitlint/config-conventional": "16.0.0",
|
"@commitlint/config-conventional": "16.0.0",
|
||||||
"@saithodev/semantic-release-backmerge": "2.1.0",
|
"@saithodev/semantic-release-backmerge": "2.1.0",
|
||||||
"@swc/cli": "0.1.55",
|
"@swc/cli": "0.1.55",
|
||||||
"@swc/core": "1.2.127",
|
"@swc/core": "1.2.129",
|
||||||
"@swc/jest": "0.2.15",
|
"@swc/jest": "0.2.17",
|
||||||
"@types/bcryptjs": "2.4.2",
|
"@types/bcryptjs": "2.4.2",
|
||||||
"@types/busboy": "0.3.1",
|
"@types/busboy": "1.3.0",
|
||||||
"@types/ejs": "3.1.0",
|
"@types/ejs": "3.1.0",
|
||||||
"@types/http-errors": "1.8.1",
|
"@types/http-errors": "1.8.1",
|
||||||
"@types/jest": "27.4.0",
|
"@types/jest": "27.4.0",
|
||||||
"@types/jsonwebtoken": "8.5.6",
|
"@types/jsonwebtoken": "8.5.7",
|
||||||
"@types/ms": "0.7.31",
|
"@types/ms": "0.7.31",
|
||||||
"@types/node": "17.0.8",
|
"@types/node": "17.0.8",
|
||||||
"@types/nodemailer": "6.4.4",
|
"@types/nodemailer": "6.4.4",
|
||||||
@ -86,12 +87,12 @@
|
|||||||
"jest": "27.4.7",
|
"jest": "27.4.7",
|
||||||
"jest-mock-extended": "2.0.4",
|
"jest-mock-extended": "2.0.4",
|
||||||
"jest-ts-webcompat-resolver": "1.0.0",
|
"jest-ts-webcompat-resolver": "1.0.0",
|
||||||
"lint-staged": "12.1.5",
|
"lint-staged": "12.1.7",
|
||||||
"markdownlint-cli": "0.30.0",
|
"markdownlint-cli": "0.30.0",
|
||||||
"nodemon": "2.0.15",
|
"nodemon": "2.0.15",
|
||||||
"plop": "3.0.5",
|
"plop": "3.0.5",
|
||||||
"prettier": "2.5.1",
|
"prettier": "2.5.1",
|
||||||
"prisma": "3.7.0",
|
"prisma": "3.8.0",
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"semantic-release": "18.0.1",
|
"semantic-release": "18.0.1",
|
||||||
"typescript": "4.5.4"
|
"typescript": "4.5.4"
|
||||||
|
@ -102,7 +102,7 @@ export const postMessageByChannelIdService: FastifyPluginAsync = async (
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
reply.statusCode = 201
|
reply.statusCode = 201
|
||||||
return {
|
const item = {
|
||||||
...message,
|
...message,
|
||||||
member: {
|
member: {
|
||||||
...memberCheck,
|
...memberCheck,
|
||||||
@ -112,6 +112,12 @@ export const postMessageByChannelIdService: FastifyPluginAsync = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await fastify.io.emitToMembers({
|
||||||
|
event: 'messages',
|
||||||
|
guildId: item.member.guildId,
|
||||||
|
payload: { action: 'create', item }
|
||||||
|
})
|
||||||
|
return item
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ export const postMessageUploadsByChannelIdService: FastifyPluginAsync = async (
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
reply.statusCode = 201
|
reply.statusCode = 201
|
||||||
return {
|
const item = {
|
||||||
...message,
|
...message,
|
||||||
member: {
|
member: {
|
||||||
...memberCheck,
|
...memberCheck,
|
||||||
@ -117,6 +117,12 @@ export const postMessageUploadsByChannelIdService: FastifyPluginAsync = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await fastify.io.emitToMembers({
|
||||||
|
event: 'messages',
|
||||||
|
guildId: item.member.guildId,
|
||||||
|
payload: { action: 'create', item }
|
||||||
|
})
|
||||||
|
return item
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,88 @@
|
|||||||
import fastifyPlugin from 'fastify-plugin'
|
import fastifyPlugin from 'fastify-plugin'
|
||||||
import { Server as SocketIoServer, ServerOptions } from 'socket.io'
|
import { Server as SocketIoServer, ServerOptions } from 'socket.io'
|
||||||
|
import { authorize } from '@thream/socketio-jwt'
|
||||||
|
|
||||||
|
import prisma from '../database/prisma.js'
|
||||||
|
import { JWT_ACCESS_SECRET } from '../configurations/index.js'
|
||||||
|
|
||||||
|
interface EmitEventOptions {
|
||||||
|
event: string
|
||||||
|
payload: {
|
||||||
|
action: 'create' | 'delete' | 'update'
|
||||||
|
item: object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EmitToAuthorizedUsersOptions extends EmitEventOptions {
|
||||||
|
/** tests whether the current connected userId is authorized to get the event, if the callback returns true, the server will emit the event to that user */
|
||||||
|
isAuthorizedCallback: (userId: number) => Promise<boolean>
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmitToAuthorizedUsers = (
|
||||||
|
options: EmitToAuthorizedUsersOptions
|
||||||
|
) => Promise<void>
|
||||||
|
|
||||||
|
interface EmitToMembersOptions extends EmitEventOptions {
|
||||||
|
guildId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmitToMembers = (options: EmitToMembersOptions) => Promise<void>
|
||||||
|
|
||||||
|
interface FastifyIo {
|
||||||
|
instance: SocketIoServer
|
||||||
|
emitToAuthorizedUsers: EmitToAuthorizedUsers
|
||||||
|
emitToMembers: EmitToMembers
|
||||||
|
}
|
||||||
|
|
||||||
declare module 'fastify' {
|
declare module 'fastify' {
|
||||||
export interface FastifyInstance {
|
export interface FastifyInstance {
|
||||||
io: SocketIoServer
|
io: FastifyIo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default fastifyPlugin(
|
export default fastifyPlugin(
|
||||||
async (fastify, options: Partial<ServerOptions>) => {
|
async (fastify, options: Partial<ServerOptions>) => {
|
||||||
const socket = new SocketIoServer(fastify.server, options)
|
const instance = new SocketIoServer(fastify.server, options)
|
||||||
fastify.decorate('io', socket)
|
instance.use(
|
||||||
|
authorize({
|
||||||
|
secret: JWT_ACCESS_SECRET
|
||||||
|
})
|
||||||
|
)
|
||||||
|
const emitToAuthorizedUsers: EmitToAuthorizedUsers = async (options) => {
|
||||||
|
const { event, payload, isAuthorizedCallback } = options
|
||||||
|
const clients = await instance.sockets.allSockets()
|
||||||
|
for (const clientId of clients) {
|
||||||
|
const client = instance.sockets.sockets.get(clientId)
|
||||||
|
if (client != null) {
|
||||||
|
const userId = client.decodedToken.id
|
||||||
|
const isAuthorized = await isAuthorizedCallback(userId)
|
||||||
|
if (isAuthorized) {
|
||||||
|
client.emit(event, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const emitToMembers: EmitToMembers = async (options) => {
|
||||||
|
const { event, payload, guildId } = options
|
||||||
|
await emitToAuthorizedUsers({
|
||||||
|
event,
|
||||||
|
payload,
|
||||||
|
isAuthorizedCallback: async (userId) => {
|
||||||
|
const memberCount = await prisma.member.count({
|
||||||
|
where: { userId, guildId }
|
||||||
|
})
|
||||||
|
return memberCount > 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const io: FastifyIo = {
|
||||||
|
instance,
|
||||||
|
emitToAuthorizedUsers,
|
||||||
|
emitToMembers
|
||||||
|
}
|
||||||
|
fastify.decorate('io', io)
|
||||||
fastify.addHook('onClose', async (fastify) => {
|
fastify.addHook('onClose', async (fastify) => {
|
||||||
fastify.io.close()
|
fastify.io.instance.close()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ fastify: '3.x' }
|
{ fastify: '3.x' }
|
||||||
|
Reference in New Issue
Block a user