diff --git a/assets/plugin/js/token_handler.js.sample b/assets/plugin/js/token_handler.js.sample new file mode 100644 index 0000000..578c5d9 --- /dev/null +++ b/assets/plugin/js/token_handler.js.sample @@ -0,0 +1,48 @@ +// ========================================================================================== +// aliyunpan JS插件回调处理函数 +// 支持 JavaScript ECMAScript 5.1 语言规范 +// +// 更多内容请查看官方文档:https://github.com/tickstep/aliyunpan +// ========================================================================================== + + +// ------------------------------------------------------------------------------------------ +// 函数说明:用户Token刷新完成后回调函数 +// +// 参数说明 +// context - 当前调用的上下文信息 +// { +// "appName": "aliyunpan", +// "version": "v0.1.3", +// "userId": "11001d48564f43b3bc5662874f04bb11", +// "nickname": "tickstep", +// "fileDriveId": "19519111", +// "albumDriveId": "29519122" +// } +// appName - 应用名称,当前固定为aliyunpan +// version - 版本号 +// userId - 当前登录用户的ID +// nickname - 用户昵称 +// fileDriveId - 用户文件网盘ID +// albumDriveId - 用户相册网盘ID +// +// params - Token刷新参数 +// { +// "result": "success", +// "message": "ok", +// "oldToken": "aa31fcc229c54d5ab6d8bfb17aff3711", +// "newToken": "bb31fcc229c54d5ab6d8bfb17aff3722", +// "updatedAt": "2022-04-14 07:05:12" +// } +// result - Token刷新的结果,success-成功,fail-失败 +// message - 消息说明,如果失败这里会有原因说明 +// oldToken - 刷新前的Token +// newToken - 刷新后的Token,只有result为success的才有该值 +// updatedAt - Token刷新的时间 +// +// 返回值说明 +// (没有返回值) +// ------------------------------------------------------------------------------------------ +function userTokenRefreshFinishCallback(context, params) { + console.log(params) +} diff --git a/docs/manual.md b/docs/manual.md index 61010de..1cf2209 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -51,6 +51,7 @@ + [2.上传文件后删除本地文件](#2.上传文件后删除本地文件) + [3.下载文件并截断过长的文件名](#3.下载文件并截断过长的文件名) + [4.上传文件去掉文件名包含的部分字符](#4.上传文件去掉文件名包含的部分字符) + + [5.Token刷新失败发送外部通知](#5.Token刷新失败发送外部通知) * [显示和修改程序配置项](#显示和修改程序配置项) - [常见问题Q&A](#常见问题Q&A) * [1. 如何获取RefreshToken](#1-如何获取RefreshToken) @@ -1050,9 +1051,10 @@ server { 8.下载的文件路径进行更改,但是网盘的文件保持不变 9.下载文件完成后,通过HTTP通知其他服务 10.同步备份功能,支持过滤本地文件,或者过滤云盘文件。定制上传或者下载需要同步的文件 +11.Token刷新失败或者过期,发送外部通知(HTTP&邮件) ### 如何使用 -JS插件的样本文件默认存放在程序所在的plugin/js文件夹下,分为下载(download_handler.js.sample)、上传(upload_handler.js.sample)、同步备份(sync_handler.js.sample)插件。 +JS插件的样本文件默认存放在程序所在的plugin/js文件夹下,分为下载(download_handler.js.sample)、上传(upload_handler.js.sample)、同步备份(sync_handler.js.sample)、用户Token(token_handler.js.sample)插件。 建议拷贝一份并将后缀名更改为.js,例如:upload_handler.js,不然插件不会生效。 你必须具备一定的JS语言基础,然后按照里面的样例根据自己所需进行改动即可。 @@ -1295,6 +1297,32 @@ function uploadFilePrepareCallback(context, params) { } ``` +#### 5.Token刷新失败发送外部通知 +Token刷新失败发送外部通知,例如Server酱 +```js +function userTokenRefreshFinishCallback(context, params) { + var header = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36", + "Content-Type": "application/json", + "Accept": "application/json" + }; + try { + if (params["result"] === "fail") { + var reqData = { + "text": "Token刷新失败", + "desp": params["message"] + }; + var r = PluginUtil.Http.post(header, "https://sctapi.ftqq.com/xxxxxkeyxxxxxx.send", JSON.stringify(reqData)); + } + } catch (e) { + if (e !== "Error") { + throw e; + } + } +} +``` + + ## 显示和修改程序配置项 ``` # 显示配置 diff --git a/internal/command/token.go b/internal/command/token.go index 0fd649a..365348d 100644 --- a/internal/command/token.go +++ b/internal/command/token.go @@ -18,6 +18,9 @@ import ( "github.com/tickstep/aliyunpan-api/aliyunpan" "github.com/tickstep/aliyunpan/cmder" "github.com/tickstep/aliyunpan/internal/config" + "github.com/tickstep/aliyunpan/internal/plugins" + "github.com/tickstep/aliyunpan/internal/utils" + "github.com/tickstep/library-go/logger" "github.com/urfave/cli" ) @@ -74,25 +77,51 @@ func CmdToken() cli.Command { // RunTokenUpdate 执行Token更新 func RunTokenUpdate(modeFlag string) { cmder.ReloadConfigFunc(nil) + + // 获取当前插件 + pluginManger := plugins.NewPluginManager(config.GetPluginDir()) + plugin, _ := pluginManger.GetPlugin() + params := &plugins.UserTokenRefreshFinishParams{ + Result: "success", + Message: "", + OldToken: "", + NewToken: "", + UpdatedAt: utils.NowTimeStr(), + } + userList := config.Config.UserList if userList == nil || len(userList) == 0 { fmt.Printf("没有登录用户,无需刷新Token\n") return } - for _,user := range userList { + for _, user := range userList { + params.Result = "success" + if modeFlag == "1" { if user.UserId != config.Config.ActiveUID { continue } } - newToken,e := aliyunpan.GetAccessTokenFromRefreshToken(user.RefreshToken) + newToken, e := aliyunpan.GetAccessTokenFromRefreshToken(user.RefreshToken) if e != nil { + params.Result = "fail" + params.Message = e.Error() fmt.Printf("无法为%s用户获取新的RefreshToken,可能需要重新登录\n", user.Nickname) continue } if newToken != nil && newToken.RefreshToken != "" { + params.OldToken = user.RefreshToken + params.NewToken = newToken.RefreshToken + user.RefreshToken = newToken.RefreshToken fmt.Printf("成功刷新%s用户的RefreshToken\n", user.Nickname) + } else { + params.Result = "fail" + } + + // plugin callback + if er := plugin.UserTokenRefreshFinishCallback(plugins.GetContext(user), params); er != nil { + logger.Verbosef("UserTokenRefreshFinishCallback error: " + er.Error()) } } cmder.SaveConfigFunc(nil) diff --git a/internal/plugins/idle_plugin.go b/internal/plugins/idle_plugin.go index d8beb14..111aede 100644 --- a/internal/plugins/idle_plugin.go +++ b/internal/plugins/idle_plugin.go @@ -44,6 +44,10 @@ func (p *IdlePlugin) SyncFileFinishCallback(context *Context, params *SyncFileFi return nil } +func (p *IdlePlugin) UserTokenRefreshFinishCallback(context *Context, params *UserTokenRefreshFinishParams) error { + return nil +} + func (p *IdlePlugin) Stop() error { return nil } diff --git a/internal/plugins/js_plugin.go b/internal/plugins/js_plugin.go index f7490b4..10371a5 100644 --- a/internal/plugins/js_plugin.go +++ b/internal/plugins/js_plugin.go @@ -215,6 +215,24 @@ func (js *JsPlugin) SyncFileFinishCallback(context *Context, params *SyncFileFin return nil } +func (js *JsPlugin) UserTokenRefreshFinishCallback(context *Context, params *UserTokenRefreshFinishParams) error { + var fn func(*Context, *UserTokenRefreshFinishParams) error + if !js.isHandlerFuncExisted("userTokenRefreshFinishCallback") { + return nil + } + err := js.vm.ExportTo(js.vm.Get("userTokenRefreshFinishCallback"), &fn) + if err != nil { + logger.Verboseln("Js函数映射到 Go 函数失败!") + return nil + } + er := fn(context, params) + if er != nil { + logger.Verboseln(er) + return nil + } + return nil +} + func (js *JsPlugin) Stop() error { return nil } diff --git a/internal/plugins/plugin.go b/internal/plugins/plugin.go index ff83da9..3feab34 100644 --- a/internal/plugins/plugin.go +++ b/internal/plugins/plugin.go @@ -135,6 +135,15 @@ type ( FileUpdatedAt string `json:"fileUpdatedAt"` } + // UserTokenRefreshFinishParams 用户Token刷新完成后回调函数 + UserTokenRefreshFinishParams struct { + Result string `json:"result"` + Message string `json:"message"` + OldToken string `json:"oldToken"` + NewToken string `json:"newToken"` + UpdatedAt string `json:"updatedAt"` + } + // Plugin 插件接口 Plugin interface { // Start 启动 @@ -161,6 +170,9 @@ type ( // SyncFileFinishCallback 同步备份-同步文件完成的回调函数 SyncFileFinishCallback(context *Context, params *SyncFileFinishParams) error + // UserTokenRefreshFinishCallback 用户Token刷新完成后回调函数 + UserTokenRefreshFinishCallback(context *Context, params *UserTokenRefreshFinishParams) error + // Stop 停止 Stop() error }