refactor: remove IO route mapping, add HTTP API tests, system prompt update

This commit is contained in:
root
2026-07-02 15:47:16 +08:00
parent 3d7d24ebb8
commit 304c3ae294
25 changed files with 3427 additions and 110 deletions

View File

@ -105,16 +105,19 @@ func (c *Client) reconnect() {
func (c *Client) readLoop() {
defer c.connected.Store(false)
defer c.mu.Lock()
defer c.mu.Unlock()
defer func() {
if c.conn != nil {
c.conn.Close()
}
}()
for {
_, message, err := c.conn.ReadMessage()
c.mu.Lock()
conn := c.conn
c.mu.Unlock()
if conn == nil {
log.Printf("[onebot] read loop: not connected")
go c.reconnect()
return
}
_, message, err := conn.ReadMessage()
if err != nil {
log.Printf("[onebot] read error: %v", err)
go c.reconnect()
@ -125,7 +128,10 @@ func (c *Client) readLoop() {
var resp ActionResponse
if err := json.Unmarshal(message, &resp); err == nil && resp.Echo != "" {
if ch, ok := c.pending.Load(resp.Echo); ok {
ch.(chan *ActionResponse) <- &resp
select {
case ch.(chan *ActionResponse) <- &resp:
default:
}
}
continue
}

View File

@ -189,9 +189,7 @@ func (d *Device) handleEvent(evt *Event) {
payload["label"] = fmt.Sprintf("private:%d", evt.UserID)
}
d.iom.InjectText(source, text)
// 同时注册输出路由:QQ 消息默认回复到 QQ 通道
d.iom.RegisterOutputRoute(source, d.name)
d.iom.InjectTextTo(source, d.name, text)
case "notice":
log.Printf("[onebot] notice from %s: type=%s", d.name, evt.NoticeType)

View File

@ -0,0 +1,165 @@
package onebot
import (
"encoding/json"
"testing"
)
func TestMessageText(t *testing.T) {
seg := MessageText("hello")
if seg.Type != "text" {
t.Errorf("expected type 'text', got %q", seg.Type)
}
if seg.Data["text"] != "hello" {
t.Errorf("expected data.text 'hello', got %q", seg.Data["text"])
}
}
func TestMessageImage(t *testing.T) {
seg := MessageImage("test.jpg")
if seg.Type != "image" {
t.Errorf("expected 'image', got %q", seg.Type)
}
if seg.Data["file"] != "test.jpg" {
t.Errorf("expected 'test.jpg', got %q", seg.Data["file"])
}
}
func TestMessageAt(t *testing.T) {
seg := MessageAt(123456)
if seg.Type != "at" {
t.Errorf("expected 'at', got %q", seg.Type)
}
if seg.Data["qq"] != "123456" {
t.Errorf("expected '123456', got %q", seg.Data["qq"])
}
}
func TestEventMarshal(t *testing.T) {
evt := Event{
Time: 1234567890,
SelfID: 10001,
PostType: "message",
MessageType: "group",
GroupID: 999,
UserID: 777,
RawMessage: "hello",
Sender: &Sender{
UserID: 777,
Nickname: "TestUser",
Role: "member",
},
}
data, err := json.Marshal(evt)
if err != nil {
t.Fatal(err)
}
var decoded Event
if err := json.Unmarshal(data, &decoded); err != nil {
t.Fatal(err)
}
if decoded.PostType != "message" {
t.Errorf("expected 'message', got %q", decoded.PostType)
}
if decoded.GroupID != 999 {
t.Errorf("expected 999, got %d", decoded.GroupID)
}
if decoded.Sender.Nickname != "TestUser" {
t.Errorf("expected 'TestUser', got %q", decoded.Sender.Nickname)
}
}
func TestEventMessagePrivate(t *testing.T) {
evt := Event{
PostType: "message",
MessageType: "private",
UserID: 123,
RawMessage: "hi",
}
if evt.PostType != "message" || evt.MessageType != "private" {
t.Errorf("unexpected event type: %s/%s", evt.PostType, evt.MessageType)
}
}
func TestActionMarshal(t *testing.T) {
action := Action{
Action: "send_private_msg",
Params: map[string]interface{}{
"user_id": 123,
"message": "hello",
},
Echo: "1",
}
data, err := json.Marshal(action)
if err != nil {
t.Fatal(err)
}
var decoded Action
if err := json.Unmarshal(data, &decoded); err != nil {
t.Fatal(err)
}
if decoded.Action != "send_private_msg" {
t.Errorf("expected 'send_private_msg', got %q", decoded.Action)
}
}
func TestActionResponse(t *testing.T) {
resp := ActionResponse{
Status: "ok",
RetCode: 0,
Data: map[string]interface{}{
"message_id": 12345,
},
Echo: "1",
}
data, _ := json.Marshal(resp)
var decoded ActionResponse
json.Unmarshal(data, &decoded)
if decoded.Status != "ok" {
t.Errorf("expected 'ok', got %q", decoded.Status)
}
}
func TestStatus(t *testing.T) {
s := Status{
AppInitialized: true,
AppEnabled: true,
Online: true,
Good: true,
}
if !s.Online || !s.Good {
t.Error("status should be online and good")
}
}
func TestEventMetaHeartbeat(t *testing.T) {
evt := Event{
PostType: "meta_event",
MetaEventType: "heartbeat",
Interval: 3000,
Status: &Status{
Online: true,
Good: true,
},
}
if evt.PostType != "meta_event" {
t.Errorf("expected 'meta_event', got %q", evt.PostType)
}
if evt.MetaEventType != "heartbeat" {
t.Errorf("expected 'heartbeat', got %q", evt.MetaEventType)
}
if !evt.Status.Online {
t.Error("should be online")
}
}