Skip to content

Commit d99b6ba

Browse files
committed
fix: Handle error messages in fastify onError and handleError hooks
1 parent 2490b67 commit d99b6ba

File tree

3 files changed

+66
-48
lines changed

3 files changed

+66
-48
lines changed
Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,74 @@
11
import { ENV } from '@env'
2-
import { isHttpError } from '@errors/HttpError.js'
3-
import { DiscordService } from '@lib/discord/DiscordService.js'
4-
import { FastifyPluginCallback } from 'fastify'
2+
import type { FastifyPluginCallback, FastifyRequest } from 'fastify'
53
import { container } from 'tsyringe'
64
import fp from 'fastify-plugin'
5+
import { isHttpError } from '@errors/HttpError.js'
6+
import {
7+
DiscordService,
8+
type MessagePayload,
9+
type MessageType,
10+
} from '@lib/discord/DiscordService.js'
11+
import { DynamicConfigService } from '@services/DynamicConfigService/index.js'
12+
13+
const errorHandlerPlugin: FastifyPluginCallback = fp(async (fastify) => {
14+
const discord = container.resolve(DiscordService)
15+
const dynamicConfig = container.resolve(DynamicConfigService)
716

8-
// TODO: apply fastify-plugin
9-
const errorHandlerPlugin: FastifyPluginCallback = (fastify, _, done) => {
10-
fastify.addHook('preHandler', function (request, reply, done) {
17+
fastify.addHook('preHandler', (request, _, done) => {
1118
if (request.body) {
1219
request.log.info({ body: request.body }, 'parsed body')
1320
}
1421
done()
1522
})
16-
fastify.addHook('onError', (request, reply, error, done) => {
17-
request.log.error(error, 'fastify onError')
18-
const discord = container.resolve(DiscordService)
19-
discord
20-
.sendMessage('error', {
21-
type: 'fastify OnError',
22-
body: request?.body,
23-
query: request?.query,
24-
error,
25-
user: request?.user,
26-
ip: request?.ip,
23+
24+
const sendErrorToDiscord = async (
25+
type: MessageType,
26+
payload: MessagePayload,
27+
request: FastifyRequest,
28+
) => {
29+
const isBlocked = await dynamicConfig.isBlockedUser(request.user?.username)
30+
if (isBlocked) {
31+
fastify.log.info('Blocked user, skipping error message')
32+
return
33+
}
34+
35+
try {
36+
await discord.sendMessage(type, {
37+
...payload,
38+
body: payload.body ?? request.body ?? 'none',
39+
query: payload.query ?? request.query ?? 'none',
40+
user: request.user,
41+
ip: request.ip,
2742
})
28-
.catch(console.error)
29-
done()
43+
} catch (discordError) {
44+
fastify.log.error(discordError, 'Failed to send error message to Discord')
45+
}
46+
}
47+
48+
fastify.addHook('onError', async (request, _, error) => {
49+
request.log.error(error, 'fastify onError')
50+
await sendErrorToDiscord('error', { type: 'fastify OnError', error }, request)
3051
})
31-
fastify.setErrorHandler((error, request, reply) => {
52+
53+
fastify.setErrorHandler(async (error, request, reply) => {
54+
const errorResponse = {
55+
message: error.message || 'Internal Server Error',
56+
name: error.name || 'Error',
57+
stack: ENV.appEnv === 'development' ? error.stack : undefined,
58+
}
59+
3260
if (isHttpError(error)) {
33-
reply.status(error.statusCode).send({
34-
message: error.message,
35-
name: error.name,
36-
stack: ENV.appEnv === 'development' ? error.stack : undefined,
37-
})
61+
reply.status(error.statusCode).send(errorResponse)
3862
} else {
39-
reply.status(500).send({
40-
message: error.message || 'Internal Server Error',
41-
name: error.name || 'Error',
42-
stack: ENV.appEnv === 'development' ? error.stack : undefined,
43-
})
63+
reply.status(500).send(errorResponse)
4464
}
4565

4666
if (ENV.appEnv === 'development') {
4767
request.log.error(error, 'fastify handleError')
4868
} else {
49-
const discord = container.resolve(DiscordService)
50-
discord
51-
.sendMessage('error', {
52-
type: 'fastify handleError',
53-
body: request?.body,
54-
query: request?.query,
55-
error,
56-
user: request?.user,
57-
ip: request?.ip,
58-
})
59-
.catch(console.error)
69+
await sendErrorToDiscord('error', { type: 'fastify handleError', error }, request)
6070
}
6171
})
72+
})
6273

63-
done()
64-
}
65-
66-
export default fp(errorHandlerPlugin)
74+
export default errorHandlerPlugin

apps/server/src/lib/discord/DiscordService.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export class DiscordService {
2020
console.log('Discord Client ready')
2121
resolve(this.client)
2222
})
23-
2423
this.client.login(ENV.discordBotToken)
2524
})
2625
}
@@ -101,8 +100,8 @@ export class DiscordService {
101100
}
102101
}
103102

104-
type MessageType = 'error' | 'spam'
105-
type MessagePayload = {
103+
export type MessageType = 'error' | 'spam'
104+
export type MessagePayload = {
106105
type: string
107106
body?: any
108107
query?: any

apps/server/src/services/DynamicConfigService/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ export class DynamicConfigService implements Service {
1313
const list = await this.readBlockUserList()
1414
return list.includes(username)
1515
}
16+
public async isBlockedUserById(userId: string): Promise<boolean> {
17+
const user = await this.db.user.findUnique({
18+
where: {
19+
id: userId,
20+
},
21+
})
22+
if (!user) {
23+
return false
24+
}
25+
return this.isBlockedUser(user.username)
26+
}
1627
private async readBlockUserList(): Promise<string[]> {
1728
const list = await this.db.dynamicConfigItem.findMany({
1829
where: {

0 commit comments

Comments
 (0)