Skip to content

Commit

Permalink
feat: support external onebot impl
Browse files Browse the repository at this point in the history
  • Loading branch information
IllTamer committed Jul 19, 2024
1 parent 691b80e commit 1817897
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 44 deletions.
3 changes: 2 additions & 1 deletion cmd/perpe/agent.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package perp

import (
"time"

global "github.com/IUnlimit/perpetua/internal"
"github.com/IUnlimit/perpetua/internal/handle"
"github.com/bytedance/gopkg/util/gopool"
log "github.com/sirupsen/logrus"
"time"
)

func EnableAgent() {
Expand Down
29 changes: 25 additions & 4 deletions cmd/perpe/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package perp

import (
"fmt"
"os"

"github.com/IUnlimit/perpetua/configs"
"github.com/IUnlimit/perpetua/internal"
global "github.com/IUnlimit/perpetua/internal"
"github.com/IUnlimit/perpetua/internal/conf"
"github.com/IUnlimit/perpetua/internal/hook/qqimpl"
"github.com/IUnlimit/perpetua/internal/model"
"github.com/IUnlimit/perpetua/internal/utils"
log "github.com/sirupsen/logrus"
"os"
)

// Configure NTQQ settings using config.yml
Expand All @@ -20,9 +22,28 @@ func Configure() {

config := global.Config
lgrFolder := global.ParentPath + "/" + global.LgrFolder
global.ImplType = model.EMBED

// check impl type
lgrWS := config.NTQQImpl.ExternalWebSocket
if lgrWS != "" {
<-utils.WaitExternalNTQQStartup(lgrWS, 5, func(alive bool) {
if alive {
log.Info("External NTQQ connection successful: ", lgrWS)
global.ImplType = model.EXTERNAL
}
}, func(err2 error) {
log.Debugf("Wait External-NTQQ startup: %v", err2)
})

if global.ImplType == model.EXTERNAL {
return
}
log.Warn("External NTQQ connect failed, try to start EMBED")
}

log.Info("Searching Lagrange.OneBot ...")
err := qqimpl.InitLagrange(lgrFolder, config.NTQQImpl.Update)
err := qqimpl.InitLagrange(lgrFolder, config.NTQQImpl.Update.Enable)
if err != nil {
log.Fatalf("Lagrange.OneBot init error %v", err)
}
Expand All @@ -33,7 +54,7 @@ func Configure() {
log.Fatalf("Failed to load lgr config: %v", err)
}
if !exists {
log.Info("Default `appsettings.json` has been generated, please configure and restart perpetua (See https://github.com/LagrangeDev/Lagrange.Core?tab=readme-ov-file#appsettingsjson-example)")
log.Info("Default `appsettings.json` has been generated, please configure and restart perpetua (See https://github.com/LagrangeDev/Lagrange.Core?tab=readme-ov-file#signserver)")
os.Exit(0)
}
}
Expand Down
14 changes: 10 additions & 4 deletions cmd/perpe/main.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package perp

import "github.com/bytedance/gopkg/util/gopool"
import (
global "github.com/IUnlimit/perpetua/internal"
"github.com/IUnlimit/perpetua/internal/model"
"github.com/bytedance/gopkg/util/gopool"
)

func Bootstrap() {
Configure()
gopool.Go(func() {
Start()
})
if global.ImplType == model.EMBED {
gopool.Go(func() {
Start()
})
}
EnableAgent()
}
21 changes: 16 additions & 5 deletions configs/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,20 @@ log:
# 是否开启控制台颜色
colorful: true

# 本配置项自动更新,无需手动
ntqq-impl:
update: false
id: 0
platform: ""
updated-at: "0001-01-01T00:00:00Z"
# 外置 onebot-11 实现的正向 ws 地址
# 手动指定 ntqq 实现的正向 ws 地址(docker 部署或连接到外置NTQQ实现时使用)
# 若检测不到,则自动开始加载内置 NTQQ 逻辑
external-web-socket: "ws://127.0.0.1:5700/onebot/v11/ws"
# 外置 onebot-11 实现的 AccessToken
# 仅在配置了 external-web-socket 时生效
external-access-token: ""
# 以下配置项除 enable 外自动更新,无需手动变动
update:
enable: false
id: 0
platform: ""
updated-at: "0001-01-01T00:00:00Z"

# http 相关配置
http:
Expand All @@ -46,13 +54,16 @@ web-socket:
end: 8110

# 反向 websocket 相关配置
# 注:是由 perpetua 主动向上报地址发起反向 ws 连接
# 使用场景举例:perpetua 在启动后主动连接到 nonebot
reverse-web-socket:
# 上报地址
- url: ''
# AccessToken
access-token: ''

# http post 相关配置
# 注:是由 perpetua 主动向上报地址上报事件
http-post:
# 上报地址
- url: ''
Expand Down
9 changes: 5 additions & 4 deletions internal/conf/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import (
"embed"
"encoding/json"
"errors"
"os"
"regexp"

"github.com/IUnlimit/perpetua/configs"
global "github.com/IUnlimit/perpetua/internal"
"github.com/IUnlimit/perpetua/internal/model"
"github.com/IUnlimit/perpetua/internal/utils"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
"os"
"regexp"
)

// LoadConfig creat and load config, return exists(file)
Expand Down Expand Up @@ -66,8 +67,8 @@ func UpdateConfig(artifact *model.Artifact) error {
}

config := global.Config
config.NTQQImpl = &model.NTQQImpl{
Update: config.NTQQImpl.Update,
config.NTQQImpl.Update = &model.Update{
Enable: config.NTQQImpl.Update.Enable,
ID: artifact.ID,
Platform: platform,
UpdatedAt: artifact.UpdatedAt,
Expand Down
6 changes: 5 additions & 1 deletion internal/global.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package global

import (
"github.com/IUnlimit/perpetua/internal/model"
"os"
"regexp"

"github.com/IUnlimit/perpetua/internal/model"
)

// MsgData websocket message data type
Expand All @@ -18,6 +19,9 @@ const LgrFolder = "Lagrange.OneBot/"
// EchoPrefix is prefix for generating echos
const EchoPrefix = "perp"

// The NTQQ impl connection type
var ImplType model.ImplType

// Restart marks whether the end status of the process is restarted
var Restart bool

Expand Down
36 changes: 24 additions & 12 deletions internal/handle/serve_websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,43 @@ import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"

global "github.com/IUnlimit/perpetua/internal"
"github.com/IUnlimit/perpetua/internal/model"
"github.com/IUnlimit/perpetua/internal/utils"
"github.com/bytedance/gopkg/util/gopool"
"github.com/gorilla/websocket"
log "github.com/sirupsen/logrus"
"net/http"
"strings"
)

func CreateNTQQWebSocket() error {
var handle = NewHandler(context.Background())
handle.AddWait()
impl, err := utils.GetForwardImpl()
if err != nil {
return err

var wsUrl string
var accessToken string
if global.ImplType == model.EXTERNAL {
config := global.Config.NTQQImpl
wsUrl = config.ExternalWebSocket
accessToken = config.ExternalAccessToken
} else { // EMBED
impl, err := utils.GetForwardImpl()
if err != nil {
return err
}
wsUrl = fmt.Sprintf("ws://%s:%d/%s", impl.Host, impl.Port, impl.Suffix)
accessToken = impl.AccessToken

log.Info("[NTQQ] Start connecting to NTQQ websocket: ", wsUrl)
<-utils.WaitNTQQStartup(impl.Host, impl.Port, func(err2 error) {
log.Debugf("Wait NTQQ startup: %v", err2)
})
}

request, _ := http.NewRequest("GET", "", nil)
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", impl.AccessToken))
wsUrl := fmt.Sprintf("ws://%s:%d/%s", impl.Host, impl.Port, impl.Suffix)

log.Info("[NTQQ] Start connecting to NTQQ websocket: ", wsUrl)
<-utils.WaitNTQQStartup(impl.Host, impl.Port, func(err2 error) {
log.Debugf("Wait NTQQ startup: %v", err2)
})
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
conn, _, err := websocket.DefaultDialer.Dial(wsUrl, request.Header)
if err != nil {
return err
Expand Down
7 changes: 7 additions & 0 deletions internal/model/api.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package model

type ImplType string

const (
EMBED = ImplType("EMBED")
EXTERNAL = ImplType("EXTERNAL")
)

type Client struct {
// 客户端ID
AppId string `json:"app_id"`
Expand Down
14 changes: 10 additions & 4 deletions internal/model/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ type Log struct {
}

type NTQQImpl struct {
Update bool `yaml:"update,omitempty"`
ID int64 `yaml:"id,omitempty"`
Platform string `yaml:"platform,omitempty"`
UpdatedAt time.Time `yaml:"updated-at"`
ExternalWebSocket string `yaml:"external-web-socket,omitempty"`
ExternalAccessToken string `yaml:"external-access-token,omitempty"`
Update *Update `yaml:"update"`
}

type Http struct {
Expand All @@ -45,6 +44,13 @@ type HttpPost struct {
Secret string `yaml:"secret,omitempty"`
}

type Update struct {
Enable bool `yaml:"enable,omitempty"`
ID int64 `yaml:"id,omitempty"`
Platform string `yaml:"platform,omitempty"`
UpdatedAt time.Time `yaml:"updated-at"`
}

type RangePort struct {
Enabled bool `yaml:"enabled,omitempty"`
Start int `yaml:"start,omitempty"`
Expand Down
25 changes: 22 additions & 3 deletions internal/utils/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package utils
import (
"errors"
"fmt"
"time"

global "github.com/IUnlimit/perpetua/internal"
"github.com/IUnlimit/perpetua/internal/model"
"github.com/bytedance/gopkg/util/gopool"
"time"
)

func BuildWSGoodResponse(status string, echo string, entry ...any) global.MsgData {
Expand Down Expand Up @@ -54,7 +55,25 @@ func WaitNTQQStartup(host string, port int, waitCallback func(error)) <-chan str
}, waitCallback)
}

func WaitCondition(gap time.Duration, condition func() error, waitCallback func(error)) <-chan struct{} {
// WaitExternalNTQQStartup wait for external NTQQ websocket connection to be enabled
func WaitExternalNTQQStartup(ws string, timeoutSeconds int, connectCallback func(bool), waitCallback func(error)) <-chan struct{} {
seconds := -1
return WaitCondition(time.Duration(1000), func() error {
seconds++
if seconds >= timeoutSeconds {
connectCallback(false)
return nil
}
err := CheckWebsocket(ws, time.Second*1)
if err != nil {
return err
}
connectCallback(true)
return nil
}, waitCallback)
}

func WaitCondition(gapedMillisecond time.Duration, condition func() error, waitCallback func(error)) <-chan struct{} {
done := make(chan struct{})

gopool.Go(func() {
Expand All @@ -66,7 +85,7 @@ func WaitCondition(gap time.Duration, condition func() error, waitCallback func(
if waitCallback != nil {
waitCallback(err)
}
time.Sleep(time.Millisecond * gap)
time.Sleep(time.Millisecond * gapedMillisecond)
}
close(done)
})
Expand Down
27 changes: 21 additions & 6 deletions internal/utils/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ package utils
import (
"encoding/json"
"fmt"
"github.com/IUnlimit/perpetua/internal/erren"
"github.com/IUnlimit/perpetua/internal/model"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"io"
"net"
"net/http"
"net/url"
"os"
"time"

"github.com/IUnlimit/perpetua/internal/erren"
"github.com/IUnlimit/perpetua/internal/model"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"

"github.com/cheggaaa/pb/v3"
)

Expand Down Expand Up @@ -101,6 +103,19 @@ func CheckPort(host string, port int, timeout time.Duration) error {
return nil
}

func CheckWebsocket(ws string, timeout time.Duration) error {
dialer := websocket.Dialer{
HandshakeTimeout: timeout,
}

conn, _, err := dialer.Dial(ws, http.Header{})
if err != nil {
return err
}
defer conn.Close()
return nil
}

// BadResponse Return error status code and error message
func BadResponse(c *gin.Context, err error) {
Err := erren.ConvertErr(err)
Expand Down Expand Up @@ -142,7 +157,7 @@ func download(resp *http.Response, filePath string, fileSize int64) error {
if fileSize == -1 {
fileSize = resp.ContentLength
}
log.Debug("Download content length: %d", fileSize)
log.Debugf("Download content length: %d", fileSize)

file, err := os.Create(filePath)
if err != nil {
Expand Down
Loading

0 comments on commit 1817897

Please sign in to comment.