This commit is contained in:
1-6
2023-07-25 09:41:56 +08:00
parent 172c244656
commit e5163b233a
23 changed files with 4729 additions and 312 deletions
+28 -13
View File
@@ -53,6 +53,7 @@ type Factory struct {
msgChan chan MsgChan
demo *CustomSender
reply func(map[string]interface{}) string
action func(map[string]interface{}) string
lm chan bool
nm int64
isAdmin func(string) bool
@@ -354,6 +355,23 @@ func (f *Factory) SetReplyHandler(function func(map[string]interface{}) string)
}
}
func (f *Factory) SetActionHandler(function func(map[string]interface{}) string) {
f.action = func(m map[string]interface{}) string {
if f.uuid != "" {
mutex := GetMutex(f.uuid)
mutex.Lock()
defer mutex.Unlock()
}
defer func() {
err := recover()
if err != nil {
pluginConsole(f.uuid).Error("Sender(\""+f.botplt+"\").SetAction error:", err)
}
}()
return function(m)
}
}
// func (f *Factory) GetReplies() {
// }
@@ -535,7 +553,7 @@ func (f *Factory) SetIsAdmin(function func(string) bool) {
func (f *Factory) Sender2(options map[string]string) *CustomSender {
var demo = *f.demo
sender := &demo
sender.SetID()
// sender.SetID()
if options != nil {
fsp := &common.FakerSenderParams{}
if v, ok := options[CONETNT]; ok {
@@ -570,8 +588,8 @@ func (f *Factory) Sender() interface{} {
func (f *Factory) Receive(props map[string]interface{}) *CustomSender {
var demo = *f.demo
sender := &demo
sender.SetID()
console.Log("senderId", sender.GetID())
// sender.SetID()
// console.Log("senderId", sender.GetID())
emf := map[string]interface{}{}
for i := range props {
h := false
@@ -653,6 +671,9 @@ func (sender *CustomSender) GetBotID() string {
type PUSH string
func (sender *CustomSender) Action(options map[string]interface{}) (interface{}, error) {
if sender.f.action != nil {
return sender.f.action(options), nil
}
var platform = sender.f.botplt
var any *common.Function
var one *common.Function
@@ -692,6 +713,7 @@ func (sender *CustomSender) Action(options map[string]interface{}) (interface{},
vm.Set("action", proxy)
vm.Set("adapter", sender.f)
})
}
return result, err
}
@@ -918,16 +940,9 @@ func (sender *CustomSender) GetID() string {
return sender.id
}
var test = "4d6371a8-2778-11ee-a3c2-821680fbbf6b"
func (sender *CustomSender) SetID() {
if test != "" {
sender.id = test
test = ""
} else {
sender.id = utils.GenUUID()
}
func (sender *CustomSender) SetID() string {
sender.id = utils.GenUUID()
sender.CreatedAt = time.Now()
senders.Store(sender.id, sender)
return sender.id
}
+10 -1
View File
@@ -162,6 +162,14 @@ type BaseSender struct {
emf map[string]interface{}
id string
CreatedAt time.Time
plugin_id string
}
func (sender *BaseSender) SetPluginID(plugin_id string) {
sender.plugin_id = plugin_id
}
func (sender *BaseSender) GetPluginID() string {
return sender.plugin_id
}
func (sender *BaseSender) SetLevel(l int) {
@@ -379,10 +387,11 @@ func (sender *BaseSender) GetID() string {
return sender.id
}
func (sender *BaseSender) SetID() {
func (sender *BaseSender) SetID() string {
sender.id = utils.GenUUID()
sender.CreatedAt = time.Now()
senders.Store(sender.id, sender)
return sender.id
}
func (sender *BaseSender) GetTime() time.Time {
+3 -1
View File
@@ -3,9 +3,11 @@ package common
import "time"
type Sender interface {
SetPluginID(string)
GetPluginID() string
GetID() string
GetTime() time.Time
SetID()
SetID() string
GetUserID() string
GetChatID() string
GetBotID() string
+1 -1
View File
@@ -17,7 +17,7 @@ func init() {
}
s := grpc.NewServer()
srpc.RegisterSillyGirlServiceServer(s, &SillyGirlService{})
log.Printf("grpc server listening at %v", lis.Addr())
// log.Printf("grpc server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
+34 -10
View File
@@ -3,6 +3,7 @@ package core
import (
"context"
"encoding/json"
"errors"
"sync"
"time"
@@ -13,8 +14,13 @@ import (
func (sg *SillyGirlService) AdapterRegist(stream srpc.SillyGirlService_AdapterRegistServer) error {
var adapter *Factory
var echos sync.Map
// defer func() {
// fmt.Println("test defer")
// }()
for {
// fmt.Println("test for")
req, err := stream.Recv()
// fmt.Println("test fored", err)
if err != nil {
return err
}
@@ -41,6 +47,24 @@ func (sg *SillyGirlService) AdapterRegist(stream srpc.SillyGirlService_AdapterRe
}
return ""
})
adapter.action = func(m map[string]interface{}) string {
m["__type__"] = "action"
echo := utils.GenUUID()
ch := make(chan string)
echos.Store(echo, ch)
defer echos.Delete(echo)
m["echo"] = echo
stream.Send(&srpc.Default{
Value: string(utils.JsonMarshal(m)),
})
select {
case v := <-ch:
return v
case <-time.After(time.Second * 5):
}
return ""
}
// fmt.Println("test start")
} else {
echo := req.GetBotId()
message_id := req.GetPlatform()
@@ -63,7 +87,7 @@ func (sg *SillyGirlService) AdapterReceive(ctx context.Context, req *srpc.Adapte
adapter, err := GetAdapter(bot_id, platform)
if err == nil {
s := adapter.Receive(msgs)
return &srpc.Default{Value: s.GetID()}, nil
return &srpc.Default{Value: s.SetID()}, nil
}
return &srpc.Default{Value: ""}, err
}
@@ -73,17 +97,17 @@ func (sg *SillyGirlService) AdapterPush(ctx context.Context, req *srpc.AdapterRe
bot_id := req.GetBotId()
platform := req.GetPlatform()
json.Unmarshal([]byte(req.Value), &msgs)
adapter, err := GetAdapter(bot_id, platform)
adapter, err := GetAdapter(platform, bot_id)
if err == nil {
result := adapter.Push(msgs)
message_id := result["message_id"]
error := result["error"]
if error != "" {
return &srpc.Default{Value: ""}, err
errst := result["error"]
if errst != "" {
return &srpc.Default{Value: ""}, errors.New(errst)
}
return &srpc.Default{Value: message_id}, err
return &srpc.Default{Value: message_id}, nil
}
return &srpc.Default{Value: ""}, err
return &srpc.Default{Value: ""}, nil
}
func (sg *SillyGirlService) AdapterSender(ctx context.Context, req *srpc.AdapterRequest) (*srpc.Default, error) {
@@ -91,10 +115,10 @@ func (sg *SillyGirlService) AdapterSender(ctx context.Context, req *srpc.Adapter
bot_id := req.GetBotId()
platform := req.GetPlatform()
json.Unmarshal([]byte(req.Value), &msgs)
adapter, err := GetAdapter(bot_id, platform)
adapter, err := GetAdapter(platform, bot_id)
if err == nil {
s := adapter.Sender2(msgs)
return &srpc.Default{Value: s.GetID()}, nil
return &srpc.Default{Value: s.SetID()}, nil
}
return &srpc.Default{Value: ""}, err
}
@@ -102,7 +126,7 @@ func (sg *SillyGirlService) AdapterSender(ctx context.Context, req *srpc.Adapter
func (sg *SillyGirlService) AdapterDestroy(ctx context.Context, req *srpc.AdapterRequest) (*srpc.Empty, error) {
bot_id := req.GetBotId()
platform := req.GetPlatform()
adapter, err := GetAdapter(bot_id, platform)
adapter, err := GetAdapter(platform, bot_id)
if err == nil {
adapter.Destroy()
}
+55
View File
@@ -2,7 +2,11 @@ package core
import (
"context"
"errors"
"sync"
"time"
"github.com/cdle/sillyplus/core/storage"
"github.com/cdle/sillyplus/proto3/srpc"
"github.com/cdle/sillyplus/utils"
)
@@ -11,6 +15,57 @@ type SillyGirlService struct {
srpc.UnsafeSillyGirlServiceServer
}
func (sg *SillyGirlService) BucketWatch(stream srpc.SillyGirlService_BucketWatchServer) error {
var watcher func(old, new, key string) *storage.Final
var echos sync.Map
for {
req, err := stream.Recv()
if err != nil {
return err
}
if watcher == nil {
watcher = func(old, new, key string) *storage.Final {
echo := utils.GenUUID()
ch := make(chan *storage.Final)
echos.Store(echo, ch)
defer echos.Delete(echo)
stream.Send(&srpc.BucketWatchResponse{
Echo: echo,
Old: old,
Now: new,
Key: key,
})
select {
case v := <-ch:
return v
case <-time.After(time.Second * 5):
}
return nil
}
storage.Watch(MakeBucket(req.Name), req.Key, watcher, req.PluginId)
} else {
echo := req.Echo
v, ok := echos.Load(echo)
var fn *storage.Final
if req.Error != "VOID" {
fn = &storage.Final{
Now: req.Now,
Message: req.Message,
}
if req.Error != "" {
fn.Error = errors.New(req.Error)
}
}
if ok {
select {
case v.(chan *storage.Final) <- fn:
case <-time.After(time.Millisecond):
}
}
}
}
}
// Get implements BucketServiceServer.Get.
func (sg *SillyGirlService) BucketGet(ctx context.Context, req *srpc.BucketKeyRequest) (*srpc.Default, error) {
value := MakeBucket(req.Name).GetString(req.Key)
+67
View File
@@ -0,0 +1,67 @@
package core
import (
"io"
"net/http"
"os"
"runtime"
"github.com/cdle/sillyplus/utils"
)
type Language struct {
Name string // node
Version string // 20230725
Os string // linux
Arch string // amd64
Links []string // 下载链接
}
var languages = []Language{
{
Name: "node",
Version: "20230725",
Os: "linux",
Arch: "amd64",
Links: []string{"https://gitee.com/sillybot/binary/releases/download/20230725/node_linux_amd64"},
},
{
Name: "node",
Version: "20230725",
Os: "darwin",
Arch: "arm64",
Links: []string{"https://gitee.com/sillybot/binary/releases/download/20230725/node_darwin_arm64"},
},
}
func init() {
for _, item := range languages {
if !(item.Os == runtime.GOOS && item.Arch == runtime.GOARCH) {
continue
}
func() {
dir := utils.ExecPath + "/language/" + item.Name
data, _ := os.ReadFile(dir + "/version")
if string(data) == item.Version {
return
}
os.MkdirAll(utils.ExecPath+"/language/"+item.Name, 0755)
resp, err := http.Get(item.Links[0])
if err != nil {
return
}
defer resp.Body.Close()
f, err := os.OpenFile(dir+"/"+item.Name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
return
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
if err != nil {
return
}
os.WriteFile(dir+"/version", []byte(item.Version), 0755)
}()
}
}
+95 -16
View File
@@ -1,6 +1,7 @@
package core
import (
"bufio"
"crypto/sha1"
"fmt"
"io/ioutil"
@@ -8,6 +9,7 @@ import (
"os/exec"
"path/filepath"
"strings"
"sync"
"github.com/cdle/sillyplus/core/common"
"github.com/cdle/sillyplus/core/storage"
@@ -22,6 +24,8 @@ func init() {
go initNodePlugins()
}
var processes sync.Map
func initNodePlugins() {
root := utils.ExecPath + "/plugins"
plugins := []string{root}
@@ -40,7 +44,7 @@ func initNodePlugins() {
plugins = append(plugins, path)
}
case 2:
if (files[1] == "main.ts" || files[1] == "main.js") && !info.IsDir() {
if (files[1] == "main.js") && !info.IsDir() { //files[1] == "main.ts" ||
AddNodePlugin(path, files[0])
}
}
@@ -52,9 +56,7 @@ func initNodePlugins() {
return
}
defer watcher.Close()
// 要监控的文件夹路径
for _, dir := range plugins {
err = watcher.Add(dir)
if err != nil {
@@ -77,12 +79,14 @@ func initNodePlugins() {
switch len(files) {
case 1:
plugin_dir = true
fmt.Println("目录事件")
// fmt.Println("目录事件")
plugin_name = files[0]
case 2:
if files[1] == "main.ts" || files[1] == "main.js" {
plugin_index = true
fmt.Println("入口文件事件")
if files[1] == "main.js" {
plugin_index = true
}
// fmt.Println("入口文件事件")
}
plugin_name = files[0]
}
@@ -131,10 +135,10 @@ func RemNodePlugin(name string) error {
pluginLock.Lock()
defer pluginLock.Unlock()
key := nameUuid(name)
fmt.Println("rem", key, name)
// fmt.Println("rem", key, name)
for i := range Functions {
if Functions[i].UUID == key {
fmt.Println("pl", key)
// fmt.Println("pl", key)
DestroyAdapterByUUID(key)
Functions[i].Running = false
if len(Functions[i].CronIds) != 0 {
@@ -177,16 +181,91 @@ func AddNodePlugin(path, name string) error {
f.Suffix = ".ts"
f.Type = "typescript"
f.Handle = func(s common.Sender, f func(vm *goja.Runtime)) interface{} {
cmd := exec.Command("node", "/Users/a1-6/.nvm/versions/node/v18.16.1/lib/node_modules/ts-node/dist/bin.js", path)
cmd.Env = append(cmd.Env, "SENDER_ID="+s.GetID())
// 执行命令,并捕获其输出
output, err := cmd.Output()
s.SetPluginID(uuid)
plt := s.GetImType()
// , "/Users/a1-6/.nvm/versions/node/v18.16.1/lib/node_modules/ts-node/dist/bin.js",
cmd := exec.Command(utils.ExecPath+"/language/node/node", path)
// cmd := exec.Command(utils.ExecPath+"/language/node/node", path)
id := s.SetID()
cmd.Env = append(cmd.Env, "SENDER_ID="+id)
cmd.Env = append(cmd.Env, "PLUGIN_ID="+uuid)
// 获取标准输出和标准错误输出的管道
stdout, err := cmd.StdoutPipe()
if err != nil {
fmt.Println("命令执行失败:", err)
return nil
// fmt.Printf("获取标准输出管道失败:%v\n", err)
// os.Exit(1)
}
stderr, err := cmd.StderrPipe()
if err != nil {
// fmt.Printf("获取标准错误输出管道失败:%v\n", err)
// os.Exit(1)
}
err = cmd.Start()
if err != nil {
}
// file, err := os.Create("output.log")
// if err != nil {
// fmt.Printf("创建文件失败:%v\n", err)
// os.Exit(1)
// }
// defer file.Close()
var wg sync.WaitGroup
wg.Add(2)
// 处理标准输出
go func() {
defer wg.Done()
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
data := scanner.Text()
fmt.Println("log", data)
// if _, err := file.WriteString(data + "\n"); err != nil {
// fmt.Printf("写入文件失败:%v\n", err)
// }
}
}()
// 处理标准错误输出
go func() {
defer wg.Done()
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
data := scanner.Text()
fmt.Fprintln(os.Stderr, "err "+data)
// if _, err := file.WriteString(data + "\n"); err != nil {
// fmt.Printf("写入文件失败:%v\n", err)
// }
}
}()
processes.Store(cmd, s)
if (plt) != "*" {
senders.Store(id, s)
defer senders.Delete(id)
defer processes.Delete(cmd)
err = cmd.Wait()
if err != nil {
fmt.Println("命令执行失败:", err)
return nil
}
} else {
processes.Range(func(key, value any) bool {
p := key.(*exec.Cmd)
if p == cmd {
return true
}
s := value.(common.Sender)
if s.GetPluginID() == uuid {
p.Process.Kill()
}
return true
})
go func() {
defer processes.Delete(cmd)
err = cmd.Wait()
}()
}
// 输出命令的输出结果
fmt.Println(string(output))
return nil
}
for _, cb := range cbs {
+133 -53
View File
@@ -4,6 +4,9 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"strings"
"sync"
"time"
@@ -14,23 +17,30 @@ import (
var senders sync.Map
func init() {
//垃圾回收
go func() {
for {
time.Sleep(time.Minute)
senders.Range(func(key, value any) bool {
s := value.(common.Sender)
if s.GetTime().Add(time.Minute * 20).Before(time.Now()) {
senders.Delete(s.GetID())
}
return true
})
}
}()
}
// func init() {
// //垃圾回收
// go func() {
// for {
// time.Sleep(time.Minute)
// senders.Range(func(key, value any) bool {
// s := value.(common.Sender)
// if s.GetTime().Add(time.Minute * 20).Before(time.Now()) {
// senders.Delete(s.GetID())
// }
// return true
// })
// }
// }()
// }
func GetSender(uuid string) (common.Sender, error) {
if uuid == "" {
return &CustomSender{
f: &Factory{
botid: "*",
},
}, nil
}
v, ok := senders.Load(uuid)
if !ok {
return nil, errors.New("not found sender")
@@ -121,47 +131,96 @@ func (sg *SillyGirlService) SenderContinue(ctx context.Context, req *srpc.Sender
}
// todo
func (sg *SillyGirlService) SenderListen(ctx context.Context, req *srpc.SenderListenRequest) (*srpc.Default, error) {
s, err := GetSender(req.Uuid)
if err != nil {
return nil, err
}
options := []interface{}{}
var carry = &Carry{
ListenPrivate: req.ListenPrivate,
ListenGroup: req.ListenGroup,
RequireAdmin: req.RequireAdmin,
AllowPlatforms: req.AllowPlatforms,
ProhibitPlatforms: req.ProhibitPlatforms,
AllowGroups: req.AllowGroups,
ProhibitGroups: req.ProhibitGroups,
AllowUsers: req.AllowUsers,
ProhibitUsers: req.ProhibitUsers,
UserID: s.GetUserID(),
ChatID: s.GetChatID(),
}
if req.Timeout != 0 {
options = append(options, time.Duration(req.Timeout)*time.Millisecond)
}
if len(req.Rules) != 0 {
for _, rule := range req.Rules {
_rs := formatRule(rule)
if len(_rs) != 0 {
carry.Function.Rules = append(carry.Function.Rules, _rs...)
} else {
carry.Function.Rules = append(carry.Function.Rules, rule)
func (sg *SillyGirlService) SenderListen(stream srpc.SillyGirlService_SenderListenServer) error {
var carry *Carry
var echos sync.Map
var persistent bool
// defer fmt.Println("已关闭,", "===")
for {
req, err := stream.Recv()
// fmt.Println("carry", carry, err)
if err == io.EOF {
break // 如果流已经关闭,则退出循环
}
if err != nil {
return err
}
if carry != nil {
echo := req.GetUuid()
value := req.GetValue()
// fmt.Println("echo", echo, "value", value)
v, ok := echos.Load(echo)
if ok {
select {
case v.(chan string) <- value:
case <-time.After(time.Millisecond):
}
}
// if !persistent {
// return nil
// }
continue
}
s, err := GetSender(req.Uuid)
if err != nil {
return err
}
options := []interface{}{}
carry = &Carry{
ListenPrivate: req.ListenPrivate,
ListenGroup: req.ListenGroup,
RequireAdmin: req.RequireAdmin,
AllowPlatforms: req.AllowPlatforms,
ProhibitPlatforms: req.ProhibitPlatforms,
AllowGroups: req.AllowGroups,
ProhibitGroups: req.ProhibitGroups,
AllowUsers: req.AllowUsers,
ProhibitUsers: req.ProhibitUsers,
UserID: s.GetUserID(),
ChatID: s.GetChatID(),
UUID: req.PluginId,
}
if req.Timeout != 0 {
options = append(options, time.Duration(req.Timeout)*time.Millisecond)
}
if len(req.Rules) != 0 {
for _, rule := range req.Rules {
_rs := formatRule(rule)
if len(_rs) != 0 {
carry.Function.Rules = append(carry.Function.Rules, _rs...)
} else {
carry.Function.Rules = append(carry.Function.Rules, rule)
}
}
}
options = append(options, carry)
if req.Persistent {
persistent = req.Persistent
options = append(options, "persistent")
}
go s.Await(s, func(s common.Sender) interface{} {
id := s.SetID()
defer senders.Delete(id)
echo := utils.GenUUID()
ch := make(chan string)
echos.Store(echo, ch)
defer echos.Delete(echo)
stream.Send(&srpc.SenderListenResponse{Echo: echo, Uuid: id})
value := <-ch
if !persistent {
if strings.HasPrefix(value, "go_again_") {
value = strings.Replace(value, "go_again_", "", 1)
return GoAgain(value)
} else {
stream.Send(&srpc.SenderListenResponse{Echo: "END"})
}
} else {
value = strings.Replace(value, "go_again_", "", 1)
}
return value
}, options...)
}
options = append(options, carry)
id := ""
s.Await(s, func(s common.Sender) interface{} {
id = s.GetID()
return nil
}, options...)
return &srpc.Default{Value: id}, nil
return nil
}
func (sg *SillyGirlService) SenderEvent(ctx context.Context, req *srpc.SenderRequest) (*srpc.Default, error) {
@@ -181,6 +240,21 @@ func (sg *SillyGirlService) SenderReply(ctx context.Context, req *srpc.ReplyRequ
return &srpc.Default{Value: message_id}, err
}
func (sg *SillyGirlService) SenderParam(ctx context.Context, req *srpc.ReplyRequest) (*srpc.Default, error) {
s, err := GetSender(req.Uuid)
if err != nil {
return nil, err
}
value := ""
i := utils.Int(req.Content)
if fmt.Sprint(i) == req.Content {
value = s.Get(i - 1)
} else {
value = s.Get(req.Content)
}
return &srpc.Default{Value: value}, err
}
func (sg *SillyGirlService) SenderAction(ctx context.Context, req *srpc.ReplyRequest) (*srpc.Default, error) {
s, err := GetSender(req.Uuid)
if err != nil {
@@ -194,3 +268,9 @@ func (sg *SillyGirlService) SenderAction(ctx context.Context, req *srpc.ReplyReq
result, err := s.Action(params)
return &srpc.Default{Value: string(utils.JsonMarshal(result))}, err
}
func (sg *SillyGirlService) SenderDestroy(ctx context.Context, req *srpc.ReplyRequest) (*srpc.Empty, error) {
// fmt.Println("删除", req.Uuid)
senders.Delete(req.Uuid)
return &srpc.Empty{}, nil
}
+17
View File
@@ -1,6 +1,7 @@
package core
import (
"context"
"encoding/base64"
"fmt"
"io/ioutil"
@@ -11,6 +12,7 @@ import (
"github.com/cdle/sillyplus/core/common"
"github.com/cdle/sillyplus/core/logs"
"github.com/cdle/sillyplus/proto3/srpc"
"github.com/cdle/sillyplus/utils"
"github.com/dop251/goja"
// "golang.org/x/image/webp"
@@ -47,6 +49,21 @@ type Console struct {
var console = &Console{}
var Logs = &Console{}
func (sg *SillyGirlService) Console(ctx context.Context, req *srpc.ConsoleRequest) (*srpc.Empty, error) {
log := &Console{
UUID: req.PluginId,
}
switch req.Type {
case "info", "log":
log.Info(req.Content)
case "error":
log.Error(req.Content)
case "debug":
log.Debug(req.Content)
}
return &srpc.Empty{}, nil
}
func pluginConsole(uuid string) *Console {
return &Console{
UUID: uuid,