Skip to content
This repository was archived by the owner on Apr 19, 2024. It is now read-only.

Commit 1f4e5c3

Browse files
author
zill
committed
Merge branch 'release/1.1.9.2'
2 parents d7ff91f + 417a036 commit 1f4e5c3

File tree

10 files changed

+202
-8
lines changed

10 files changed

+202
-8
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,17 @@ v2-xBot is multi panel, serverless (cloudflare worker) bot to order management &
2323

2424
# Get Started
2525
0) Create a cloudflare worker, KV namespace & bind to `db` variable
26-
1) Got to worker `settings`, `variables` section, and add following variables:
26+
1) Go to worker `settings`, `variables` section, and add following variables:
2727
- `adminId` : your Telegram Admin ID (get from [MyIdInfoBot](https://t.me/Myidinfobot)).
2828
- `botToken` : your Telegram bot token.
2929
- `tlgSupport` : your support Telegram username (Remember put `@` at the first).
3030
3) Download [Latest Version](https://github.com/javadib/v2-xbot/releases/latest/download/dist.zip)
3131
4) Extract `dist.zip` and replace whole `index.js` codes with default cloudflare worker code.
3232
4) Open `YOUR_WORKER.worker.dev/check` to check all variables are `✅ OK`.
33+
4) Open `YOUR_WORKER.worker.dev/seed` to save initial data.
34+
5) To enable Auto-Backup, first set values in bot management section, then Go to worker, `Triggers` tab, `Cron Triggers` section, and add cron trigger.
3335
5) Save and deploy worker and send a `GET ` request to `/webhook` path to register webhook of your bot. make sure you see `ok` in response.
36+
3437
#
3538
![1](./docs/images/register-result.png)
3639

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "v2-xbot",
33
"description": "A multi panel, serverless (cloudflare worker) bot to order management & VPN Accounting",
4-
"version": "1.1.9.0",
4+
"version": "1.1.9.2",
55
"author": "javadib",
66
"repository": "https://github.com/javadib/v2-xbot.git",
77
"scripts": {

src/index.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ const Logger = !enableLog || env === 'production' ? console : TlgBot;
3333
// const Logger = TlgBot;
3434

3535

36+
Object.prototype.requiredProps = function (required = []) {
37+
let data = this;
38+
let missingProps = required.filter(p => !data.hasOwnProperty(p));
39+
40+
let error = missingProps.length >= 1 ?
41+
{ok: false, error: {message: "this props is required.", required: missingProps}} : undefined;
42+
43+
return error;
44+
}
45+
46+
3647
Object.prototype.transform = function (text) {
3748
let keys = Object.keys(this);
3849

@@ -65,6 +76,16 @@ Array.prototype.ToTlgButtons = async function ({idKey, textKey}, prevCmd, addBac
6576
}
6677

6778

79+
addEventListener("scheduled", async (event) => {
80+
try {
81+
event.waitUntil(doBackup(event));
82+
} catch (e) {
83+
let text = e?.stack || e?.message || JSON.stringify(e);
84+
return await TlgBot.sendToAdmin(text, [])
85+
}
86+
});
87+
88+
6889
/**
6990
* Wait for requests to the worker
7091
*/
@@ -590,6 +611,27 @@ async function sendInvoice2(message, session, nextCmd) {
590611
], {method: 'editMessageText', messageId: message.message_id})
591612
}
592613

614+
async function doBackup(event, opt = {}) {
615+
// console.log(`doBackup exec: ${new Date().toISOString()}`);
616+
617+
let backup = (await app.getBackupInfo({Logger: TlgBot})) || {};
618+
// await TlgBot.sendToAdmin(`backup: ${JSON.stringify(backup)}`, [])
619+
620+
let requiredProps = backup.requiredProps(["chatId", "serverUrl"]);
621+
if (requiredProps) {
622+
return await TlgBot.sendToAdmin(app.keys.serverBackup.messages.notSet, [])
623+
}
624+
625+
// await TlgBot.sendToAdmin(`backup.url: ${backup.serverUrl}`, []);
626+
627+
let res = await new Hiddify().takeBackup({serverUrl: backup.serverUrl}, {Logger});
628+
let resText = await res.text();
629+
// console.log(`takeBackup res: ${resText}`);
630+
631+
let fileName = `${new URL(backup.serverUrl).hostname}.json`;
632+
return await TlgBot.sendDocument(backup.chatId, new Blob(Array.from(resText)), fileName)
633+
}
634+
593635
async function setExtendAccount(message, order, opt = {}) {
594636
let chatId = message.chat_id || message.chat.id;
595637
let invoiceSess = {

src/models/admin.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module.exports = {
1111
[{text: Command.list.manageServer.textIcon(), callback_data: Command.list.manageServer.id}],
1212
[{text: Command.list.managePayment.textIcon(), callback_data: Command.list.managePayment.id}],
1313
[{text: Command.list.changeWelcome.textIcon(), callback_data: Command.list.changeWelcome.id}],
14+
[{text: Command.list.backupText.textIcon(), callback_data: Command.list.backupText.id}],
1415
]
1516
},
1617

src/models/app.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
11
'use strict';
22

3+
import {BaseModel} from "./base-model";
4+
import {log} from "util";
5+
36
const Config = require('../config');
47

5-
class app {
8+
class app extends BaseModel {
69
_db;
710
dbKey = "app"
811
keys = {
912
seedCaliApp: {id: "seedCaliApp", default: false},
13+
serverBackup: {
14+
id: "serverBackup",
15+
messages: {
16+
notSet: `تنیظمات بکاپ گیری بدرستی انجام نشده.
17+
لطفا در قسمت مدیریت آنها را اعمال کنید یا
18+
برای غیر فعال کردن بکاپ خودکار، در تنظیمات کلودفلر، بخش Cron Triggers را پاک کنید`
19+
}
20+
21+
},
1022
}
1123

1224
constructor(db) {
25+
super();
26+
1327
this._db = db;
1428
}
1529

@@ -43,6 +57,19 @@ class app {
4357
async saveCustomWelcome({db, input, message, usrSession, isAdmin}) {
4458
await this._db.update(this.dbKey, {[this.customWelcome]: input})
4559
}
60+
61+
async getBackupInfo(options = {}) {
62+
let app = JSON.parse(await this._db.get(this.dbKey)) || {};
63+
let data = app[this.keys.serverBackup.id] || {};
64+
65+
return data;
66+
}
67+
68+
async setBackupInfo({db, input, message, usrSession, isAdmin}) {
69+
let data = await this.parseInput(input);
70+
71+
await this._db.update(this.dbKey, {[this.keys.serverBackup.id]: data})
72+
}
4673
}
4774

4875
module.exports = app;

src/models/base-model.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"use strict";
2+
3+
export class BaseModel {
4+
constructor() {
5+
}
6+
7+
toInput(obj, options = {}) {
8+
let {separator = ':'} = options;
9+
return Object.keys(obj).reduce((pv, cv, i) => {
10+
pv += `${cv} ${separator} ${obj[cv]}\n`;
11+
12+
return pv;
13+
}, '')
14+
}
15+
16+
async parseInput(input, options = {}) {
17+
let {separator = ':'} = options;
18+
19+
let result = input.split('\n').reduce((pv, cv, i) => {
20+
let split = cv.split(separator);
21+
22+
if (split.length < 2) return pv;
23+
24+
pv[split[0].trim()] = split.slice(1).join(separator).trim();
25+
26+
return pv;
27+
}, {})
28+
29+
return result;
30+
}
31+
}

src/models/command.js

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,54 @@ const Cmd = {
217217
"buttons": ["manage"]
218218
},
219219

220+
"backupText": {
221+
"prevId": "manage",
222+
"id": "backupText",
223+
"title": "تنظیمات بکاپ",
224+
"icon": `🚨`,
225+
textIcon() {
226+
return `${this.icon} ${this.title}`
227+
},
228+
229+
"asButton": true,
230+
"body": `🚨
231+
232+
برای تهیه بکاپ، طبق الگوی زیر مشخصات سرور رو ثبت کنید:
233+
serverUrl: ${"آدرس سرور".replaceAll(" ", "_")}
234+
chatId: ${"آیدی کانال/گروه/شخص".replaceAll(" ", "_")}
235+
`,
236+
"successText": ``,
237+
"helpText": `
238+
توجه کنید فقط مقدار بعد از : رو تغییر بدید`,
239+
"preFunc": "",
240+
"nextId": "setBackupInfo",
241+
"savedInSession": true,
242+
"buttons": []
243+
},
244+
"setBackupInfo": {
245+
"prevId": "manage",
246+
"id": "setBackupInfo",
247+
// "title": "ساخت پلن جدید",
248+
// "icon": `📦 ➕`,
249+
// textIcon() {
250+
// return `${this.icon} ${this.title}`
251+
// },
252+
"asButton": false,
253+
"body": `✅ تنظیمات بکاپ با موفقیت ثبت شد.`,
254+
"successText": ``,
255+
"helpText": ``,
256+
"preFunc": "app;setBackupInfo",
257+
preFuncData() {
258+
let [model, func] = this.preFunc.split(';');
259+
260+
return {model, func}
261+
},
262+
"nextId": "",
263+
"savedInSession": true,
264+
"resultInNew": true,
265+
"buttons": ["manage"]
266+
},
267+
220268

221269

222270
"manage": {
@@ -235,7 +283,7 @@ const Cmd = {
235283
"helpText": ``,
236284
"preFunc": '',
237285
"nextId": "",
238-
"buttons": ["managePlan", "manageServer", "managePayment", "manageClientApp", "changeWelcome"]
286+
"buttons": ["managePlan", "manageServer", "managePayment", "manageClientApp", "changeWelcome", "backupText"]
239287
},
240288
"managePlan": {
241289
"prevId": "manage",

src/modules/hiddify.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use strict";
22

3-
const { v4: uuidv4 } = require('uuid');
3+
const {v4: uuidv4} = require('uuid');
44

55

66
const wFetch = require("./wfetch");
@@ -28,8 +28,11 @@ module.exports = class Hiddify {
2828
return new wFetch().request(url, 'POST', raw, {"Content-Type": "application/json"});
2929
}
3030

31-
async extendAccount(messasage, order, plan, server, uid, options = {}) {
32-
let data = {
31+
async extendAccount(message, order, plan, server, uid, options = {}) {
32+
let url = new URL(`/hiddify/extend`, this.baseUrl);
33+
34+
//TODO: fixme
35+
let data = {
3336
"baseUrl": server.url,
3437
"uuid": uuidv4(),
3538
"name": order.accountName,
@@ -51,4 +54,15 @@ module.exports = class Hiddify {
5154

5255
return new wFetch().request(url, 'POST', data, {"Content-Type": "application/json"});
5356
}
57+
58+
async takeBackup(data, options = {}) {
59+
let url = new URL("/hiddify/backup", this.baseUrl);
60+
61+
let raw = {
62+
"baseUrl": data.serverUrl,
63+
}
64+
65+
return new wFetch().request(url, 'POST', raw, {"Content-Type": "application/json"});
66+
}
67+
5468
}

src/modules/telegram.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const Config = require('../config');
55
module.exports = class Telegram {
66
_token;
77

8-
static instance = new Telegram(Config.bot.token);
8+
static instance = new Telegram(Config.bot.token);
99

1010
constructor(token) {
1111
this._token = token;
@@ -42,6 +42,24 @@ module.exports = class Telegram {
4242
}))).json()
4343
}
4444

45+
async sendDocument(chatId, file, fileName, caption, options = {}) {
46+
let formData = new FormData();
47+
formData.append("chat_id", chatId);
48+
formData.append("document", file, fileName);
49+
50+
if (caption) {
51+
formData.append("caption", caption);
52+
}
53+
54+
let requestOptions = {
55+
method: 'POST',
56+
body: formData,
57+
redirect: 'follow'
58+
};
59+
60+
return await fetch(this.apiUrl('sendDocument'), requestOptions)
61+
}
62+
4563
/**
4664
* Send a message with a single button
4765
* `button` must be an button-object like `{ text: 'Button', callback_data: 'data'}`

wrangler-sample.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name = "v2-xbot"
2+
compatibility_date = "2023-01-01"
3+
node_compat = true
4+
vars = { env = "staging", enableLog = "false", botToken = "YOUR_BOT_TOKEN", adminId = "YOUR_ADMIN_ID", tlgSupport = "@YOUR_SUUPORT_ID" }
5+
kv_namespaces = [
6+
{ binding = "db", id = "YOUR_KV_ID" },
7+
]
8+
[triggers]
9+
crons = ["0 */1 * * *"] # Auto-Backup cron job
10+

0 commit comments

Comments
 (0)