-
Notifications
You must be signed in to change notification settings - Fork 0
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
fix: use webhooks for discord notification #84
Merged
Merged
Changes from 6 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
6c704b2
fix: changed bot token to webhook
0xGorilla 537ef50
fix: added discord notifier
0xGorilla 8807e3f
fix: uncommented index
0xGorilla b1757bd
style: lint
0xGorilla 139da81
Merge remote-tracking branch 'origin/dev' into fix/discord-webhook
jahabeebs 27c1f7d
feat: better notification logic
jahabeebs f6ceff2
fix: pr comments
jahabeebs 84c0df8
fix: as unknown
jahabeebs 85fb6cf
fix: excess messages
jahabeebs 1aed46b
chore: docs
jahabeebs b467c85
fix: stringify
jahabeebs 1b1aab9
fix: this.actor and tests
jahabeebs e281b9e
fix: pr comments
jahabeebs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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 |
---|---|---|
@@ -1,7 +1,7 @@ | ||
import { z } from "zod"; | ||
|
||
const ConfigSchema = z.object({ | ||
DISCORD_WEBHOOK: z.string().min(1), | ||
DISCORD_WEBHOOK: z.string().url().optional(), | ||
}); | ||
|
||
export const config = ConfigSchema.parse(process.env); |
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
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 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,5 +1,6 @@ | ||||||||||||||
import { isNativeError } from "util/types"; | ||||||||||||||
import type { APIEmbed, JSONEncodable } from "discord.js"; | ||||||||||||||
import { Logger, stringify } from "@ebo-agent/shared"; | ||||||||||||||
import { WebhookClient, WebhookMessageCreateOptions } from "discord.js"; | ||||||||||||||
|
||||||||||||||
import { NotificationFailureException } from "../exceptions/index.js"; | ||||||||||||||
|
@@ -14,18 +15,23 @@ export type WebhookMessage = WebhookMessageCreateOptions & { | |||||||||||||
*/ | ||||||||||||||
export class DiscordNotifier implements NotificationService { | ||||||||||||||
private client: WebhookClient; | ||||||||||||||
private defaultAvatarUrl?: string; | ||||||||||||||
private logger: Logger; | ||||||||||||||
|
||||||||||||||
/** | ||||||||||||||
* Creates an instance of DiscordNotifier. | ||||||||||||||
* | ||||||||||||||
* @param {string} url - The Discord webhook URL. | ||||||||||||||
* @param {string} [defaultAvatarUrl] - The default avatar URL to use if none is provided. | ||||||||||||||
*/ | ||||||||||||||
constructor(url: string) { | ||||||||||||||
constructor(url: string, defaultAvatarUrl?: string) { | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's inject
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ |
||||||||||||||
this.client = new WebhookClient({ url }); | ||||||||||||||
this.defaultAvatarUrl = defaultAvatarUrl; | ||||||||||||||
this.logger = Logger.getInstance(); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/** | ||||||||||||||
* Sends a notification message to Discord. | ||||||||||||||
* Sends a notification message to Discord. Errors are logged but not thrown. | ||||||||||||||
* | ||||||||||||||
* @param {IMessage} message - The message to send. | ||||||||||||||
* @returns {Promise<void>} A promise that resolves when the message is sent. | ||||||||||||||
|
@@ -34,7 +40,26 @@ export class DiscordNotifier implements NotificationService { | |||||||||||||
const webhookMessage = this.buildWebhookMessage(message); | ||||||||||||||
try { | ||||||||||||||
await this.client.send(webhookMessage); | ||||||||||||||
console.error(this.client, this.client); | ||||||||||||||
} catch (error) { | ||||||||||||||
this.logger.error( | ||||||||||||||
`Failed to send Discord notification: ${ | ||||||||||||||
error instanceof Error ? error.message : String(error) | ||||||||||||||
}`, | ||||||||||||||
); | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/** | ||||||||||||||
* Sends a notification message to Discord. Throws an exception if sending fails. | ||||||||||||||
* | ||||||||||||||
* @param {IMessage} message - The message to send. | ||||||||||||||
* @returns {Promise<void>} A promise that resolves when the message is sent. | ||||||||||||||
* @throws {NotificationFailureException} If sending the message fails. | ||||||||||||||
*/ | ||||||||||||||
async sendOrThrow(message: IMessage): Promise<void> { | ||||||||||||||
const webhookMessage = this.buildWebhookMessage(message); | ||||||||||||||
try { | ||||||||||||||
await this.client.send(webhookMessage); | ||||||||||||||
} catch (error) { | ||||||||||||||
throw new NotificationFailureException("An error occurred with the Discord client."); | ||||||||||||||
} | ||||||||||||||
|
@@ -50,7 +75,7 @@ export class DiscordNotifier implements NotificationService { | |||||||||||||
return { | ||||||||||||||
username: message.username || "EBO Agent", | ||||||||||||||
content: message.title, | ||||||||||||||
avatarURL: message.avatarUrl || "https://cryptologos.cc/logos/the-graph-grt-logo.png", | ||||||||||||||
avatarURL: message.avatarUrl || this.defaultAvatarUrl, | ||||||||||||||
embeds: | ||||||||||||||
message.subtitle || message.description | ||||||||||||||
? [this.buildWebhookMessageEmbed(message)] | ||||||||||||||
|
@@ -76,42 +101,50 @@ export class DiscordNotifier implements NotificationService { | |||||||||||||
/** | ||||||||||||||
* Creates an IMessage from an error. | ||||||||||||||
* | ||||||||||||||
* @param err - The error object of type unknown. | ||||||||||||||
* @param context - Additional context for the error. | ||||||||||||||
* @param defaultMessage - A default message describing the error context. | ||||||||||||||
* @returns An IMessage object ready to be sent via the notifier. | ||||||||||||||
* @param {string} defaultMessage - A default message describing the error context. | ||||||||||||||
* @param {unknown} [context={}] - Additional context for the error. | ||||||||||||||
* @param {unknown} [err] - The error object. | ||||||||||||||
* @returns {IMessage} An IMessage object ready to be sent via the notifier. | ||||||||||||||
*/ | ||||||||||||||
public createErrorMessage( | ||||||||||||||
err: unknown, | ||||||||||||||
context: Record<string, unknown>, | ||||||||||||||
defaultMessage: string, | ||||||||||||||
context: unknown = {}, | ||||||||||||||
err?: unknown, | ||||||||||||||
): IMessage { | ||||||||||||||
const contextObject = typeof context === "object" && context !== null ? context : {}; | ||||||||||||||
if (isNativeError(err)) { | ||||||||||||||
return { | ||||||||||||||
title: `**Error:** ${err.name} - ${err.message}`, | ||||||||||||||
description: `**Context:**\n\`\`\`json\n${JSON.stringify( | ||||||||||||||
{ | ||||||||||||||
message: defaultMessage, | ||||||||||||||
stack: err.stack, | ||||||||||||||
...context, | ||||||||||||||
}, | ||||||||||||||
null, | ||||||||||||||
2, | ||||||||||||||
)}\n\`\`\``, | ||||||||||||||
description: `**Context:**\n\`\`\`json\n${stringify({ | ||||||||||||||
...contextObject, | ||||||||||||||
stack: err.stack, | ||||||||||||||
})}\n\`\`\``, | ||||||||||||||
}; | ||||||||||||||
} else { | ||||||||||||||
return { | ||||||||||||||
title: `**Error:** Unknown error`, | ||||||||||||||
description: `**Context:**\n\`\`\`json\n${JSON.stringify( | ||||||||||||||
{ | ||||||||||||||
message: defaultMessage, | ||||||||||||||
error: String(err), | ||||||||||||||
...context, | ||||||||||||||
}, | ||||||||||||||
null, | ||||||||||||||
2, | ||||||||||||||
)}\n\`\`\``, | ||||||||||||||
title: `**Error:** ${defaultMessage}`, | ||||||||||||||
description: `**Context:**\n\`\`\`json\n${stringify({ | ||||||||||||||
...contextObject, | ||||||||||||||
error: err ? stringify(err) : undefined, | ||||||||||||||
})}\n\`\`\``, | ||||||||||||||
}; | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/** | ||||||||||||||
* Sends an error notification message to Discord. | ||||||||||||||
* | ||||||||||||||
* @param {string} defaultMessage - A default message describing the error context. | ||||||||||||||
* @param {Record<string, unknown>} [context={}] - Additional context for the error. | ||||||||||||||
* @param {unknown} [err] - The error object. | ||||||||||||||
* @returns {Promise<void>} A promise that resolves when the message is sent. | ||||||||||||||
*/ | ||||||||||||||
public async sendError( | ||||||||||||||
defaultMessage: string, | ||||||||||||||
context: Record<string, unknown> = {}, | ||||||||||||||
err?: unknown, | ||||||||||||||
): Promise<void> { | ||||||||||||||
const errorMessage = this.createErrorMessage(defaultMessage, context, err); | ||||||||||||||
await this.send(errorMessage); | ||||||||||||||
} | ||||||||||||||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could add some link referring to Discord docs on how to create your Webhook
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅