Files
Sillyv2/core/task.go
T
2023-07-17 09:36:07 +08:00

400 lines
9.0 KiB
Go

package core
import (
"encoding/json"
"fmt"
"regexp"
"sort"
"time"
"github.com/cdle/sillyplus/core/common"
"github.com/cdle/sillyplus/core/storage"
"github.com/cdle/sillyplus/utils"
"github.com/gin-gonic/gin"
"github.com/robfig/cron/v3"
)
var tasks = MakeBucket("tasks")
type TasksResult struct {
Success bool `json:"success"`
Data []*Tasks `json:"data"`
Page int `json:"page"`
Total int `json:"total"`
Time time.Time `json:"time"`
}
type Sender struct {
ChatID string `json:"chat_id"`
UserID string `json:"user_id"`
Platfrom string `json:"platform"`
BotID string `json:"bot_id"`
}
type Tasks struct {
Index int `json:"id"` //编号 顺序编号
ID string `json:"task_id"` //任务ID
Title string `json:"title"` //任务名
Schedule string `json:"schedule"` //计划时间
Senders []Sender `json:"senders"` //发送人
Command string `json:"command"` //消息指令
Scripts []string `json:"scripts"` //触发脚本
CronID int `json:"cron_id"`
CreatedAt int `json:"created_at"` //创建时间戳(秒)转换成日期
Remark string `json:"remark"`
Enable bool `json:"enable"`
Handle func() `json:"-"`
Icons []interface{} `json:"icons"`
}
var pts = []*Tasks{}
func RegistTasks(pt *Tasks) {
pt.Handle = func() {
content := pt.Command
for _, meta := range pt.Senders {
adapter, _ := GetAdapter(meta.Platfrom, meta.BotID)
if adapter != nil {
sender := adapter.Sender()
sender.SetFsps(&common.FakerSenderParams{
Content: content,
ChatID: meta.ChatID,
UserID: meta.UserID,
})
for _, script := range pt.Scripts {
for _, function := range Functions {
if function.UUID == script {
for i := range function.Rules {
reg, err := regexp.Compile(function.Rules[i])
if err == nil {
if res := reg.FindStringSubmatch(content); len(res) > 0 {
sender.SetMatch(res[1:])
sender.SetParams(function.Params[i])
}
}
}
function.Handle(sender, nil)
break
}
}
}
}
}
}
cid, _ := CRON.AddFunc(pt.Schedule, pt.Handle)
pt.CronID = int(cid)
console.Debug("已添加计划任务:%s(%v)", pt.Title, pt.CronID)
}
func init() {
tasks.Foreach(func(b1, b2 []byte) error {
pt := Tasks{}
err := json.Unmarshal(b2, &pt)
if err != nil {
return nil
}
RegistTasks(&pt)
pts = append(pts, &pt)
return nil
})
sort.Sort(byCreatedAt2(pts))
for i := range pts {
pts[i].Index = i + 1
}
storage.Watch(tasks, nil, func(old, new, key string) *storage.Final {
console.Log("已更新计划任务")
ocg := Tasks{}
ncg := Tasks{}
json.Unmarshal([]byte(old), &ocg)
json.Unmarshal([]byte(new), &ncg)
tmp := pts
if old != "" {
if new == "" { // 删除
if ocg.ID != "" {
for i, cg := range tmp {
if cg.ID == ocg.ID {
CRON.Remove(cron.EntryID(tmp[i].CronID))
tmp = append(tmp[:i], tmp[i+1:]...)
break
}
}
} else {
return nil
}
} else { // 修改
if ocg.ID != "" {
for i, cg := range tmp {
if cg.ID == ocg.ID {
CRON.Remove(cron.EntryID(tmp[i].CronID))
tmp[i] = &ncg
RegistTasks(&ncg)
//todo 增
break
}
}
} else {
return nil
}
}
} else { //创建
if ncg.ID != "" {
tmp = append(tmp, &ncg)
RegistTasks(&ncg)
//todo 增
} else {
return nil
}
}
sort.Sort(byCreatedAt2(pts))
for i := range tmp {
tmp[i].Index = i + 1
}
pts = tmp
return nil
})
GinApi(GET, "/api/tasks", RequireAuth, func(ctx *gin.Context) {
current := utils.Int(ctx.Query("current"))
pageSize := utils.Int(ctx.Query("pageSize"))
rr := TasksResult{
Success: true,
}
pts := pts
rr.Total = len(pts)
if current == 0 {
current = 1
}
if pageSize == 0 {
pageSize = 20
}
begin := (current - 1) * pageSize
end := (current) * pageSize
if end > rr.Total {
end = rr.Total
}
if begin > end {
begin = end
}
rr.Data = pts[begin:end]
for i := range rr.Data {
rr.Data[i].Icons = []interface{}{}
for _, script := range rr.Data[i].Scripts {
for _, f := range Functions {
if f.UUID == script {
if f.Icon != "" {
rr.Data[i].Icons = append(rr.Data[i].Icons, map[string]interface{}{
"link": f.Icon,
"title": f.Title,
})
break
}
}
}
}
}
ctx.JSON(200, rr)
})
GinApi(POST, "/api/tasks", RequireAuth, func(ctx *gin.Context) {
// 将请求的 JSON 数据解析为一个 map[string]interface{} 类型的变量
var updateData map[string]interface{}
err := ctx.BindJSON(&updateData)
if err != nil {
ctx.JSON(200, map[string]interface{}{
"success": false,
"errorMessage": err.Error(),
})
return
}
v, ok := updateData["task_id"]
if !ok {
ctx.JSON(200, map[string]interface{}{
"success": false,
"errorMessage": "任务ID不能为空",
})
return
}
task_id := v.(string)
var tp = Tasks{
ID: task_id,
}
tasks.First(&tp)
for key, value := range updateData {
switch key {
case "title":
if v, ok := value.(string); ok {
tp.Title = v
}
case "remark":
if v, ok := value.(string); ok {
tp.Remark = v
}
case "schedule":
if v, ok := value.(string); ok {
tp.Schedule = v
id, err := CRON.AddFunc(tp.Schedule, func() {})
if err != nil {
ctx.JSON(200, map[string]interface{}{
"success": false,
"errorMessage": "Cron表达式错误:" + err.Error(),
})
return
}
CRON.Remove(id)
}
case "senders":
ss := []Sender{}
err := json.Unmarshal(utils.JsonMarshal(value), &ss)
if err != nil {
ctx.JSON(200, map[string]interface{}{
"success": false,
"errorMessage": "Senders错误:" + err.Error(),
})
return
}
tp.Senders = ss
case "command":
if v, ok := value.(string); ok {
tp.Command = v
}
case "scripts":
if v, ok := value.([]interface{}); ok {
tp.Scripts = toStringSlice(v)
}
case "enable":
if v, ok := value.(bool); ok {
tp.Enable = v
}
}
}
if tp.CreatedAt == 0 {
tp.CreatedAt = int(time.Now().Unix())
}
tasks.Set(task_id, utils.JsonMarshal(tp))
if err != nil {
ctx.JSON(200, map[string]interface{}{
"success": false,
"errorMessage": err.Error(),
})
return
}
ctx.JSON(200, map[string]interface{}{
"success": true,
})
})
GinApi(DELETE, "/api/tasks", RequireAuth, func(ctx *gin.Context) {
pt := &Tasks{}
err := ctx.BindJSON(pt)
if err != nil {
ctx.JSON(200, map[string]interface{}{
"success": false,
"errorMessage": err.Error(),
})
return
}
if pt.ID == "" {
ctx.JSON(200, map[string]interface{}{
"success": false,
"errorMessage": "任务ID不为空",
})
return
}
tasks.Set(pt.ID, "")
ctx.JSON(200, map[string]interface{}{
"success": true,
})
})
GinApi(GET, "/api/task/selects", RequireAuth, func(ctx *gin.Context) {
var scripts = map[string]string{}
var task_id = ctx.Query("task_id")
var pts = pts
var chat_ids = []string{}
var user_ids = []string{}
for _, pt := range pts {
if pt.ID == task_id {
for _, s := range pt.Senders {
if s.ChatID != "" {
chat_ids = append(chat_ids, s.ChatID)
}
if s.UserID != "" {
user_ids = append(user_ids, s.UserID)
}
}
break
}
}
functions := Functions
for _, function := range functions {
if function.UUID != "" {
scripts[function.UUID] = function.Title + ".js"
}
}
var user_names = []NicklabeL{}
var group_names = []NicklabeL{{
Label: "私聊",
Value: "",
}}
nickname.Foreach(func(b1, b2 []byte) error {
v := &Nickname{}
code := string(b1)
err := json.Unmarshal(b2, v)
if err == nil {
if v.Group {
if Contains(chat_ids, code) {
group_names = append(group_names, NicklabeL{
Label: fmt.Sprintf("%s(%s)", v.Value, code),
Value: code,
})
}
} else {
if Contains(user_ids, code) {
user_names = append(user_names, NicklabeL{
Label: fmt.Sprintf("%s(%s)", v.Value, code),
Value: code,
})
}
}
}
return nil
})
platforms := map[string][]string{}
for _, plt := range getPltsArray() {
platforms[plt] = GetAdapterBotsID(plt)
}
ctx.JSON(200, map[string]interface{}{
"success": true,
"data": map[string]interface{}{
"scripts": scripts,
"platforms": platforms,
"user_names": user_names,
"group_names": group_names,
},
})
})
GinApi(GET, "/api/tasks/run", RequireAuth, func(ctx *gin.Context) {
var task_id = ctx.Query("task_id")
for _, pt := range pts {
if pt.ID == task_id {
pt.Handle()
}
}
ctx.JSON(200, map[string]interface{}{
"success": true,
})
})
}
type byCreatedAt2 []*Tasks
func (s byCreatedAt2) Len() int {
return len(s)
}
func (s byCreatedAt2) Less(i, j int) bool {
return s[i].CreatedAt > s[j].CreatedAt
}
func (s byCreatedAt2) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}