update readme, and fix auto install sctript.

This commit is contained in:
liaojack8 2020-07-05 13:20:12 +08:00
parent 5f424722f7
commit 85ccba7c72
10 changed files with 60 additions and 266 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

View File

@ -1,129 +0,0 @@
# 几个坑
* Telegram Bot API 提供了两种方式, webhook 和 long polling目前项目只支持 webhook 方式。
* webhook 方式必须要用HTTPS 也就是需要准备**个人域名**和**一个有效证书**
* 证书一定要单独域名证书(泛域名证书不能用)
# 原理/思路
TG创建bot要起一个服务支持BOT的功能 所以需要配置webhook 让tg 和服务器建立连接。webhook 需要有HTTPS的外网域名并且修改DNS指向你所配置的服务器IP这样就能保证TG的请求可以顺利到达并且验证BOT。
在服务器内部如果如果是单BOT 可以直接用nodje 配合 PM2 直接起服务,然后修改server.js端口号443。 如果服务器上有多个服务,那么就需要用反向代理,反代简单说就是一个服务+映射规则 (ngnix或者apache后者其他都可以) 侦听80或者443端口如果有指定的映射请求 就转发到内部映射的各个服务。
例如
```
aaa.domain.com <=> locahost:3001
bbb.domain.com <=> locahost:3002
domain.com/ccc <=> localhost:3003
```
# 步骤
1. 需要去tg 创建一个bot会得到token 和bot的tgurl
2. BOT服务
1. 服务器上clone 项目安装node, npm install
2. 如果需要配置多个BOT, clone不同目录, server.js里修改配置port和config.js
3. 安装PM2在每个bot目录下 PM2 start server.js
4. ``` pm2 status``` 确认服务跑起来了
1. 如果没起来, 查log文件见底部
5. curl 检查本地连接, curl 检查远端连接, not found 就对了
3. 外部连接
1. 修改DNS我是用cloudflare 把添加A record 直接把静态IP 绑定
2. 绑定以后, 本地开个terminal, ping 刚添加域名直到解析的IP是你绑定的这步确保连接上是畅通的
4. apache2开启SSL和反代
1. 复制证书到任意位置
2. 运行底部命令
3. /etc/apache2/sites-available 下找到默认的.conf或者自己建个conf也行
4. 修改底部配置信息
5. 保存重启 ```service apache2 restart```
5. 剩下的就是配置和检查webhook这里面也有不少坑在反代配置文件部分。。记不清了。。
6. 如果一切顺利 /help 会弹出目录
```
pm2 部分
tail -200 ~/.pm2/logs/server-error.log
tail -200 ~/.pm2/logs/server-out.log
curl "localhost:23333"
curl "domain:23333"
SSL+反代
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
/etc/apache2/sites-available/xxx.conf
<VirtualHost *:443>
SSLEngine on
SSLProtocol all
SSLCertificateFile {{CERT_DIR}}/{{domain.cer}}
SSLCertificateKeyFile {{CERT_DIR}}/{{domain.key}}
SSLCACertificateFile {{CERT_DIR}}/{{domain.ca.cer}}
ServerName {{domain}}
ProxyRequests Off
ProxyPreserveHost On
ProxyVia Full
<Proxy *>
Require all granted
</Proxy>
# 这里我用的是子目录映射方式。懒得再申请一个证书。。domain.com/ccc <=> localhost:3003
ProxyPass /{{bot1url}}/ http://127.0.0.1:23334/ # bot1
ProxyPassReverse /{{bot1url}}/ http://127.0.0.1:23334/ # bot1
ProxyPass /{{bot2url}}/ http://127.0.0.1:23333/ # bot2
ProxyPassReverse /{{bot2url}}/ http://127.0.0.1:23333/ # bot2
</VirtualHost>
something for verify and DEBUG
Apache command:
service apache2 restart
service apache2 stop
service apache2 status
service apache2 reload
tail -100 /var/log/apache2/error.log
验证一下SSL:
https://www.ssllabs.com/ssltest/analyze.html 确保Trusted和In trust store是绿的反正我这两个绿的就TG就能找到的到
SET webhook
curl -F "url=https://{{domain}}/{{bot1url}}/api/gdurl/tgbot" 'https://api.telegram.org/bot{{BOT_TOKEN}}/setWebhook'
delete webhook
curl -F "url=" https://api.telegram.org/bot{{BOT_TOKEN}}/setWebhook
check webhook
curl "https://api.telegram.org/bot{{BOT_TOKEN}}/getWebhookInfo"
```
![avatar](/doc/bot-worked.png)
# Reference Link
https://core.telegram.org/bots
https://core.telegram.org/bots/api
https://www.jianshu.com/p/ca804497afa0

View File

@ -139,7 +139,7 @@ echo "server {
server { server {
listen 443 ssl; listen 443 ssl;
ssl on; ssl on;
ssl_certificate /etc/ssl/certificate-all.crt; ssl_certificate /etc/ssl/certificate.crt;
ssl_certificate_key /etc/ssl/private.key; ssl_certificate_key /etc/ssl/private.key;
server_name $YOUR_DOMAIN_NAME; server_name $YOUR_DOMAIN_NAME;
location / { location / {

View File

@ -197,6 +197,15 @@ echo -e "\033[1;32m“nginx”起一个web服务......\033[0m"
cd $nginx_conf cd $nginx_conf
echo "server { echo "server {
listen 80; listen 80;
server_name ecbot.nctu.me;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
ssl on;
ssl_certificate /etc/ssl/certificate.crt;
ssl_certificate_key /etc/ssl/private.key;
server_name $YOUR_DOMAIN_NAME; server_name $YOUR_DOMAIN_NAME;
location / { location / {
proxy_pass http://127.0.0.1:23333/; proxy_pass http://127.0.0.1:23333/;

BIN
pic/example1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
pic/example2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
pic/example3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

153
readme.md
View File

@ -2,15 +2,27 @@
> 不只是最快的 google drive 拷贝工具 [与其他工具的对比](./compare.md) > 不只是最快的 google drive 拷贝工具 [与其他工具的对比](./compare.md)
> 我就懶的翻譯readme了, 大家自己看吧, 主要新增/修改/翻譯tg_bot介面的部分 > 我就只寫我修改過的部分吧 具體說明還是看[這邊](https://github.com/iwestlin/gd-utils)和[這邊](https://github.com/vitaminx/gd-utils)吧
## tg_bot 修改部分
- 執行/task命令時, 會回傳完成度百分比
## 一键安装脚本 ![](./pic/example2.png)
- 安装机器人需准备好以下四个条件: - 貼上分享連結時, 新增更多可用的常用選項, 不用每次都另外輸入dst ID
- 在Telegram上注册好机器人并取得并记录下该机器人TOKEN - 這邊預設三個複製目的地都相同, 皆為`config.js`中的`DEFAULT_TARGET`
- 一个域名在cloudflare解析到该机器人所在VPS的IP - 修改處在[`router.js`](router.js)的Line 68. Line 73, 給target賦值上對應的dst ID就行了
- 向机器人@userinfobot获取个人TG账号ID并记录 ![](./pic/example1.png)
- 注册好一个Google team drive加入sa并记录下该盘ID - 複製完成時, 跳出的通知會顯示文件大小
- 准备好以上四个条件后复制以下全部内容粘贴到VPS命令行窗口回车即可
![](./pic/example3.png)
> 這邊說一下我用的服務及配置(免費配置): always-free gcp Compute Engine + zerossl + 免費的domain
> hosting
>注意我的配置沒有用到cloudflare
## 一鍵安裝腳本
- 這邊的安裝腳本我有稍作修改 與fork過來的原版不一樣
- 不使用cloudflare解析
- ssl另外配置在nginx服務當中(後面會說明證書放置路徑)
- 具體安裝條件、限制請去參考[腳本原作者的專案](https://github.com/vitaminx/gd-utils)
- 這邊放了貼上就能用的命令
- gdutils项目一键部署脚本包括“查询转存”和“TG机器人”两部分 - gdutils项目一键部署脚本包括“查询转存”和“TG机器人”两部分
``` ```
bash -c "$(curl -fsSL https://raw.githubusercontent.com/vitaminx/gd-utils/master/gdutilsinstall.sh)" bash -c "$(curl -fsSL https://raw.githubusercontent.com/vitaminx/gd-utils/master/gdutilsinstall.sh)"
@ -35,76 +47,14 @@
- debian 9/10 - debian 9/10
- ubuntu 16.04/18.04/19.10/20.04 - ubuntu 16.04/18.04/19.10/20.04
## demo ## 搭建步驟
[https://drive.google.com/drive/folders/124pjM5LggSuwI1n40bcD5tQ13wS0M6wg](https://drive.google.com/drive/folders/124pjM5LggSuwI1n40bcD5tQ13wS0M6wg) 1. 啟用一台主機, VPS、私人伺服器都行(私人伺服器如果沒有設定硬撥, 必須去路由器設定端口對應)
2. 確認固定ip, 或是用ddns服務 都行
## 更新日志 3. 使用domain hosting服務解析到動態域名, 或新增A record指定到固定ip
[2020-06-30] 4. 用domain hosting設定好的固定域名, 去申請ssl證書
5. 將證書放到對應路徑 /etc/ssl/certificate.crt 和 /etc/ssl/private.key
- 命令行操作时不换行输出进度信息同时将进度信息输出间隔调整为1秒 6. 設定完成後, 確認主機的端口開放
- 隐藏 timeout exceed 报错信息 7. 執行安裝腳本, 就會自動以nginx起動服務, 特別設定了http轉https的跳轉
## 重要更新2020-06-29
如果你遇到了以下几种问题,请务必阅读此节:
- 任务异常中断
- 命令行日志无限循环输出但进度不变
- 复制完发现丢文件
有不少网友遇到这些问题但是作者一直无法复现直到有tg网友发了张运行日志截图
![](./static/error-log.png)
报错日志的意思是找不到对应的目录ID这种情况会发生在SA没有对应目录的阅读权限的时候。
当进行server side copy时需要向Google的服务器提交要复制的文件ID和复制的位置也就是新创建的目录ID由于在请求时是随机选取的SA所以当选中没有权限的SA时这次拷贝请求没有对应目录的权限就会发生图中的错误。
**所以上述这些问题的源头是sa目录下混杂了没有权限的json文件**
以下是解决办法:
- 在项目目录下,执行 `git pull` 拉取最新代码
- 执行 `./validate-sa.js -h` 查看使用说明
- 选择一个你的sa拥有阅读权限的目录ID执行 `./validate-sa.js 你的目录ID`
程序会读取sa目录下所有json文件依次检查它们是否拥有对 `你的目录ID` 的阅读权限如果最后发现了无效的SA程序会提供选项允许用户将无效的sa json移动到特定目录。
将无效sa文件移动以后如果你使用了pm2启动需要 `pm2 reload server` 重启下进程。
操作示例: [https://drive.google.com/drive/folders/1iiTAzWF_v9fo_IxrrMYiRGQ7QuPrnxHf](https://drive.google.com/drive/folders/1iiTAzWF_v9fo_IxrrMYiRGQ7QuPrnxHf)
## 常见问题
下面是一些网友的踩坑心得,如果你配置的时候也不小心掉进坑里,可以进去找找有没有解决办法:
- [ikarosone 基于宝塔的搭建过程](https://www.ikarosone.top/archives/195.html)
- [@greathappyforest 踩的坑](doc/tgbot-appache2-note.md)
在命令行操作时如果输出 `timeout exceed` 这样的消息是正常情况不会影响最终结果因为程序对每个请求都有7次重试的机制。
如果timeout的消息比较多可以考虑降低并行请求数下文有具体方法。
复制结束后,如果最后输出的消息里有 `未读取完毕的目录ID`只需要在命令行执行上次同样的拷贝命令选continue即可继续。
如果你成功复制完以后统计新的文件夹链接发现文件数比源文件夹少说明Google正在更新数据库请给它一点时间。。一般等半小时再统计数据会比较完整。
如果你使用tg操作时发送拷贝命令以后/task 进度始终未开始(在复制文件数超多的文件夹时常会发生),是正常现象。
这是因为程序正在获取源文件夹的所有文件信息。它的运行机制严格按照以下顺序:
1、获取源文件夹所有文件信息
2、根据源文件夹的目录结构在目标文件夹创建目录
3、所有目录创建完成后开始复制文件
**如果源文件夹的文件数非常多(一百万以上),请一定在命令行进行操作**因为程序运行的时候会把文件信息保存在内存中文件数太多的话容易内存占用太多被nodejs干掉。可以像这样执行命令
```
node --max-old-space-size=4096 count folder-id -S
```
这样进程就能最大占用4G内存了。
## 搭建过程
[https://drive.google.com/drive/folders/1Lu7Cwh9lIJkfqYDIaJrFpzi8Lgdxr4zT](https://drive.google.com/drive/folders/1Lu7Cwh9lIJkfqYDIaJrFpzi8Lgdxr4zT)
需要注意的地方:
- 视频中省略了一个比较重要的步骤就是**从本地上传service account授权文件到 sa 目录下**tg机器人的所有操作都是通过sa授权的所以你们别忘了。。
- 视频中**nginx的配置里server_name就是你的二级域名需要和cloudflare的设置一样**的mybbbottt我分开录的视频所以没做到一致。
- 还有省略的步骤就是注册域名和把域名托管到cloudflare了这一步网上太多资料了甚至也有免费注册一年域名的地方 https://www.freenom.com/ ),具体教程大家搜搜看吧。
## 功能简介 ## 功能简介
本工具目前支持以下功能: 本工具目前支持以下功能:
@ -174,53 +124,6 @@ http_proxy="YOUR_PROXY_URL" && https_proxy=$http_proxy && HTTP_PROXY=$http_proxy
如果想把机器人的使用权限分享给别的用户,只需要改成这样子: `tg_whitelist: ['viegg', '其他人的username']` 如果想把机器人的使用权限分享给别的用户,只需要改成这样子: `tg_whitelist: ['viegg', '其他人的username']`
接下来需要将代码部署到服务器上。
如果你一开始就是在服务器上配置的,可以直接执行`npm i pm2 -g`
如果你之前是在本地操作的,请在服务器上同样重复一遍,配置好相关参数后,执行`npm i pm2 -g`安装进程守护程序pm2
安装好pm2之后执行 `pm2 start server.js`,代码运行后会在服务器上监听`23333`端口。
如果你启动程序后想看运行日志,执行 `pm2 logs`
查看 pm2 守护的进程列表,执行 `pm2 l`
停止运行中的进程,执行 `pm2 stop 对应的进程名称`
**如果你修改了代码中的配置,需要 `pm2 reload server` 才能生效**。
> 如果你不想用nginx可以将`server.js`中的`23333`改成`80`直接监听80端口可能需要root权限
接下来可通过nginx或其他工具起一个web服务示例nginx配置
```
server {
listen 80;
server_name your.server.name;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:23333/;
}
}
```
配置好nginx后可以再套一层cloudflare具体教程请自行搜索。
检查网站是否部署成功可以命令行执行请将YOUR_WEBSITE_URL替换成你的网址
```
curl 'YOUR_WEBSITE_URL/api/gdurl/count?fid=124pjM5LggSuwI1n40bcD5tQ13wS0M6wg'
```
![](./static/count.png)
如果返回了这样的文件统计,说明部署成功了。
最后,在命令行执行(请将[YOUR_WEBSITE]和[YOUR_BOT_TOKEN]分别替换成你自己的网址和bot token
```
curl -F "url=[YOUR_WEBSITE]/api/gdurl/tgbot" 'https://api.telegram.org/bot[YOUR_BOT_TOKEN]/setWebhook'
```
这样,就将你的服务器连接上你的 telegram bot 了试着给bot发送个 `/help`,如果它回复给你使用说明,那就配置成功了。
## 补充说明 ## 补充说明
在`config.js`文件里,还有另外的几个参数: 在`config.js`文件里,还有另外的几个参数:
``` ```

View File

@ -64,8 +64,13 @@ router.post('/api/gdurl/tgbot', async ctx => {
tg_copy({ fid, chat_id }).then(task_id => { tg_copy({ fid, chat_id }).then(task_id => {
task_id && sm({ chat_id, text: `開始複製任務ID: ${task_id} 可輸入 /task ${task_id} 查詢進度` }) task_id && sm({ chat_id, text: `開始複製任務ID: ${task_id} 可輸入 /task ${task_id} 查詢進度` })
}) })
} else if (action === 'disCopy') { } else if (action === 'copy2') {
const target = '11231' //儲存目的地2 const target = ''
tg_copy({ fid, target, chat_id }).then(task_id => {
task_id && sm({ chat_id, text: `開始複製任務ID: ${task_id} 可輸入 /task ${task_id} 查詢進度` })
})
} else if (action === 'copy3') {
const target = ''
tg_copy({ fid, target, chat_id }).then(task_id => { tg_copy({ fid, target, chat_id }).then(task_id => {
task_id && sm({ chat_id, text: `開始複製任務ID: ${task_id} 可輸入 /task ${task_id} 查詢進度` }) task_id && sm({ chat_id, text: `開始複製任務ID: ${task_id} 可輸入 /task ${task_id} 查詢進度` })
}) })
@ -117,7 +122,7 @@ router.post('/api/gdurl/tgbot', async ctx => {
task_id = parseInt(task_id) task_id = parseInt(task_id)
if (!task_id) { if (!task_id) {
const running_tasks = db.prepare('select id from task where status=?').all('copying') const running_tasks = db.prepare('select id from task where status=?').all('copying')
if (!running_tasks.length) return sm({ chat_id, text: '当前暂无运行中的任务' }) if (!running_tasks.length) return sm({ chat_id, text: '目前沒有執行中的任務' })
return running_tasks.forEach(v => send_task_info({ chat_id, task_id: v.id }).catch(console.error)) return running_tasks.forEach(v => send_task_info({ chat_id, task_id: v.id }).catch(console.error))
} }
send_task_info({ task_id, chat_id }).catch(console.error) send_task_info({ task_id, chat_id }).catch(console.error)

View File

@ -50,8 +50,13 @@ function send_choice ({ fid, chat_id }) {
{ text: '文件統計', callback_data: `count ${fid}` } { text: '文件統計', callback_data: `count ${fid}` }
], ],
[ [
{ text: '開始複製(預設)', callback_data: `copy ${fid}` }, { text: '開始複製(預設)', callback_data: `copy ${fid}` }
{ text: '開始複製(discord)', callback_data: `disCopy ${fid}` } ],
[
{ text: '開始複製(1)', callback_data: `copy2 ${fid}` }
],
[
{ text: '開始複製(2)', callback_data: `copy3 ${fid}` }
] ]
] ]
} }
@ -169,6 +174,7 @@ async function tg_copy ({ fid, target, chat_id, update }) { // return task_id
text += '源資料夾:' + gen_link(source, name) + '\n' text += '源資料夾:' + gen_link(source, name) + '\n'
text += '目錄完成數:' + copied_folders + '/' + folder_count + '\n' text += '目錄完成數:' + copied_folders + '/' + folder_count + '\n'
text += '文件完成數:' + copied_files + '/' + file_count + '\n' text += '文件完成數:' + copied_files + '/' + file_count + '\n'
text += '合計大小:' + (total_size || '未知大小') + '\n'
sm({ chat_id, text, parse_mode: 'HTML' }) sm({ chat_id, text, parse_mode: 'HTML' })
}) })
.catch(err => { .catch(err => {