Files
goclaw/internal/gateway/methods/sessions.go
T
viettranx 9115169c03 feat: expand audit logging via pub/sub event pattern
Replace direct ActivityStore injection with event-driven audit system.
Handlers emit audit events via msgBus.Broadcast(), a single subscriber
with buffered channel persists to activity_logs table.

Coverage expanded from 3 agent CRUD actions to ~65 audit points across
all HTTP handlers and WebSocket RPC methods including agents, providers,
skills, MCP servers, cron, sessions, teams, pairing, and more.
2026-03-12 18:34:56 +07:00

162 lines
5.1 KiB
Go

package methods
import (
"context"
"encoding/json"
"github.com/nextlevelbuilder/goclaw/internal/bus"
"github.com/nextlevelbuilder/goclaw/internal/gateway"
"github.com/nextlevelbuilder/goclaw/internal/i18n"
"github.com/nextlevelbuilder/goclaw/internal/store"
"github.com/nextlevelbuilder/goclaw/pkg/protocol"
)
// SessionsMethods handles sessions.list, sessions.preview, sessions.patch, sessions.delete, sessions.reset.
type SessionsMethods struct {
sessions store.SessionStore
eventBus bus.EventPublisher
}
func NewSessionsMethods(sess store.SessionStore, eventBus bus.EventPublisher) *SessionsMethods {
return &SessionsMethods{sessions: sess, eventBus: eventBus}
}
func (m *SessionsMethods) Register(router *gateway.MethodRouter) {
router.Register(protocol.MethodSessionsList, m.handleList)
router.Register(protocol.MethodSessionsPreview, m.handlePreview)
router.Register(protocol.MethodSessionsPatch, m.handlePatch)
router.Register(protocol.MethodSessionsDelete, m.handleDelete)
router.Register(protocol.MethodSessionsReset, m.handleReset)
}
type sessionsListParams struct {
AgentID string `json:"agentId"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
func (m *SessionsMethods) handleList(_ context.Context, client *gateway.Client, req *protocol.RequestFrame) {
var params sessionsListParams
if req.Params != nil {
json.Unmarshal(req.Params, &params)
}
if params.Limit <= 0 {
params.Limit = 20
}
result := m.sessions.ListPagedRich(store.SessionListOpts{
AgentID: params.AgentID,
Limit: params.Limit,
Offset: params.Offset,
})
client.SendResponse(protocol.NewOKResponse(req.ID, map[string]any{
"sessions": result.Sessions,
"total": result.Total,
"limit": params.Limit,
"offset": params.Offset,
}))
}
type sessionKeyParams struct {
Key string `json:"key"`
}
func (m *SessionsMethods) handlePreview(ctx context.Context, client *gateway.Client, req *protocol.RequestFrame) {
locale := store.LocaleFromContext(ctx)
var params sessionKeyParams
if err := json.Unmarshal(req.Params, &params); err != nil {
client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, i18n.T(locale, i18n.MsgInvalidJSON)))
return
}
history := m.sessions.GetHistory(params.Key)
summary := m.sessions.GetSummary(params.Key)
client.SendResponse(protocol.NewOKResponse(req.ID, map[string]any{
"key": params.Key,
"messages": history,
"summary": summary,
}))
}
// handlePatch updates session metadata fields.
// Matching TS sessions.patch (src/gateway/server-methods/sessions.ts:237-287).
func (m *SessionsMethods) handlePatch(ctx context.Context, client *gateway.Client, req *protocol.RequestFrame) {
locale := store.LocaleFromContext(ctx)
var params struct {
Key string `json:"key"`
Label *string `json:"label,omitempty"`
Model *string `json:"model,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
}
if err := json.Unmarshal(req.Params, &params); err != nil {
client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, i18n.T(locale, i18n.MsgInvalidJSON)))
return
}
if params.Key == "" {
client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, i18n.T(locale, i18n.MsgRequired, "key")))
return
}
// Apply label patch
if params.Label != nil {
m.sessions.SetLabel(params.Key, *params.Label)
}
// Apply model patch
if params.Model != nil {
m.sessions.UpdateMetadata(params.Key, *params.Model, "", "")
}
// Apply metadata patch
if len(params.Metadata) > 0 {
m.sessions.SetSessionMetadata(params.Key, params.Metadata)
}
// Save changes to DB
m.sessions.Save(params.Key)
client.SendResponse(protocol.NewOKResponse(req.ID, map[string]any{
"ok": true,
"key": params.Key,
}))
emitAudit(m.eventBus, client, "session.patched", "session", params.Key)
}
func (m *SessionsMethods) handleDelete(ctx context.Context, client *gateway.Client, req *protocol.RequestFrame) {
locale := store.LocaleFromContext(ctx)
var params sessionKeyParams
if err := json.Unmarshal(req.Params, &params); err != nil {
client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, i18n.T(locale, i18n.MsgInvalidJSON)))
return
}
if err := m.sessions.Delete(params.Key); err != nil {
client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInternal, err.Error()))
return
}
client.SendResponse(protocol.NewOKResponse(req.ID, map[string]any{
"ok": true,
}))
emitAudit(m.eventBus, client, "session.deleted", "session", params.Key)
}
func (m *SessionsMethods) handleReset(ctx context.Context, client *gateway.Client, req *protocol.RequestFrame) {
locale := store.LocaleFromContext(ctx)
var params sessionKeyParams
if err := json.Unmarshal(req.Params, &params); err != nil {
client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, i18n.T(locale, i18n.MsgInvalidJSON)))
return
}
m.sessions.Reset(params.Key)
client.SendResponse(protocol.NewOKResponse(req.ID, map[string]any{
"ok": true,
}))
emitAudit(m.eventBus, client, "session.reset", "session", params.Key)
}