Skip to content

Commit

Permalink
plugin handler
Browse files Browse the repository at this point in the history
  • Loading branch information
lz1998 committed Dec 18, 2021
1 parent 173f3b6 commit c671fc2
Show file tree
Hide file tree
Showing 5 changed files with 2,676 additions and 588 deletions.
47 changes: 39 additions & 8 deletions dto_proto/http_dto.proto
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,6 @@ message ListBotResp{
repeated Bot bot_list = 1;
}

//// 机器人登陆 /bot/login/v1/
//message BotLoginAsyncReq{
// int64 bot_id = 1;
//}
//message BotLoginAsyncResp{
//}

// 处理验证码 /captcha/solve/v1/
message SolveCaptchaReq{
int64 bot_id = 1;
Expand Down Expand Up @@ -88,12 +81,50 @@ message QRCodeLoginResp{
}


message Plugin{
string name = 1;
bool disabled = 2;
bool json = 3;
repeated string urls = 4;
repeated int32 event_filter = 5;
repeated int32 api_filter = 6;
string regex_filter = 7;
string regex_replace = 8;
repeated Header extra_header = 9;
message Header{
string key = 1;
repeated string value = 2;
}
}

message ListPluginReq{
}
message ListPluginResp{
repeated Plugin plugins = 1;
}

message SavePluginReq{
Plugin plugin = 1;
}
message SavePluginResp{
}

message DeletePluginReq{
string name = 1;
}
message DeletePluginResp{
}


service HttpService{
rpc CreateBot(CreateBotReq)returns (CreateBotResp);
rpc DeleteBot(DeleteBotReq)returns (DeleteBotResp);
rpc ListBot(ListBotReq)returns (ListBotResp);
// rpc BotLoginAsync(BotLoginAsyncReq)returns (BotLoginAsyncResp);
rpc SolveCaptcha(SolveCaptchaReq)returns (SolveCaptchaResp);
rpc FetchQRCode(FetchQRCodeReq)returns (QRCodeLoginResp);
rpc QueryQRCodeStatus(QueryQRCodeStatusReq)returns (QRCodeLoginResp);

rpc ListPlugin(ListPluginReq)returns (ListPluginResp);
rpc SavePlugin(SavePluginReq)returns (SavePluginResp);
rpc DeletePlugin(DeletePluginReq)returns (DeletePluginResp);
}
92 changes: 92 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
package config

import (
"bytes"
"encoding/json"
"fmt"
"github.com/ProtobufBot/Go-Mirai-Client/pkg/util"
log "github.com/sirupsen/logrus"
"io/ioutil"
"os"
"path"
"strings"
)

//go:generate go run github.com/a8m/syncmap -o "gen_plugin_map.go" -pkg config -name PluginMap "map[string]*Plugin"
var (
Fragment = false // 是否分片
Expand Down Expand Up @@ -45,3 +57,83 @@ type Plugin struct {
ExtraHeader map[string][]string `json:"extra_header"` // 自定义请求头
// TODO event filter, msg filter, regex filter, prefix filter, suffix filter
}

const pluginPath = "plugins"

func LoadPlugins() {
if !util.PathExists(pluginPath) {
return
}
files, err := ioutil.ReadDir(pluginPath)
if err != nil {
log.Warnf("failed to read plugin dir: %s", err)
return
}

if len(files) == 0 {
log.Warnf("plugin dir is empty")
return
}

ClearPlugins(Plugins)
for _, file := range files {
if !strings.HasSuffix(file.Name(), ".json") {
continue
}
pluginName := strings.TrimSuffix(file.Name(), ".json")
filepath := path.Join(pluginPath, file.Name())
b, err := os.ReadFile(filepath)
if err != nil {
log.Warnf("failed to read plugin file: %s %s", filepath, err)
continue
}
plugin := &Plugin{}
if err := json.NewDecoder(bytes.NewReader(b)).Decode(plugin); err != nil {
log.Warnf("failed to decode plugin file: %s %s", filepath, err)
continue
}
plugin.Name = pluginName
Plugins.Store(plugin.Name, plugin)
}
}

func WritePlugins() {
if !util.PathExists(pluginPath) {
if err := os.MkdirAll(pluginPath, 0777); err != nil {
log.Warnf("failed to mkdir")
return
}
}
DeletePluginFiles()
Plugins.Range(func(key string, plugin *Plugin) bool {
pluginFilename := fmt.Sprintf("%s.json", plugin.Name)
filepath := path.Join(pluginPath, pluginFilename)
b, err := json.MarshalIndent(plugin, "", " ")
if err != nil {
log.Warnf("failed to marshal plugin, %s", plugin.Name)
return true
}
if err := os.WriteFile(filepath, b, 0777); err != nil {
log.Warnf("failed to write file, %s", pluginFilename)
return true
}
return true
})
}

func DeletePluginFiles() {
files, err := ioutil.ReadDir(pluginPath)
if err != nil {
log.Warnf("failed to read plugin dir: %s", err)
}
for _, file := range files {
if !strings.HasSuffix(file.Name(), ".json") {
continue
}
filepath := path.Join(pluginPath, file.Name())
if err := os.Remove(filepath); err != nil {
log.Warnf("failed to remove plugin file: %s", filepath)
continue
}
}
}
73 changes: 6 additions & 67 deletions pkg/gmc/gmc.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package gmc

import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
Expand Down Expand Up @@ -92,10 +89,9 @@ func Start() {
os.Exit(0)
}

pluginPath := "plugins"
LoadPlugins(pluginPath) // 如果文件存在,从文件读取gmc config
LoadParamConfig() // 如果参数存在,从参数读取gmc config,并覆盖
WritePlugins(pluginPath) // 内存中的gmc config写到文件
config.LoadPlugins() // 如果文件存在,从文件读取gmc config
LoadParamConfig() // 如果参数存在,从参数读取gmc config,并覆盖
config.WritePlugins() // 内存中的gmc config写到文件
config.Plugins.Range(func(key string, value *config.Plugin) bool {
log.Infof("Plugin(%s): %s", value.Name, util.MustMarshal(value))
return true
Expand All @@ -105,66 +101,6 @@ func Start() {
InitGin() // 初始化GIN HTTP管理
}

func LoadPlugins(pluginPath string) {
if !util.PathExists(pluginPath) {
return
}
files, err := ioutil.ReadDir(pluginPath)
if err != nil {
log.Warnf("failed to read plugin dir: %s", err)
return
}

if len(files) == 0 {
log.Warnf("plugin dir is empty")
return
}

config.ClearPlugins(config.Plugins)
for _, file := range files {
if !strings.HasSuffix(file.Name(), ".json") {
continue
}
pluginName := strings.TrimSuffix(file.Name(), ".json")
filepath := path.Join(pluginPath, file.Name())
b, err := os.ReadFile(filepath)
if err != nil {
log.Warnf("failed to read plugin file: %s %s", filepath, err)
continue
}
plugin := &config.Plugin{}
if err := json.NewDecoder(bytes.NewReader(b)).Decode(plugin); err != nil {
log.Warnf("failed to decode plugin file: %s %s", filepath, err)
continue
}
plugin.Name = pluginName
config.Plugins.Store(plugin.Name, plugin)
}
}

func WritePlugins(pluginPath string) {
if !util.PathExists(pluginPath) {
if err := os.MkdirAll(pluginPath, 0777); err != nil {
log.Warnf("failed to mkdir")
return
}
}
config.Plugins.Range(func(key string, plugin *config.Plugin) bool {
pluginFilename := fmt.Sprintf("%s.json", plugin.Name)
filepath := path.Join(pluginPath, pluginFilename)
b, err := json.MarshalIndent(plugin, "", " ")
if err != nil {
log.Warnf("failed to marshal plugin, %s", plugin.Name)
return true
}
if err := os.WriteFile(filepath, b, 0777); err != nil {
log.Warnf("failed to write file, %s", pluginFilename)
return true
}
return true
})
}

func LoadParamConfig() {
// sms是true,如果本来是true,不变。如果本来是false,变true
if sms {
Expand Down Expand Up @@ -223,6 +159,9 @@ func InitGin() {
router.POST("/captcha/solve/v1", handler.SolveCaptcha)
router.POST("/qrcode/fetch/v1", handler.FetchQrCode)
router.POST("/qrcode/query/v1", handler.QueryQRCodeStatus)
router.POST("/plugin/list/v1", handler.ListPlugin)
router.POST("/plugin/save/v1", handler.SavePlugin)
router.POST("/plugin/delete/v1", handler.DeletePlugin)
realPort, err := RunGin(router, ":"+config.Port)
if err != nil {
util.FatalError(fmt.Errorf("failed to run gin, err: %+v", err))
Expand Down
93 changes: 93 additions & 0 deletions pkg/gmc/handler/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

"github.com/ProtobufBot/Go-Mirai-Client/pkg/bot"
"github.com/ProtobufBot/Go-Mirai-Client/pkg/config"
"github.com/ProtobufBot/Go-Mirai-Client/pkg/device"
"github.com/ProtobufBot/Go-Mirai-Client/pkg/gmc/plugins"
"github.com/ProtobufBot/Go-Mirai-Client/pkg/plugin"
Expand Down Expand Up @@ -229,6 +230,98 @@ func QueryQRCodeStatus(c *gin.Context) {
Return(c, resp)
}

func ListPlugin(c *gin.Context) {
req := &dto.ListPluginReq{}
err := c.Bind(req)
if err != nil {
c.String(http.StatusBadRequest, "bad request")
return
}
var resp = &dto.ListPluginResp{
Plugins: []*dto.Plugin{},
}
config.Plugins.Range(func(key string, p *config.Plugin) bool {
resp.Plugins = append(resp.Plugins, &dto.Plugin{
Name: p.Name,
Disabled: p.Disabled,
Json: p.Json,
Urls: p.Urls,
EventFilter: p.EventFilter,
ApiFilter: p.ApiFilter,
RegexFilter: p.RegexFilter,
RegexReplace: p.RegexReplace,
ExtraHeader: func() []*dto.Plugin_Header {
headers := make([]*dto.Plugin_Header, 0)
for k, v := range p.ExtraHeader {
headers = append(headers, &dto.Plugin_Header{
Key: k,
Value: v,
})
}
return headers
}(),
})
return true
})
Return(c, resp)
}

func SavePlugin(c *gin.Context) {
req := &dto.SavePluginReq{}
err := c.Bind(req)
if err != nil {
c.String(http.StatusBadRequest, "bad request")
return
}
if req.Plugin == nil {
c.String(http.StatusBadRequest, "plugin is nil")
return
}
p := req.Plugin
if p.ApiFilter == nil {
p.ApiFilter = []int32{}
}
if p.EventFilter == nil {
p.EventFilter = []int32{}
}
if p.Urls == nil {
p.Urls = []string{}
}
config.Plugins.Store(p.Name, &config.Plugin{
Name: p.Name,
Disabled: p.Disabled,
Json: p.Json,
Urls: p.Urls,
EventFilter: p.EventFilter,
ApiFilter: p.ApiFilter,
RegexFilter: p.RegexFilter,
RegexReplace: p.RegexReplace,
ExtraHeader: func() map[string][]string {
headers := map[string][]string{}
for _, h := range p.ExtraHeader {
headers[h.Key] = h.Value
}
return headers
}(),
})
config.WritePlugins()
resp := &dto.SavePluginResp{}
Return(c, resp)
}

func DeletePlugin(c *gin.Context) {
req := &dto.DeletePluginReq{}
err := c.Bind(req)
if err != nil {
c.String(http.StatusBadRequest, "bad request")
return
}
config.Plugins.Delete(req.Name)
config.WritePlugins()
resp := &dto.DeletePluginResp{}
Return(c, resp)
}

func Return(c *gin.Context, resp proto.Message) {
var (
data []byte
Expand Down
Loading

0 comments on commit c671fc2

Please sign in to comment.