- ControlPlane 라우터에 워커/에이전트 구독 채널을 추가한다 - ProtoSocket 기반 실시간 양방향 채널( dispatcher, envelope, server)을 구현한다 - Forgejo push 이벤트를 provider 어댑터로 처리하도록 연동한다 - PostgreSQL 스토리지 백엔드를 분리하여 postgres.go로 신설한다 - Git engine command에 diff/checkout/merge 연쇄 연산을 추가한다 - 런타임 모델에 agentSession, runtimeChannel 스키마를 추가한다 - 데이터베이스 마이그레이션에 agent_session, runtime_channel, lease 테이블을 추가한다 - agent-contract에 Forgejo branch events 계약 문서를 작성한다 - 로드맵 마일스톤과 아카이브 작업을 갱신한다
83 lines
1.8 KiB
Go
83 lines
1.8 KiB
Go
package protosocket
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
type HandlerFunc func(context.Context, Envelope) Envelope
|
|
|
|
type Dispatcher struct {
|
|
mu sync.RWMutex
|
|
handlers map[string]HandlerFunc
|
|
}
|
|
|
|
func NewDispatcher() *Dispatcher {
|
|
return &Dispatcher{handlers: make(map[string]HandlerFunc)}
|
|
}
|
|
|
|
func (d *Dispatcher) Register(action string, handler HandlerFunc) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
d.handlers[action] = handler
|
|
}
|
|
|
|
func (d *Dispatcher) Dispatch(ctx context.Context, env Envelope) Envelope {
|
|
d.mu.RLock()
|
|
handler, ok := d.handlers[env.Action]
|
|
d.mu.RUnlock()
|
|
if !ok {
|
|
return ErrorResponse(env, "UNSUPPORTED_ACTION", fmt.Sprintf("unsupported action: %s", env.Action), false)
|
|
}
|
|
return handler(ctx, env)
|
|
}
|
|
|
|
func SuccessResponse(req Envelope, payload map[string]any) Envelope {
|
|
return Envelope{
|
|
ProtocolVersion: ProtocolVersion,
|
|
ID: generateID(),
|
|
CorrelationID: req.ID,
|
|
Type: "response",
|
|
Channel: req.Channel,
|
|
Action: req.Action,
|
|
Payload: payload,
|
|
}
|
|
}
|
|
|
|
func ErrorResponse(req Envelope, code, message string, retryable bool) Envelope {
|
|
return Envelope{
|
|
ProtocolVersion: ProtocolVersion,
|
|
ID: generateID(),
|
|
CorrelationID: req.ID,
|
|
Type: "error",
|
|
Channel: req.Channel,
|
|
Action: req.Action,
|
|
Error: &EnvelopeError{
|
|
Code: code,
|
|
Message: message,
|
|
Retryable: retryable,
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewEventEnvelope(action string, payload map[string]any) Envelope {
|
|
return Envelope{
|
|
ProtocolVersion: ProtocolVersion,
|
|
ID: generateID(),
|
|
Type: "event",
|
|
Channel: "event",
|
|
Action: action,
|
|
Payload: payload,
|
|
}
|
|
}
|
|
|
|
func generateID() string {
|
|
b := make([]byte, 16)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "id-fallback"
|
|
}
|
|
return hex.EncodeToString(b)
|
|
}
|