refactor: switch server from axios to fetch api

This commit is contained in:
gauthier-th
2024-06-26 16:35:46 +02:00
committed by Gauthier
parent 27cd125532
commit 0f6ba544f8
10 changed files with 163 additions and 107 deletions

View File

@@ -1,4 +1,3 @@
// import rateLimit from 'axios-rate-limit';
import rateLimit from '@server/utils/rateLimit';
import type NodeCache from 'node-cache';

View File

@@ -1,6 +1,5 @@
import logger from '@server/logger';
import axios from 'axios';
import rateLimit, { type rateLimitOptions } from 'axios-rate-limit';
import rateLimit from '@server/utils/rateLimit';
import { createHash } from 'crypto';
import { promises } from 'fs';
import path, { join } from 'path';
@@ -98,26 +97,30 @@ class ImageProxy {
return files.length;
}
private axios;
private fetch: typeof fetch;
private cacheVersion;
private key;
private baseUrl;
constructor(
key: string,
baseUrl: string,
options: {
cacheVersion?: number;
rateLimitOptions?: rateLimitOptions;
rateLimitOptions?: {
maxRPS: number;
maxRequests: number;
};
} = {}
) {
this.cacheVersion = options.cacheVersion ?? 1;
this.baseUrl = baseUrl;
this.key = key;
this.axios = axios.create({
baseURL: baseUrl,
});
if (options.rateLimitOptions) {
this.axios = rateLimit(this.axios, options.rateLimitOptions);
this.fetch = rateLimit(this.fetch, options.rateLimitOptions);
} else {
this.fetch = fetch;
}
}
@@ -182,17 +185,20 @@ class ImageProxy {
): Promise<ImageResponse | null> {
try {
const directory = join(this.getCacheDirectory(), cacheKey);
const response = await this.axios.get(path, {
responseType: 'arraybuffer',
});
const href =
this.baseUrl +
(this.baseUrl.endsWith('/') ? '' : '/') +
(path.startsWith('/') ? path.slice(1) : path);
const response = await this.fetch(href);
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const buffer = Buffer.from(response.data, 'binary');
const extension = path.split('.').pop() ?? '';
const maxAge = Number(
(response.headers['cache-control'] ?? '0').split('=')[1]
(response.headers.get('cache-control') ?? '0').split('=')[1]
);
const expireAt = Date.now() + maxAge * 1000;
const etag = (response.headers.etag ?? '').replace(/"/g, '');
const etag = (response.headers.get('etag') ?? '').replace(/"/g, '');
await this.writeToCacheDir(
directory,

View File

@@ -4,7 +4,6 @@ import { User } from '@server/entity/User';
import type { NotificationAgentDiscord } from '@server/lib/settings';
import { getSettings, NotificationAgentKey } from '@server/lib/settings';
import logger from '@server/logger';
import axios from 'axios';
import {
hasNotificationType,
Notification,
@@ -292,14 +291,20 @@ class DiscordAgent
}
}
await axios.post(settings.options.webhookUrl, {
username: settings.options.botUsername
? settings.options.botUsername
: getSettings().main.applicationTitle,
avatar_url: settings.options.botAvatarUrl,
embeds: [this.buildEmbed(type, payload)],
content: userMentions.join(' '),
} as DiscordWebhookPayload);
await fetch(settings.options.webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: settings.options.botUsername
? settings.options.botUsername
: getSettings().main.applicationTitle,
avatar_url: settings.options.botAvatarUrl,
embeds: [this.buildEmbed(type, payload)],
content: userMentions.join(' '),
} as DiscordWebhookPayload),
});
return true;
} catch (e) {

View File

@@ -2,7 +2,6 @@ import { IssueStatus, IssueTypeName } from '@server/constants/issue';
import type { NotificationAgentGotify } from '@server/lib/settings';
import { getSettings } from '@server/lib/settings';
import logger from '@server/logger';
import axios from 'axios';
import { hasNotificationType, Notification } from '..';
import type { NotificationAgent, NotificationPayload } from './agent';
import { BaseAgent } from './agent';
@@ -133,7 +132,13 @@ class GotifyAgent
const endpoint = `${settings.options.url}/message?token=${settings.options.token}`;
const notificationPayload = this.getNotificationPayload(type, payload);
await axios.post(endpoint, notificationPayload);
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(notificationPayload),
});
return true;
} catch (e) {

View File

@@ -3,7 +3,6 @@ import { MediaStatus } from '@server/constants/media';
import type { NotificationAgentLunaSea } from '@server/lib/settings';
import { getSettings } from '@server/lib/settings';
import logger from '@server/logger';
import axios from 'axios';
import { hasNotificationType, Notification } from '..';
import type { NotificationAgent, NotificationPayload } from './agent';
import { BaseAgent } from './agent';
@@ -101,19 +100,20 @@ class LunaSeaAgent
});
try {
await axios.post(
settings.options.webhookUrl,
this.buildPayload(type, payload),
settings.options.profileName
await fetch(settings.options.webhookUrl, {
method: 'POST',
headers: settings.options.profileName
? {
headers: {
Authorization: `Basic ${Buffer.from(
`${settings.options.profileName}:`
).toString('base64')}`,
},
'Content-Type': 'application/json',
}
: undefined
);
: {
'Content-Type': 'application/json',
Authorization: `Basic ${Buffer.from(
`${settings.options.profileName}:`
).toString('base64')}`,
},
body: JSON.stringify(this.buildPayload(type, payload)),
});
return true;
} catch (e) {

View File

@@ -5,7 +5,6 @@ import { User } from '@server/entity/User';
import type { NotificationAgentPushbullet } from '@server/lib/settings';
import { getSettings, NotificationAgentKey } from '@server/lib/settings';
import logger from '@server/logger';
import axios from 'axios';
import {
hasNotificationType,
Notification,
@@ -123,15 +122,17 @@ class PushbulletAgent
});
try {
await axios.post(
endpoint,
{ ...notificationPayload, channel_tag: settings.options.channelTag },
{
headers: {
'Access-Token': settings.options.accessToken,
},
}
);
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Token': settings.options.accessToken,
},
body: JSON.stringify({
...notificationPayload,
channel_tag: settings.options.channelTag,
}),
});
} catch (e) {
logger.error('Error sending Pushbullet notification', {
label: 'Notifications',
@@ -163,10 +164,13 @@ class PushbulletAgent
});
try {
await axios.post(endpoint, notificationPayload, {
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Token': payload.notifyUser.settings.pushbulletAccessToken,
},
body: JSON.stringify(notificationPayload),
});
} catch (e) {
logger.error('Error sending Pushbullet notification', {
@@ -211,10 +215,13 @@ class PushbulletAgent
});
try {
await axios.post(endpoint, notificationPayload, {
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Token': user.settings.pushbulletAccessToken,
},
body: JSON.stringify(notificationPayload),
});
} catch (e) {
logger.error('Error sending Pushbullet notification', {

View File

@@ -5,7 +5,6 @@ import { User } from '@server/entity/User';
import type { NotificationAgentPushover } from '@server/lib/settings';
import { getSettings, NotificationAgentKey } from '@server/lib/settings';
import logger from '@server/logger';
import axios from 'axios';
import {
hasNotificationType,
Notification,
@@ -52,12 +51,12 @@ class PushoverAgent
imageUrl: string
): Promise<Partial<PushoverImagePayload>> {
try {
const response = await axios.get(imageUrl, {
responseType: 'arraybuffer',
});
const base64 = Buffer.from(response.data, 'binary').toString('base64');
const response = await fetch(imageUrl);
const arrayBuffer = await response.arrayBuffer();
const base64 = Buffer.from(arrayBuffer).toString('base64');
const contentType = (
response.headers['Content-Type'] || response.headers['content-type']
response.headers.get('Content-Type') ||
response.headers.get('content-type')
)?.toString();
return {
@@ -201,12 +200,18 @@ class PushoverAgent
});
try {
await axios.post(endpoint, {
...notificationPayload,
token: settings.options.accessToken,
user: settings.options.userToken,
sound: settings.options.sound,
} as PushoverPayload);
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...notificationPayload,
token: settings.options.accessToken,
user: settings.options.userToken,
sound: settings.options.sound,
} as PushoverPayload),
});
} catch (e) {
logger.error('Error sending Pushover notification', {
label: 'Notifications',
@@ -241,12 +246,18 @@ class PushoverAgent
});
try {
await axios.post(endpoint, {
...notificationPayload,
token: payload.notifyUser.settings.pushoverApplicationToken,
user: payload.notifyUser.settings.pushoverUserKey,
sound: payload.notifyUser.settings.pushoverSound,
} as PushoverPayload);
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...notificationPayload,
token: payload.notifyUser.settings.pushoverApplicationToken,
user: payload.notifyUser.settings.pushoverUserKey,
sound: payload.notifyUser.settings.pushoverSound,
} as PushoverPayload),
});
} catch (e) {
logger.error('Error sending Pushover notification', {
label: 'Notifications',
@@ -291,11 +302,17 @@ class PushoverAgent
});
try {
await axios.post(endpoint, {
...notificationPayload,
token: user.settings.pushoverApplicationToken,
user: user.settings.pushoverUserKey,
} as PushoverPayload);
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...notificationPayload,
token: user.settings.pushoverApplicationToken,
user: user.settings.pushoverUserKey,
} as PushoverPayload),
});
} catch (e) {
logger.error('Error sending Pushover notification', {
label: 'Notifications',

View File

@@ -2,7 +2,6 @@ import { IssueStatus, IssueTypeName } from '@server/constants/issue';
import type { NotificationAgentSlack } from '@server/lib/settings';
import { getSettings } from '@server/lib/settings';
import logger from '@server/logger';
import axios from 'axios';
import { hasNotificationType, Notification } from '..';
import type { NotificationAgent, NotificationPayload } from './agent';
import { BaseAgent } from './agent';
@@ -238,10 +237,13 @@ class SlackAgent
subject: payload.subject,
});
try {
await axios.post(
settings.options.webhookUrl,
this.buildEmbed(type, payload)
);
await fetch(settings.options.webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(this.buildEmbed(type, payload)),
});
return true;
} catch (e) {

View File

@@ -5,7 +5,6 @@ import { User } from '@server/entity/User';
import type { NotificationAgentTelegram } from '@server/lib/settings';
import { getSettings, NotificationAgentKey } from '@server/lib/settings';
import logger from '@server/logger';
import axios from 'axios';
import {
hasNotificationType,
Notification,
@@ -175,11 +174,17 @@ class TelegramAgent
});
try {
await axios.post(endpoint, {
...notificationPayload,
chat_id: settings.options.chatId,
disable_notification: !!settings.options.sendSilently,
} as TelegramMessagePayload | TelegramPhotoPayload);
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...notificationPayload,
chat_id: settings.options.chatId,
disable_notification: !!settings.options.sendSilently,
} as TelegramMessagePayload | TelegramPhotoPayload),
});
} catch (e) {
logger.error('Error sending Telegram notification', {
label: 'Notifications',
@@ -210,12 +215,18 @@ class TelegramAgent
});
try {
await axios.post(endpoint, {
...notificationPayload,
chat_id: payload.notifyUser.settings.telegramChatId,
disable_notification:
!!payload.notifyUser.settings.telegramSendSilently,
} as TelegramMessagePayload | TelegramPhotoPayload);
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...notificationPayload,
chat_id: payload.notifyUser.settings.telegramChatId,
disable_notification:
!!payload.notifyUser.settings.telegramSendSilently,
} as TelegramMessagePayload | TelegramPhotoPayload),
});
} catch (e) {
logger.error('Error sending Telegram notification', {
label: 'Notifications',
@@ -257,11 +268,17 @@ class TelegramAgent
});
try {
await axios.post(endpoint, {
...notificationPayload,
chat_id: user.settings.telegramChatId,
disable_notification: !!user.settings?.telegramSendSilently,
} as TelegramMessagePayload | TelegramPhotoPayload);
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...notificationPayload,
chat_id: user.settings.telegramChatId,
disable_notification: !!user.settings?.telegramSendSilently,
} as TelegramMessagePayload | TelegramPhotoPayload),
});
} catch (e) {
logger.error('Error sending Telegram notification', {
label: 'Notifications',

View File

@@ -3,7 +3,6 @@ import { MediaStatus } from '@server/constants/media';
import type { NotificationAgentWebhook } from '@server/lib/settings';
import { getSettings } from '@server/lib/settings';
import logger from '@server/logger';
import axios from 'axios';
import { get } from 'lodash';
import { hasNotificationType, Notification } from '..';
import type { NotificationAgent, NotificationPayload } from './agent';
@@ -178,17 +177,16 @@ class WebhookAgent
});
try {
await axios.post(
settings.options.webhookUrl,
this.buildPayload(type, payload),
settings.options.authHeader
? {
headers: {
Authorization: settings.options.authHeader,
},
}
: undefined
);
await fetch(settings.options.webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(settings.options.authHeader
? { Authorization: settings.options.authHeader }
: {}),
},
body: JSON.stringify(this.buildPayload(type, payload)),
});
return true;
} catch (e) {