Skip to content

Commit

Permalink
feat:初步支持 gocq
Browse files Browse the repository at this point in the history
* 前端交互未完成;黑名单/群邀请与协议实现分离未完成
* 为了协助先提交到远程
  • Loading branch information
f44r committed Mar 6, 2023
1 parent af0aeca commit 2c093f8
Show file tree
Hide file tree
Showing 15 changed files with 1,928 additions and 210 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ go-cqhttp/
frontend/
backups/
update/
walle-q/
_help_cache
87 changes: 80 additions & 7 deletions api/api_bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"encoding/base64"
"encoding/hex"
"fmt"
"net/http"
"runtime"
"sealdice-core/dice"
Expand Down Expand Up @@ -171,7 +172,7 @@ func ImConnectionsSetData(c echo.Context) error {
if err == nil {
for _, i := range myDice.ImSession.EndPoints {
if i.Id == v.Id {
ad := i.Adapter.(*dice.PlatformAdapterQQOnebot)
ad := i.Adapter.(*dice.PlatformAdapterGocq)
ad.SetQQProtocol(v.Protocol)
ad.IgnoreFriendRequest = v.IgnoreFriendRequest
return c.JSON(http.StatusOK, i)
Expand Down Expand Up @@ -241,14 +242,26 @@ func ImConnectionsQrcodeGet(c echo.Context) error {
Id string `form:"id" json:"id"`
}{}
err := c.Bind(&v)
fmt.Println(err)
if err == nil {
for _, i := range myDice.ImSession.EndPoints {
fmt.Println(i.Id, i.ProtocolType, i.ProtocolType)
if i.Id == v.Id {
pa := i.Adapter.(*dice.PlatformAdapterQQOnebot)
if pa.GoCqHttpState == dice.GoCqHttpStateCodeInLoginQrCode {
return c.JSON(http.StatusOK, map[string]string{
"img": "data:image/png;base64," + base64.StdEncoding.EncodeToString(pa.GoCqHttpQrcodeData),
})
switch i.ProtocolType {
case "onebot":
pa := i.Adapter.(*dice.PlatformAdapterGocq)
if pa.GoCqHttpState == dice.StateCodeInLoginQrCode {
return c.JSON(http.StatusOK, map[string]string{
"img": "data:image/png;base64," + base64.StdEncoding.EncodeToString(pa.GoCqHttpQrcodeData),
})
}
case "walle-q":
pa := i.Adapter.(*dice.PlatformAdapterWalleQ)
if pa.WalleQState == dice.WqStateCodeInLoginQrCode {
return c.JSON(http.StatusOK, map[string]string{
"img": "data:image/png;base64," + base64.StdEncoding.EncodeToString(pa.WalleQQrcodeData),
})
}
}
return c.JSON(http.StatusOK, i)
}
Expand All @@ -257,6 +270,44 @@ func ImConnectionsQrcodeGet(c echo.Context) error {
return c.JSON(http.StatusNotFound, nil)
}

func ImConnectionsAddWalleQ(c echo.Context) error {
if !doAuth(c) {
return c.JSON(http.StatusForbidden, nil)
}
v := struct {
Account string `yaml:"account" json:"account"`
Password string `yaml:"password" json:"password"`
Protocol int `json:"protocol"`
}{}
err := c.Bind(&v)
if err == nil {
uid, err := strconv.ParseInt(v.Account, 10, 64)
if err != nil {
return c.String(430, "")
}

for _, i := range myDice.ImSession.EndPoints {
if i.UserId == dice.FormatDiceIdQQ(uid) {
return c.JSON(CODE_ALREADY_EXISTS, i)
}
}

conn := dice.NewWqConnectInfoItem(v.Account)
conn.UserId = dice.FormatDiceIdQQ(uid)
conn.ProtocolType = "walle-q"
pa := conn.Adapter.(*dice.PlatformAdapterWalleQ)
pa.InPackWalleQProtocol = v.Protocol
pa.InPackWalleQPassword = v.Password
pa.Session = myDice.ImSession

myDice.ImSession.EndPoints = append(myDice.ImSession.EndPoints, conn)
dice.WalleQServe(myDice, conn, v.Password, v.Protocol, false)
myDice.Save(false)
return c.JSON(200, conn)
}
return c.String(430, "")
}

func ImConnectionsGocqhttpRelogin(c echo.Context) error {
if !doAuth(c) {
return c.JSON(http.StatusForbidden, nil)
Expand All @@ -282,6 +333,26 @@ func ImConnectionsGocqhttpRelogin(c echo.Context) error {
return c.JSON(http.StatusNotFound, nil)
}

func ImConnectionsWalleQRelogin(c echo.Context) error {
if !doAuth(c) {
return c.JSON(http.StatusForbidden, nil)
}

v := struct {
Id string `form:"id" json:"id"`
}{}
err := c.Bind(&v)
if err == nil {
for _, i := range myDice.ImSession.EndPoints {
if i.Id == v.Id {
i.Adapter.DoRelogin()
return c.JSON(http.StatusOK, nil)
}
}
}
return c.JSON(http.StatusNotFound, nil)
}

func ImConnectionsAddDiscord(c echo.Context) error {
if !doAuth(c) {
return c.JSON(http.StatusForbidden, nil)
Expand Down Expand Up @@ -467,7 +538,7 @@ func ImConnectionsAdd(c echo.Context) error {

conn := dice.NewGoCqhttpConnectInfoItem(v.Account)
conn.UserId = dice.FormatDiceIdQQ(uid)
pa := conn.Adapter.(*dice.PlatformAdapterQQOnebot)
pa := conn.Adapter.(*dice.PlatformAdapterGocq)
pa.InPackGoCqHttpProtocol = v.Protocol
pa.InPackGoCqHttpPassword = v.Password
pa.Session = myDice.ImSession
Expand Down Expand Up @@ -670,10 +741,12 @@ func Bind(e *echo.Echo, _myDice *dice.DiceManager) {
e.POST(prefix+"/im_connections/addTelegram", ImConnectionsAddTelegram)
e.POST(prefix+"/im_connections/addMinecraft", ImConnectionsAddMinecraft)
e.POST(prefix+"/im_connections/addDodo", ImConnectionsAddDodo)
e.POST(prefix+"/im_connections/addWalleQ", ImConnectionsAddWalleQ)
e.POST(prefix+"/im_connections/del", ImConnectionsDel)
e.POST(prefix+"/im_connections/set_enable", ImConnectionsSetEnable)
e.POST(prefix+"/im_connections/set_data", ImConnectionsSetData)
e.POST(prefix+"/im_connections/gocqhttpRelogin", ImConnectionsGocqhttpRelogin)
e.POST(prefix+"/im_connections/walleQRelogin", ImConnectionsWalleQRelogin)

e.GET(prefix+"/configs/customText", customText)
e.POST(prefix+"/configs/customText/save", customTextSave)
Expand Down
2 changes: 1 addition & 1 deletion dice/dice_backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func (dm *DiceManager) Backup(cfg AllBackupConfig, bakFilename string) (string,
if cfg2.Accounts {
for _, i := range d.ImSession.EndPoints {
if i.Platform == "QQ" {
pa := i.Adapter.(*PlatformAdapterQQOnebot)
pa := i.Adapter.(*PlatformAdapterGocq)
if pa.UseInPackGoCqhttp {
backup(d, filepath.Join(d.BaseConfig.DataDir, i.RelWorkDir, "config.yml"))
backup(d, filepath.Join(d.BaseConfig.DataDir, i.RelWorkDir, "device.json"))
Expand Down
2 changes: 1 addition & 1 deletion dice/dice_ban.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (i *BanListInfo) AddScoreBase(uid string, score int64, place string, reason
v.BanTime = time.Now().Unix()

if ctx.EndPoint.Platform == "QQ" {
ctx.EndPoint.Adapter.(*PlatformAdapterQQOnebot).DeleteFriend(ctx, place)
ctx.EndPoint.Adapter.(*PlatformAdapterGocq).DeleteFriend(ctx, place)
}
}

Expand Down
111 changes: 19 additions & 92 deletions dice/gocqhttp_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/ShiraazMoollatjie/goluhn"
"github.com/acarl005/stripansi"
"github.com/fy0/procs"
"github.com/google/uuid"
"math/rand"
"os"
"path/filepath"
"regexp"
"runtime/debug"
"strings"
"time"

"github.com/ShiraazMoollatjie/goluhn"
"github.com/acarl005/stripansi"
"github.com/fy0/procs"
"github.com/google/uuid"
)

type deviceFile struct {
Expand Down Expand Up @@ -372,7 +373,7 @@ func NewGoCqhttpConnectInfoItem(account string) *EndPointInfo {
conn.Enable = false
conn.RelWorkDir = "extra/go-cqhttp-qq" + account

conn.Adapter = &PlatformAdapterQQOnebot{
conn.Adapter = &PlatformAdapterGocq{
EndPoint: conn,
UseInPackGoCqhttp: true,
}
Expand All @@ -388,7 +389,7 @@ func GoCqHttpServeProcessKill(dice *Dice, conn *EndPointInfo) {
}
}()

pa, ok := conn.Adapter.(*PlatformAdapterQQOnebot)
pa, ok := conn.Adapter.(*PlatformAdapterGocq)
if !ok {
return
}
Expand Down Expand Up @@ -429,14 +430,14 @@ func GoCqHttpServeRemoveSessionToken(dice *Dice, conn *EndPointInfo) {
}

func GoCqHttpServe(dice *Dice, conn *EndPointInfo, password string, protocol int, isAsyncRun bool) {
pa := conn.Adapter.(*PlatformAdapterQQOnebot)
//if pa.GoCqHttpState != GoCqHttpStateCodeInit {
pa := conn.Adapter.(*PlatformAdapterGocq)
//if pa.GoCqHttpState != StateCodeInit {
// return
//}

pa.CurLoginIndex += 1
loginIndex := pa.CurLoginIndex
pa.GoCqHttpState = GoCqHttpStateCodeInLogin
pa.GoCqHttpState = StateCodeInLogin

fmt.Println("GoCqHttpServe begin")
workDir := filepath.Join(dice.BaseConfig.DataDir, conn.RelWorkDir)
Expand Down Expand Up @@ -516,13 +517,13 @@ func GoCqHttpServe(dice *Dice, conn *EndPointInfo, password string, protocol int
// 获取二维码失败,登录失败
if strings.Contains(line, "fetch qrcode error: Packet timed out ") {
dice.Logger.Infof("从QQ服务器获取二维码错误(超时),帐号: <%s>(%s)", conn.Nickname, conn.UserId)
pa.GoCqHttpState = GoCqHttpStateCodeLoginFailed
pa.GoCqHttpState = StateCodeLoginFailed
}

// 未知错误,gocqhttp崩溃
if strings.Contains(line, "Packet failed to sendPacket: connection closed") {
dice.Logger.Infof("登录异常,gocqhttp崩溃")
pa.GoCqHttpState = GoCqHttpStateCodeLoginFailed
pa.GoCqHttpState = StateCodeLoginFailed
}

if strings.Contains(line, "WARNING") && strings.Contains(line, "账号已开启设备锁,请前往") {
Expand All @@ -531,7 +532,7 @@ func GoCqHttpServe(dice *Dice, conn *EndPointInfo, password string, protocol int
dice.Logger.Info("触发设备锁流程: ", len(m) > 0)
if len(m) > 0 {
// 设备锁流程,因为需要重新登录,进行一个“已成功登录过”的标记,这样配置文件不会被删除
pa.GoCqHttpState = GoCqHttpStateCodeInLoginDeviceLock
pa.GoCqHttpState = StateCodeInLoginDeviceLock
pa.GoCqHttpLoginSucceeded = true
pa.GoCqHttpLoginDeviceLockUrl = m[1]
fmt.Println("??????????????????? why")
Expand All @@ -544,15 +545,15 @@ func GoCqHttpServe(dice *Dice, conn *EndPointInfo, password string, protocol int
}

if strings.Contains(line, "发送验证码失败,可能是请求过于频繁.") {
pa.GoCqHttpState = GoCqHttpStateCodeLoginFailed
pa.GoCqHttpState = StateCodeLoginFailed
pa.GocqhttpLoginFailedReason = "发送验证码失败,可能是请求过于频繁"
}

// 登录成功
if strings.Contains(line, "CQ WebSocket 服务器已启动") {
// CQ WebSocket 服务器已启动
// 登录成功 欢迎使用
pa.GoCqHttpState = GoCqHttpStateCodeLoginSuccessed
pa.GoCqHttpState = StateCodeLoginSuccessed
pa.GoCqHttpLoginSucceeded = true
dice.Logger.Infof("gocqhttp登录成功,帐号: <%s>(%s)", conn.Nickname, conn.UserId)

Expand Down Expand Up @@ -650,13 +651,13 @@ func GoCqHttpServe(dice *Dice, conn *EndPointInfo, password string, protocol int
fmt.Println("如控制台二维码不好扫描,可以手动打开 ./data/default/extra/go-cqhttp-qqXXXXX 目录下qrcode.png")
qrdata, err := os.ReadFile(qrcodeFile)
if err == nil {
pa.GoCqHttpState = GoCqHttpStateCodeInLoginQrCode
pa.GoCqHttpState = StateCodeInLoginQrCode
pa.GoCqHttpQrcodeData = qrdata
dice.Logger.Info("获取二维码成功")
_ = os.Rename(qrcodeFile, qrcodeFile+".bak.png")
} else {
pa.GoCqHttpQrcodeData = nil
pa.GoCqHttpState = GoCqHttpStateCodeLoginFailed
pa.GoCqHttpState = StateCodeLoginFailed
pa.GocqhttpLoginFailedReason = "获取二维码失败"
dice.Logger.Info("获取二维码失败,错误为: ", err.Error())
}
Expand Down Expand Up @@ -685,14 +686,14 @@ func GoCqHttpServe(dice *Dice, conn *EndPointInfo, password string, protocol int
}

isInLogin := pa.IsInLogin()
isDeviceLockLogin := pa.GoCqHttpState == GoCqHttpStateCodeInLoginDeviceLock
isDeviceLockLogin := pa.GoCqHttpState == StateCodeInLoginDeviceLock
if !isDeviceLockLogin {
// 如果在设备锁流程中,不清空数据
GoCqHttpServeProcessKill(dice, conn)

if isInLogin {
conn.State = 3
pa.GoCqHttpState = GoCqHttpStateCodeLoginFailed
pa.GoCqHttpState = StateCodeLoginFailed
}
}

Expand All @@ -709,77 +710,3 @@ func GoCqHttpServe(dice *Dice, conn *EndPointInfo, password string, protocol int
run()
}
}

// 注意:放在这里并不科学,记得重构
func ServeQQ(d *Dice, ep *EndPointInfo) {
defer CrashLog()
if ep.Platform == "QQ" {
conn := ep.Adapter.(*PlatformAdapterQQOnebot)

if !conn.DiceServing {
conn.DiceServing = true
} else {
return
}

ep.Enable = true
ep.State = 2 // 连接中

checkQuit := func() bool {
if conn.GoCqHttpState == GoCqHttpStateCodeInLoginDeviceLock {
d.Logger.Infof("检测到设备锁流程,暂时不再连接")
ep.State = 0
return true
}
if !conn.DiceServing {
// 退出连接
d.Logger.Infof("检测到连接关闭,不再进行此onebot服务的重连: <%s>(%s)", ep.Nickname, ep.UserId)
return true
}
return false
}

lastRetryTime := time.Now().Unix()
waitTimes := 0
for {
if checkQuit() {
break
}

// 骰子开始连接
d.Logger.Infof("开始连接 onebot 服务,帐号 <%s>(%s),重试计数[%d/%d]", ep.Nickname, ep.UserId, waitTimes, 5)
ret := ep.Adapter.Serve()

if time.Now().Unix()-lastRetryTime > 8*60 {
lastRetryTime = 0
}
lastRetryTime = time.Now().Unix()

if ret == 0 {
break
}

if checkQuit() {
break
}

waitTimes += 1
if waitTimes > 5 {
d.Logger.Infof("onebot 连接重试次数过多,先行中断: <%s>(%s)", ep.Nickname, ep.UserId)
conn.DiceServing = false
break
}

//d.Logger.Infof("onebot 连接失败[%d/%d],将在15秒后重新连接,帐号 <%s>(%s)", waitTimes, 5, ep.Nickname, ep.UserId)
time.Sleep(15 * time.Second)
}
}
}

func GetAndroidDeviceTemplateName() []string {
names := []string{}
for _, i := range androidDevicePool {
names = append(names, i.name)
}
return names
}
Loading

0 comments on commit 2c093f8

Please sign in to comment.