This commit is contained in:
源文雨 2022-10-28 11:35:18 +08:00
commit ea2c81a9c7
4 changed files with 102 additions and 183 deletions

View File

@ -619,15 +619,9 @@ print("run[CQ:image,file="+j["img"]+"]")
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle"` `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle"`
- [x] (在群xxx)丢漂流瓶(到频道xxx) [消息] - [x] @Bot pick (随机捞一个漂流瓶)
- [x] (从频道xxx)捡漂流瓶 - [x] @Bot throw xxx (投递内容xxx,支持图片文字,投递内容需要大于10个字符或者带有图片)
- [x] @BOT 创建频道 xxx
- [x] 跳入(频道)海中
- [x] 注:不显式限制时,私聊发送可在所有群抽到,群聊发送仅可在本群抽到,默认频道为 global
</details> </details>
<details> <details>

View File

@ -1,53 +0,0 @@
package driftbottle
import (
"fmt"
"hash/crc64"
"strconv"
"sync"
"github.com/FloatTech/floatbox/binary"
sql "github.com/FloatTech/sqlite"
)
type bottle struct {
ID int64 `db:"id"` // ID qq_grp_name_msg 的 crc64
QQ int64 `db:"qq"` // QQ 发送者 qq
Grp int64 `db:"grp"` // Grp 限制抽出的群 / 人(负数)
Name string `db:"name"` // Name 发送者 昵称
Msg string `db:"msg"` // Msg 消息,纯文本
}
var sea = &sql.Sqlite{}
var seamu sync.RWMutex
func newBottle(qq, grp int64, name, msg string) *bottle {
id := int64(crc64.Checksum(binary.StringToBytes(fmt.Sprintf("%d_%d_%s_%s", qq, grp, name, msg)), crc64.MakeTable(crc64.ISO)))
return &bottle{ID: id, QQ: qq, Grp: grp, Name: name, Msg: msg}
}
func (b *bottle) throw(db *sql.Sqlite, channel string) error {
seamu.Lock()
defer seamu.Unlock()
return db.Insert(channel, b)
}
func (b *bottle) destroy(db *sql.Sqlite, channel string) error {
seamu.Lock()
defer seamu.Unlock()
return db.Del(channel, "WHERE id="+strconv.FormatInt(b.ID, 10))
}
// fetchBottle grp != 0
func fetchBottle(db *sql.Sqlite, channel string, grp int64) (*bottle, error) {
seamu.RLock()
defer seamu.RUnlock()
b := new(bottle)
return b, db.Find(channel, b, "WHERE grp=0 or grp="+strconv.FormatInt(grp, 10)+" ORDER BY RANDOM() limit 1")
}
func createChannel(db *sql.Sqlite, channel string) error {
seamu.Lock()
defer seamu.Unlock()
return db.Create(channel, &bottle{})
}

View File

@ -2,132 +2,107 @@
package driftbottle package driftbottle
import ( import (
"fmt"
"hash/crc64"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
"unicode/utf8"
"github.com/FloatTech/floatbox/binary"
sql "github.com/FloatTech/sqlite"
ctrl "github.com/FloatTech/zbpctrl" ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control"
"github.com/sirupsen/logrus" "github.com/FloatTech/zbputils/ctxext"
zero "github.com/wdvxdr1123/ZeroBot" zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
type sea struct {
ID int64 `db:"id"` // ID qq_grp_name_msg 的 crc64 hashCheck.
QQ int64 `db:"qq"` // Get current user(Who sends this)
Name string `db:"Name"` // his or her name at that time:P
Msg string `db:"msg"` // What he or she sent to bot?
Grp int64 `db:"grp"` // which group sends this msg?
Time string `db:"time"` // we need to know the current time,master>
}
var seaSide = &sql.Sqlite{}
var seaLocker sync.RWMutex
// We need a container to inject what we need :(
func init() { func init() {
en := control.Register("driftbottle", &ctrl.Options[*zero.Ctx]{ en := control.Register("driftbottle", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Help: "漂流瓶\n- (在群xxx)丢漂流瓶(到频道xxx) [消息]\n- (从频道xxx)捡漂流瓶\n- @BOT 创建频道 xxx\n- 跳入(频道)海中\n- 注:不显式限制时,私聊发送可在所有群抽到,群聊发送仅可在本群抽到,默认频道为 global", Help: "简单的漂流瓶\n" + "- @bot pick" + "- @bot throw xxx (xxx为投递内容)",
PrivateDataFolder: "driftbottle", PrivateDataFolder: "driftbottle",
}) })
sea.DBPath = en.DataFolder() + "sea.db" seaSide.DBPath = en.DataFolder() + "sea.db"
err := sea.Open(time.Hour * 24) err := seaSide.Open(time.Hour * 24)
if err != nil { if err != nil {
panic(err) panic(err)
} }
_ = createChannel(sea, "global")
en.OnRegex(`^(在群\d+)?丢漂流瓶(到频道\w+)?\s+(.*)$`).SetBlock(true). _ = createChannel(seaSide)
Handle(func(ctx *zero.Ctx) { en.OnFullMatch("pick", zero.OnlyToMe, zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
msgs := ctx.State["regex_matched"].([]string) be, err := fetchBottle(seaSide)
grp := ctx.Event.GroupID
channel := "global"
msg := msgs[3]
var err error
if msgs[1] != "" {
grp, err = strconv.ParseInt(msgs[1][6:], 10, 64)
if err != nil { if err != nil {
ctx.SendChain(message.Text("群号非法!")) ctx.SendChain(message.Text("ERR:", err))
}
idstr := strconv.Itoa(int(be.ID))
qqstr := strconv.Itoa(int(be.QQ))
grpstr := strconv.Itoa(int(be.Grp))
botname := zero.BotConfig.NickName[0]
msg := message.Message{message.CustomNode(botname, ctx.Event.SelfID, botname+"试着帮你捞出来了这个~\nID:"+idstr+"\n投递人: "+be.Name+"("+qqstr+")"+"\n群号: "+grpstr+"\n时间: "+be.Time+"\n内容: \n"+be.Msg)}
ctx.Send(msg)
})
en.OnRegex(`throw.*?(.*)`, zero.OnlyToMe, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
senderFormatTime := time.Unix(ctx.Event.Time, 0).Format("2006-01-02 15:04:05")
rawSenderMessage := ctx.State["regex_matched"].([]string)[1]
rawMessageCallBack := message.UnescapeCQCodeText(rawSenderMessage)
keyWordsNum := utf8.RuneCountInString(rawMessageCallBack)
if keyWordsNum < 10 {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("需要投递的内容过少( "))
return return
} }
} // check current needs and prepare to throw drift_bottle.
if msgs[2] != "" { err = globalbottle(
channel = msgs[2][9:]
}
if msg == "" {
ctx.SendChain(message.Text("消息为空!"))
return
}
logrus.Debugln("[driftbottle]", grp, channel, msg)
err = newBottle(
ctx.Event.UserID, ctx.Event.UserID,
grp, ctx.Event.GroupID,
senderFormatTime,
ctx.CardOrNickName(ctx.Event.UserID), ctx.CardOrNickName(ctx.Event.UserID),
msg, rawMessageCallBack,
).throw(sea, channel) ).throw(seaSide)
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
return return
} }
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你将它扔进大海,希望有人捞到吧~"))) ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("已经帮你丢出去了哦~")))
})
en.OnRegex(`^(从频道\w+)?捡漂流瓶$`).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
msgs := ctx.State["regex_matched"].([]string)
grp := ctx.Event.GroupID
if grp == 0 {
grp = -ctx.Event.UserID
}
if grp == 0 {
ctx.SendChain(message.Text("找不到对象!"))
return
}
channel := "global"
if msgs[1] != "" {
channel = msgs[1][9:]
}
logrus.Debugln("[driftbottle]", grp, channel)
b, err := fetchBottle(sea, channel, grp)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
err = b.destroy(sea, channel)
wg.Done()
}()
ctx.Send(
message.ReplyWithMessage(
ctx.Event.MessageID,
message.Text("你在海边捡到了一个来自 ", b.Name, " 的漂流瓶,打开瓶子,里面有一张纸条,写着:"),
message.Text(b.Msg),
),
)
wg.Wait()
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
})
en.OnPrefix("创建频道", zero.SuperUserPermission, zero.OnlyToMe).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
channel := strings.TrimRight(ctx.State["args"].(string), " ")
if channel == "" {
ctx.SendChain(message.Text("频道名为空!"))
return
}
err := createChannel(sea, channel)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("成功~")))
})
en.OnRegex(`^跳入(\w+)?海中$`).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
msgs := ctx.State["regex_matched"].([]string)
channel := "global"
if msgs[1] != "" {
channel = msgs[1]
}
seamu.RLock()
c, err := sea.Count(channel)
seamu.RUnlock()
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你缓缓走入大海,感受着海浪轻柔地拍打着你的小腿,膝盖……\n波浪卷着你的腰腹你感觉有些把握不住平衡了……\n……\n你沉入海中", c, " 个物体与你一同沉浮。\n不知何处涌来一股暗流你失去了意识。")))
}) })
} }
func globalbottle(qq, grp int64, time, name, msg string) *sea { // Check as if the User is available and collect information to store.
id := int64(crc64.Checksum(binary.StringToBytes(fmt.Sprintf("%d_%d_%s_%s_%s", grp, qq, time, name, msg)), crc64.MakeTable(crc64.ISO)))
return &sea{ID: id, Grp: grp, Time: time, QQ: qq, Name: name, Msg: msg}
}
func (be *sea) throw(db *sql.Sqlite) error {
seaLocker.Lock()
defer seaLocker.Unlock()
return db.Insert("global", be)
}
func fetchBottle(db *sql.Sqlite) (*sea, error) {
seaLocker.Lock()
defer seaLocker.Unlock()
be := new(sea)
return be, db.Pick("global", be)
}
func createChannel(db *sql.Sqlite) error {
seaLocker.Lock()
defer seaLocker.Unlock()
return db.Create("global", &sea{})
}

View File

@ -62,7 +62,11 @@ func init() {
}).ApplySingle(ctxext.DefaultSingle) }).ApplySingle(ctxext.DefaultSingle)
cache := engine.DataFolder() + "cache" cache := engine.DataFolder() + "cache"
_ = os.MkdirAll(cache, 0755) _ = os.RemoveAll(cache)
err := os.MkdirAll(cache, 0755)
if err != nil {
panic(err)
}
getTarot := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { getTarot := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
data, err := engine.GetLazyData("tarots.json", true) data, err := engine.GetLazyData("tarots.json", true)
@ -142,19 +146,18 @@ func init() {
} }
imgurl := bed + reverse[p] + card.ImgURL imgurl := bed + reverse[p] + card.ImgURL
imgname := "" imgname := ""
imgpath := cache + "/" + imgname + ".png"
if p == 1 { if p == 1 {
imgname = reverse[p][:len(reverse[p])-1] + card.Name imgname = reverse[p][:len(reverse[p])-1] + name
} else { } else {
imgname = card.Name imgname = name
} }
err := pool.SendImageFromPool(imgname, imgpath, func() error { imgpath := cache + "/" + imgname + ".png"
err := pool.SendImageFromPool("pool"+imgname, imgpath, func() error {
data, err := web.RequestDataWith(web.NewTLS12Client(), imgurl, "GET", "gitcode.net", web.RandUA()) data, err := web.RequestDataWith(web.NewTLS12Client(), imgurl, "GET", "gitcode.net", web.RandUA())
if err != nil { if err != nil {
return err return err
} }
var f *os.File f, err := os.Create(imgpath)
f, err = os.Create(imgpath)
if err != nil { if err != nil {
return err return err
} }
@ -191,9 +194,9 @@ func init() {
var imgmsg message.MessageSegment var imgmsg message.MessageSegment
var err error var err error
if p == 1 { if p == 1 {
imgmsg, err = poolimg(ctx, imgurl, reverse[p][:len(reverse[p])-1]+card.Name, cache) imgmsg, err = poolimg(ctx, imgurl, reverse[p][:len(reverse[p])-1]+name, cache)
} else { } else {
imgmsg, err = poolimg(ctx, imgurl, card.Name, cache) imgmsg, err = poolimg(ctx, imgurl, name, cache)
} }
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
@ -285,9 +288,9 @@ func init() {
var imgmsg message.MessageSegment var imgmsg message.MessageSegment
var err error var err error
if p == 1 { if p == 1 {
imgmsg, err = poolimg(ctx, imgurl, reverse[p][:len(reverse[p])-1]+card.Name, cache) imgmsg, err = poolimg(ctx, imgurl, reverse[p][:len(reverse[p])-1]+name, cache)
} else { } else {
imgmsg, err = poolimg(ctx, imgurl, card.Name, cache) imgmsg, err = poolimg(ctx, imgurl, name, cache)
} }
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
@ -323,7 +326,7 @@ func init() {
func poolimg(ctx *zero.Ctx, imgurl, imgname, cache string) (msg message.MessageSegment, err error) { func poolimg(ctx *zero.Ctx, imgurl, imgname, cache string) (msg message.MessageSegment, err error) {
imgfile := cache + "/" + imgname + ".png" imgfile := cache + "/" + imgname + ".png"
aimgfile := file.BOTPATH + "/" + imgfile aimgfile := file.BOTPATH + "/" + imgfile
m, err := pool.GetImage(imgname) m, err := pool.GetImage("pool" + imgname)
if err == nil { if err == nil {
msg = message.Image(m.String()) msg = message.Image(m.String())
if ctxext.SendToSelf(ctx)(msg) == 0 { if ctxext.SendToSelf(ctx)(msg) == 0 {