diff --git a/Dockerfile b/Dockerfile
index 9668844..2df236d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,6 +8,9 @@ COPY . .
RUN apk add --update --no-cache python3 g++ make py3-pip
+# Push client(only support pure text message)
+RUN pip install apprise
+
RUN pnpm install --frozen-lockfile
RUN pnpm build
diff --git a/package.json b/package.json
index f0fce15..8e16308 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
"detect-browser": "^5.3.0",
"dotenv": "^16.3.1",
"eventemitter-strict": "^1.0.1",
+ "execa": "^5.1.1",
"express": "^4.18.2",
"express-async-errors": "^3.1.1",
"express-validator": "^7.0.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7414397..eaeb7f4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -82,6 +82,9 @@ dependencies:
eventemitter-strict:
specifier: ^1.0.1
version: 1.0.1
+ execa:
+ specifier: ^5.1.1
+ version: 5.1.1
express:
specifier: ^4.18.2
version: 4.18.2
@@ -5183,7 +5186,6 @@ packages:
onetime: 5.1.2
signal-exit: 3.0.7
strip-final-newline: 2.0.0
- dev: true
/execa@7.2.0:
resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==}
@@ -5983,7 +5985,6 @@ packages:
/human-signals@2.1.0:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
- dev: true
/human-signals@4.3.1:
resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
@@ -6911,7 +6912,6 @@ packages:
/merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
- dev: true
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
@@ -6961,7 +6961,6 @@ packages:
/mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
- dev: true
/mimic-fn@4.0.0:
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
@@ -7346,7 +7345,6 @@ packages:
engines: {node: '>=8'}
dependencies:
path-key: 3.1.1
- dev: true
/npm-run-path@5.2.0:
resolution: {integrity: sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==}
@@ -7423,7 +7421,6 @@ packages:
engines: {node: '>=6'}
dependencies:
mimic-fn: 2.1.0
- dev: true
/onetime@6.0.0:
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
@@ -9484,7 +9481,6 @@ packages:
/signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
- dev: true
/signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
@@ -9839,7 +9835,6 @@ packages:
/strip-final-newline@2.0.0:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
- dev: true
/strip-final-newline@3.0.0:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
diff --git a/src/client/components/modals/NotificationInfo/strategies/apprise.tsx b/src/client/components/modals/NotificationInfo/strategies/apprise.tsx
new file mode 100644
index 0000000..269a8a6
--- /dev/null
+++ b/src/client/components/modals/NotificationInfo/strategies/apprise.tsx
@@ -0,0 +1,26 @@
+import { Form, Input } from 'antd';
+import React from 'react';
+
+export const NotificationApprise: React.FC = React.memo(() => {
+ return (
+ <>
+
+
+
+
+ >
+ );
+});
+NotificationApprise.displayName = 'NotificationApprise';
diff --git a/src/client/components/modals/NotificationInfo/strategies/index.ts b/src/client/components/modals/NotificationInfo/strategies/index.ts
index 916de13..91300de 100644
--- a/src/client/components/modals/NotificationInfo/strategies/index.ts
+++ b/src/client/components/modals/NotificationInfo/strategies/index.ts
@@ -1,6 +1,7 @@
import React from 'react';
import { NotificationSMTP } from './smtp';
import { NotificationTelegram } from './telegram';
+import { NotificationApprise } from './apprise';
interface NotificationStrategy {
label: string;
@@ -14,6 +15,11 @@ export const notificationStrategies: NotificationStrategy[] = [
name: 'smtp',
form: NotificationSMTP,
},
+ {
+ label: 'Apprise(Support 90+ services)',
+ name: 'apprise',
+ form: NotificationApprise,
+ },
{
label: 'Telegram',
name: 'telegram',
diff --git a/src/server/main.ts b/src/server/main.ts
index 31775b4..494605e 100644
--- a/src/server/main.ts
+++ b/src/server/main.ts
@@ -19,7 +19,6 @@ import { initUdpServer } from './udp/server';
import { createServer } from 'http';
import { initSocketio } from './ws';
import { monitorManager } from './model/monitor';
-import { settings } from './utils/settings';
import { env } from './utils/env';
import cors from 'cors';
import { serverStatusRouter } from './router/serverStatus';
@@ -28,7 +27,7 @@ import { logger } from './utils/logger';
import { monitorRouter } from './router/monitor';
import { healthRouter } from './router/health';
-const port = settings.port;
+const port = env.port;
const app = express();
const httpServer = createServer(app);
diff --git a/src/server/model/monitor/provider/__tests__/openai.spec.ts b/src/server/model/monitor/provider/__tests__/openai.spec.ts
index e72e92f..b9f7740 100644
--- a/src/server/model/monitor/provider/__tests__/openai.spec.ts
+++ b/src/server/model/monitor/provider/__tests__/openai.spec.ts
@@ -1,10 +1,10 @@
import { describe, expect, test } from 'vitest';
import { getBillingCreditGrants } from '../openai';
-describe.runIf(!!process.env.OPENAI_SESS_KEY)('openai', () => {
+describe.runIf(!!process.env.TEST_OPENAI_SESS_KEY)('openai', () => {
test('getBillingCreditGrants should be ok', async () => {
const res = await getBillingCreditGrants(
- String(process.env.OPENAI_SESS_KEY)
+ String(process.env.TEST_OPENAI_SESS_KEY)
);
expect(typeof res.allUSD).toBe('number');
diff --git a/src/server/model/notification/provider/__tests__/apprise.spec.ts b/src/server/model/notification/provider/__tests__/apprise.spec.ts
new file mode 100644
index 0000000..b3faea7
--- /dev/null
+++ b/src/server/model/notification/provider/__tests__/apprise.spec.ts
@@ -0,0 +1,17 @@
+import { describe, test } from 'vitest';
+import { apprise } from '../apprise';
+import { token } from '../../token';
+
+describe.runIf(!!process.env.TEST_APPRISE_URL)('apprise', () => {
+ test('apprise should be work', async () => {
+ await apprise.send(
+ {
+ payload: {
+ appriseUrl: process.env.TEST_APPRISE_URL,
+ },
+ } as any,
+ 'test title',
+ [token.text('Foooo'), token.newline(), token.text('Baaaar')]
+ );
+ });
+});
diff --git a/src/server/model/notification/provider/apprise.ts b/src/server/model/notification/provider/apprise.ts
new file mode 100644
index 0000000..187eebd
--- /dev/null
+++ b/src/server/model/notification/provider/apprise.ts
@@ -0,0 +1,34 @@
+import { NotificationProvider } from './type';
+import { baseContentTokenizer } from '../token';
+import execa from 'execa';
+
+interface ApprisePayload {
+ appriseUrl: string;
+}
+
+// Fork from https://github.com/louislam/uptime-kuma/blob/HEAD/server/notification-providers/smtp.js
+export const apprise: NotificationProvider = {
+ send: async (notification, title, message) => {
+ const payload = notification.payload as unknown as ApprisePayload;
+
+ const content = baseContentTokenizer.parse(message);
+
+ const args = ['-vv', '-b', content, payload.appriseUrl];
+ if (title) {
+ args.push('-t');
+ args.push(title);
+ }
+
+ const { stdout } = await execa('apprise', args);
+
+ const output = stdout
+ ? stdout.toString()
+ : 'ERROR: maybe apprise not found';
+
+ if (output) {
+ if (output.includes('ERROR')) {
+ throw new Error(output);
+ }
+ }
+ },
+};
diff --git a/src/server/model/notification/provider/index.ts b/src/server/model/notification/provider/index.ts
index 3e46aeb..08f4793 100644
--- a/src/server/model/notification/provider/index.ts
+++ b/src/server/model/notification/provider/index.ts
@@ -1,8 +1,10 @@
+import { apprise } from './apprise';
import { smtp } from './smtp';
import { telegram } from './telegram';
import type { NotificationProvider } from './type';
export const notificationProviders: Record = {
smtp,
+ apprise,
telegram,
};
diff --git a/src/server/utils/env.ts b/src/server/utils/env.ts
index 4e0007e..e76c33e 100644
--- a/src/server/utils/env.ts
+++ b/src/server/utils/env.ts
@@ -1,4 +1,5 @@
export const env = {
+ port: Number(process.env.PORT || 12345),
allowRegister: checkEnvTrusty(process.env.ALLOW_REGISTER),
allowOpenapi: checkEnvTrusty(process.env.ALLOW_OPENAPI),
websiteId: process.env.WEBSITE_ID,
diff --git a/src/server/utils/settings.ts b/src/server/utils/settings.ts
deleted file mode 100644
index 632d16c..0000000
--- a/src/server/utils/settings.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const settings = {
- port: Number(process.env.PORT || 12345),
-};