1
0
mirror of https://github.com/Mrs4s/go-cqhttp.git synced 2025-05-04 19:17:37 +08:00

Merge branch 'dev' into database-support

# Conflicts:
#	main.go
This commit is contained in:
wdvxdr 2021-10-10 22:34:53 +08:00
commit 69a187ddd7
No known key found for this signature in database
GPG Key ID: 703F8C071DE7A1B6
11 changed files with 181 additions and 119 deletions

View File

@ -14,6 +14,8 @@ RUN set -ex \
FROM alpine:latest FROM alpine:latest
RUN apk add --no-cache ffmpeg
COPY --from=builder /build/cqhttp /usr/bin/cqhttp COPY --from=builder /build/cqhttp /usr/bin/cqhttp
RUN chmod +x /usr/bin/cqhttp RUN chmod +x /usr/bin/cqhttp

View File

@ -29,3 +29,9 @@ var (
func nocheck(_ io.ReadSeeker) (bool, string) { func nocheck(_ io.ReadSeeker) (bool, string) {
return true, "" return true, ""
} }
// todo: enable in v1.1.0
// onebot v12 feature
const (
AcceptOneBotV12HTTPEndPoint = false
)

View File

@ -3,8 +3,12 @@ package base
import ( import (
"flag" "flag"
"fmt"
"os" "os"
"os/exec"
"path" "path"
"path/filepath"
"strings"
"time" "time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -17,7 +21,7 @@ import (
var ( var (
LittleC string // config file LittleC string // config file
LittleD bool // daemon LittleD bool // daemon
LittleH bool // help LittleH bool // Help
LittleWD string // working directory LittleWD string // working directory
) )
@ -55,7 +59,7 @@ func Parse() {
dc := path.Join(wd, "config.yml") dc := path.Join(wd, "config.yml")
flag.StringVar(&LittleC, "c", dc, "configuration filename") flag.StringVar(&LittleC, "c", dc, "configuration filename")
flag.BoolVar(&LittleD, "d", false, "running as a daemon") flag.BoolVar(&LittleD, "d", false, "running as a daemon")
flag.BoolVar(&LittleH, "h", false, "this help") flag.BoolVar(&LittleH, "h", false, "this Help")
flag.StringVar(&LittleWD, "w", "", "cover the working directory") flag.StringVar(&LittleWD, "w", "", "cover the working directory")
d := flag.Bool("D", false, "debug mode") d := flag.Bool("D", false, "debug mode")
flag.Parse() flag.Parse()
@ -105,3 +109,40 @@ func Init() {
} }
} }
} }
// Help cli命令行-h的帮助提示
func Help() {
fmt.Printf(`go-cqhttp service
version: %s
Usage:
server [OPTIONS]
Options:
`, Version)
flag.PrintDefaults()
os.Exit(0)
}
// ResetWorkingDir 重设工作路径
func ResetWorkingDir() {
wd := LittleWD
args := make([]string, 0, len(os.Args))
for i := 1; i < len(os.Args); i++ {
if os.Args[i] == "-w" {
i++ // skip value field
} else if !strings.HasPrefix(os.Args[i], "-w") {
args = append(args, os.Args[i])
}
}
p, _ := filepath.Abs(os.Args[0])
proc := exec.Command(p, args...)
proc.Stdin = os.Stdin
proc.Stdout = os.Stdout
proc.Stderr = os.Stderr
proc.Dir = wd
err := proc.Run()
if err != nil {
panic(err)
}
os.Exit(0)
}

95
main.go
View File

@ -5,13 +5,8 @@ import (
"crypto/md5" "crypto/md5"
"crypto/sha1" "crypto/sha1"
"encoding/hex" "encoding/hex"
"flag"
"fmt"
"os" "os"
"os/exec"
"path" "path"
"path/filepath"
"strings"
"sync" "sync"
"time" "time"
@ -29,7 +24,7 @@ import (
"github.com/Mrs4s/go-cqhttp/internal/base" "github.com/Mrs4s/go-cqhttp/internal/base"
"github.com/Mrs4s/go-cqhttp/internal/cache" "github.com/Mrs4s/go-cqhttp/internal/cache"
"github.com/Mrs4s/go-cqhttp/internal/selfupdate" "github.com/Mrs4s/go-cqhttp/internal/selfupdate"
"github.com/Mrs4s/go-cqhttp/modules/config" "github.com/Mrs4s/go-cqhttp/modules/servers"
"github.com/Mrs4s/go-cqhttp/server" "github.com/Mrs4s/go-cqhttp/server"
_ "github.com/Mrs4s/go-cqhttp/modules/mime" // mime检查模块 _ "github.com/Mrs4s/go-cqhttp/modules/mime" // mime检查模块
@ -49,11 +44,11 @@ func main() {
base.Parse() base.Parse()
switch { switch {
case base.LittleH: case base.LittleH:
help() base.Help()
case base.LittleD: case base.LittleD:
server.Daemon() server.Daemon()
case base.LittleWD != "": case base.LittleWD != "":
resetWorkDir() base.ResetWorkingDir()
} }
base.Init() base.Init()
@ -332,49 +327,8 @@ func main() {
base.Account.Status = 0 base.Account.Status = 0
} }
cli.SetOnlineStatus(allowStatus[base.Account.Status]) cli.SetOnlineStatus(allowStatus[base.Account.Status])
bot := coolq.NewQQBot(cli)
for _, m := range base.Servers { servers.Run(coolq.NewQQBot(cli))
if h, ok := m["http"]; ok {
hc := new(config.HTTPServer)
if err := h.Decode(hc); err != nil {
log.Warn("读取http配置失败 :", err)
} else if !hc.Disabled {
go server.RunHTTPServerAndClients(bot, hc)
}
}
if s, ok := m["ws"]; ok {
sc := new(config.WebsocketServer)
if err := s.Decode(sc); err != nil {
log.Warn("读取正向Websocket配置失败 :", err)
} else if !sc.Disabled {
go server.RunWebSocketServer(bot, sc)
}
}
if c, ok := m["ws-reverse"]; ok {
rc := new(config.WebsocketReverse)
if err := c.Decode(rc); err != nil {
log.Warn("读取反向Websocket配置失败 :", err)
} else if !rc.Disabled {
go server.RunWebSocketClient(bot, rc)
}
}
if p, ok := m["pprof"]; ok {
pc := new(config.PprofServer)
if err := p.Decode(pc); err != nil {
log.Warn("读取pprof配置失败 :", err)
} else if !pc.Disabled {
go server.RunPprofServer(pc)
}
}
if p, ok := m["lambda"]; ok {
lc := new(config.LambdaServer)
if err := p.Decode(lc); err != nil {
log.Warn("读取pprof配置失败 :", err)
} else if !lc.Disabled {
go server.RunLambdaClient(bot, lc)
}
}
}
log.Info("资源初始化完成, 开始处理信息.") log.Info("资源初始化完成, 开始处理信息.")
log.Info("アトリは、高性能ですから!") log.Info("アトリは、高性能ですから!")
@ -414,45 +368,6 @@ func PasswordHashDecrypt(encryptedPasswordHash string, key []byte) ([]byte, erro
return result, nil return result, nil
} }
// help cli命令行-h的帮助提示
func help() {
fmt.Printf(`go-cqhttp service
version: %s
Usage:
server [OPTIONS]
Options:
`, base.Version)
flag.PrintDefaults()
os.Exit(0)
}
func resetWorkDir() {
wd := base.LittleWD
args := make([]string, 0, len(os.Args))
for i := 1; i < len(os.Args); i++ {
if os.Args[i] == "-w" {
i++ // skip value field
} else if !strings.HasPrefix(os.Args[i], "-w") {
args = append(args, os.Args[i])
}
}
p, _ := filepath.Abs(os.Args[0])
proc := exec.Command(p, args...)
proc.Stdin = os.Stdin
proc.Stdout = os.Stdout
proc.Stderr = os.Stderr
proc.Dir = wd
err := proc.Run()
if err != nil {
panic(err)
}
os.Exit(0)
}
func newClient() *client.QQClient { func newClient() *client.QQClient {
c := client.NewClientEmpty() c := client.NewClientEmpty()
c.OnServerUpdated(func(bot *client.QQClient, e *client.ServerUpdatedEvent) bool { c.OnServerUpdated(func(bot *client.QQClient, e *client.ServerUpdatedEvent) bool {

View File

@ -0,0 +1,31 @@
// Package servers provide servers register
package servers
import (
"gopkg.in/yaml.v3"
"github.com/Mrs4s/go-cqhttp/coolq"
"github.com/Mrs4s/go-cqhttp/internal/base"
)
var svr = make(map[string]func(*coolq.CQBot, yaml.Node))
// Register 注册 Server
func Register(name string, proc func(*coolq.CQBot, yaml.Node)) {
_, ok := svr[name]
if ok {
panic(name + " server has existed")
}
svr[name] = proc
}
// Run 运行所有svr
func Run(bot *coolq.CQBot) {
for _, l := range base.Servers {
for name, conf := range l {
if fn, ok := svr[name]; ok {
go fn(bot, conf)
}
}
}
}

View File

@ -1,2 +1,13 @@
// Package server 包含HTTP,WebSocket,反向WebSocket请求处理的相关函数与结构体 // Package server 包含HTTP,WebSocket,反向WebSocket请求处理的相关函数与结构体
package server package server
import "github.com/Mrs4s/go-cqhttp/modules/servers"
// 注册
func init() {
servers.Register("http", runHTTP)
servers.Register("ws", runWSServer)
servers.Register("ws-reverse", runWSClient)
servers.Register("pprof", runPprof)
servers.Register("lambda", runLambda)
}

View File

@ -19,8 +19,11 @@ import (
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
"gopkg.in/yaml.v3"
"github.com/Mrs4s/go-cqhttp/coolq" "github.com/Mrs4s/go-cqhttp/coolq"
"github.com/Mrs4s/go-cqhttp/global"
"github.com/Mrs4s/go-cqhttp/internal/base"
"github.com/Mrs4s/go-cqhttp/modules/config" "github.com/Mrs4s/go-cqhttp/modules/config"
) )
@ -114,14 +117,21 @@ func (s *httpServer) ServeHTTP(writer http.ResponseWriter, request *http.Request
return return
} }
action := strings.TrimPrefix(request.URL.Path, "/") var response global.MSG
action = strings.TrimSuffix(action, "_async") if base.AcceptOneBotV12HTTPEndPoint && request.URL.Path == "/" {
log.Debugf("HTTPServer接收到API调用: %v", action) action := strings.TrimSuffix(ctx.Get("action").Str, "_async")
ret := s.api.callAPI(action, &ctx) log.Debugf("HTTPServer接收到API调用: %v", action)
response = s.api.callAPI(action, ctx.Get("params"))
} else {
action := strings.TrimPrefix(request.URL.Path, "/")
action = strings.TrimSuffix(action, "_async")
log.Debugf("HTTPServer接收到API调用: %v", action)
response = s.api.callAPI(action, &ctx)
}
writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.Header().Set("Content-Type", "application/json; charset=utf-8")
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
_ = json.NewEncoder(writer).Encode(ret) _ = json.NewEncoder(writer).Encode(response)
} }
func checkAuth(req *http.Request, token string) int { func checkAuth(req *http.Request, token string) int {
@ -149,13 +159,19 @@ func checkAuth(req *http.Request, token string) int {
} }
} }
// RunHTTPServerAndClients 启动HTTP服务器与HTTP上报客户端 // runHTTP 启动HTTP服务器与HTTP上报客户端
func RunHTTPServerAndClients(bot *coolq.CQBot, conf *config.HTTPServer) { func runHTTP(bot *coolq.CQBot, node yaml.Node) {
var ( var conf config.HTTPServer
s = new(httpServer) switch err := node.Decode(&conf); {
addr string case err != nil:
) log.Warn("读取http配置失败 :", err)
s.accessToken = conf.AccessToken fallthrough
case conf.Disabled:
return
}
var addr string
s := &httpServer{accessToken: conf.AccessToken}
if conf.Host == "" || conf.Port == 0 { if conf.Host == "" || conf.Port == 0 {
goto client goto client
} }

View File

@ -5,7 +5,6 @@ import (
"context" "context"
"os" "os"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/Mrs4s/go-cqhttp/coolq" "github.com/Mrs4s/go-cqhttp/coolq"
@ -76,7 +75,7 @@ func longPolling(bot *coolq.CQBot, maxSize int) handler {
return nil return nil
} }
var ( var (
ok int32 once sync.Once
ch = make(chan []interface{}, 1) ch = make(chan []interface{}, 1)
timeout = time.Duration(p.Get("timeout").Int()) * time.Second timeout = time.Duration(p.Get("timeout").Int()) * time.Second
) )
@ -87,7 +86,7 @@ func longPolling(bot *coolq.CQBot, maxSize int) handler {
if queue.Len() == 0 { if queue.Len() == 0 {
cond.Wait() cond.Wait()
} }
if atomic.CompareAndSwapInt32(&ok, 0, 1) { once.Do(func() {
limit := int(p.Get("limit").Int()) limit := int(p.Get("limit").Int())
if limit <= 0 || queue.Len() < limit { if limit <= 0 || queue.Len() < limit {
limit = queue.Len() limit = queue.Len()
@ -97,12 +96,12 @@ func longPolling(bot *coolq.CQBot, maxSize int) handler {
ret[i] = queue.Remove(queue.Front()) ret[i] = queue.Remove(queue.Front())
} }
ch <- ret ch <- ret
} })
}() }()
if timeout != 0 { if timeout != 0 {
select { select {
case <-time.After(timeout): case <-time.After(timeout):
atomic.StoreInt32(&ok, 1) once.Do(func() {})
return coolq.OK([]interface{}{}) return coolq.OK([]interface{}{})
case ret := <-ch: case ret := <-ch:
return coolq.OK(ret) return coolq.OK(ret)

View File

@ -8,12 +8,23 @@ import (
"time" "time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
"github.com/Mrs4s/go-cqhttp/coolq"
"github.com/Mrs4s/go-cqhttp/modules/config" "github.com/Mrs4s/go-cqhttp/modules/config"
) )
// RunPprofServer 启动 pprof 性能分析服务器 // runPprof 启动 pprof 性能分析服务器
func RunPprofServer(conf *config.PprofServer) { func runPprof(_ *coolq.CQBot, node yaml.Node) {
var conf config.PprofServer
switch err := node.Decode(&conf); {
case err != nil:
log.Warn("读取pprof配置失败 :", err)
fallthrough
case conf.Disabled:
return
}
addr := fmt.Sprintf("%s:%d", conf.Host, conf.Port) addr := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
mux := http.NewServeMux() mux := http.NewServeMux()
mux.HandleFunc("/debug/pprof/", pprof.Index) mux.HandleFunc("/debug/pprof/", pprof.Index)

View File

@ -13,6 +13,7 @@ import (
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
"github.com/Mrs4s/go-cqhttp/coolq" "github.com/Mrs4s/go-cqhttp/coolq"
"github.com/Mrs4s/go-cqhttp/global" "github.com/Mrs4s/go-cqhttp/global"
@ -77,8 +78,17 @@ func (l *lambdaResponseWriter) WriteHeader(statusCode int) {
var cli *lambdaClient var cli *lambdaClient
// RunLambdaClient type: [scf,aws] // runLambda type: [scf,aws]
func RunLambdaClient(bot *coolq.CQBot, conf *config.LambdaServer) { func runLambda(bot *coolq.CQBot, node yaml.Node) {
var conf config.LambdaServer
switch err := node.Decode(&conf); {
case err != nil:
log.Warn("读取lambda配置失败 :", err)
fallthrough
case conf.Disabled:
return
}
cli = &lambdaClient{ cli = &lambdaClient{
lambdaType: conf.Type, lambdaType: conf.Type,
client: http.Client{Timeout: 0}, client: http.Client{Timeout: 0},

View File

@ -10,6 +10,8 @@ import (
"sync" "sync"
"time" "time"
"gopkg.in/yaml.v3"
"github.com/Mrs4s/go-cqhttp/coolq" "github.com/Mrs4s/go-cqhttp/coolq"
"github.com/Mrs4s/go-cqhttp/global" "github.com/Mrs4s/go-cqhttp/global"
"github.com/Mrs4s/go-cqhttp/modules/config" "github.com/Mrs4s/go-cqhttp/modules/config"
@ -54,11 +56,20 @@ var upgrader = websocket.Upgrader{
}, },
} }
// RunWebSocketServer 运行一个正向WS server // runWSServer 运行一个正向WS server
func RunWebSocketServer(b *coolq.CQBot, conf *config.WebsocketServer) { func runWSServer(b *coolq.CQBot, node yaml.Node) {
var conf config.WebsocketServer
switch err := node.Decode(&conf); {
case err != nil:
log.Warn("读取正向Websocket配置失败 :", err)
fallthrough
case conf.Disabled:
return
}
s := &webSocketServer{ s := &webSocketServer{
bot: b, bot: b,
conf: conf, conf: &conf,
token: conf.AccessToken, token: conf.AccessToken,
filter: conf.Filter, filter: conf.Filter,
} }
@ -77,11 +88,20 @@ func RunWebSocketServer(b *coolq.CQBot, conf *config.WebsocketServer) {
}() }()
} }
// RunWebSocketClient 运行一个正向WS client // runWSClient 运行一个反向向WS client
func RunWebSocketClient(b *coolq.CQBot, conf *config.WebsocketReverse) { func runWSClient(b *coolq.CQBot, node yaml.Node) {
var conf config.WebsocketReverse
switch err := node.Decode(&conf); {
case err != nil:
log.Warn("读取反向Websocket配置失败 :", err)
fallthrough
case conf.Disabled:
return
}
c := &websocketClient{ c := &websocketClient{
bot: b, bot: b,
conf: conf, conf: &conf,
token: conf.AccessToken, token: conf.AccessToken,
filter: conf.Filter, filter: conf.Filter,
} }