- 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 계약 문서를 작성한다 - 로드맵 마일스톤과 아카이브 작업을 갱신한다
120 lines
3 KiB
Go
120 lines
3 KiB
Go
package protosocket
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"google.golang.org/protobuf/types/known/structpb"
|
|
)
|
|
|
|
const ProtocolVersion = "nomadcode.proto-socket.v1"
|
|
|
|
type Envelope struct {
|
|
ProtocolVersion string `json:"protocol_version"`
|
|
ID string `json:"id"`
|
|
CorrelationID string `json:"correlation_id"`
|
|
Type string `json:"type"`
|
|
Channel string `json:"channel"`
|
|
Action string `json:"action"`
|
|
Actor map[string]any `json:"actor,omitempty"`
|
|
Auth map[string]any `json:"auth,omitempty"`
|
|
Payload map[string]any `json:"payload,omitempty"`
|
|
Error *EnvelopeError `json:"error,omitempty"`
|
|
Meta map[string]any `json:"meta,omitempty"`
|
|
}
|
|
|
|
type EnvelopeError struct {
|
|
Code string `json:"code"`
|
|
Message string `json:"message"`
|
|
Retryable bool `json:"retryable"`
|
|
Details map[string]any `json:"details,omitempty"`
|
|
}
|
|
|
|
func (e Envelope) ToStruct() (*structpb.Struct, error) {
|
|
value := map[string]any{
|
|
"protocol_version": e.ProtocolVersion,
|
|
"id": e.ID,
|
|
"correlation_id": e.CorrelationID,
|
|
"type": e.Type,
|
|
"channel": e.Channel,
|
|
"action": e.Action,
|
|
}
|
|
if e.Actor != nil {
|
|
value["actor"] = e.Actor
|
|
}
|
|
if e.Auth != nil {
|
|
value["auth"] = e.Auth
|
|
}
|
|
if e.Payload != nil {
|
|
value["payload"] = e.Payload
|
|
}
|
|
if e.Meta != nil {
|
|
value["meta"] = e.Meta
|
|
}
|
|
if e.Error != nil {
|
|
errValue := map[string]any{
|
|
"code": e.Error.Code,
|
|
"message": e.Error.Message,
|
|
"retryable": e.Error.Retryable,
|
|
}
|
|
if e.Error.Details != nil {
|
|
errValue["details"] = e.Error.Details
|
|
}
|
|
value["error"] = errValue
|
|
}
|
|
return structpb.NewStruct(value)
|
|
}
|
|
|
|
func EnvelopeFromStruct(value *structpb.Struct) (Envelope, error) {
|
|
var env Envelope
|
|
if value == nil {
|
|
return env, fmt.Errorf("nil struct")
|
|
}
|
|
raw := value.AsMap()
|
|
if v, ok := raw["protocol_version"].(string); ok {
|
|
env.ProtocolVersion = v
|
|
}
|
|
if v, ok := raw["id"].(string); ok {
|
|
env.ID = v
|
|
}
|
|
if v, ok := raw["correlation_id"].(string); ok {
|
|
env.CorrelationID = v
|
|
}
|
|
if v, ok := raw["type"].(string); ok {
|
|
env.Type = v
|
|
}
|
|
if v, ok := raw["channel"].(string); ok {
|
|
env.Channel = v
|
|
}
|
|
if v, ok := raw["action"].(string); ok {
|
|
env.Action = v
|
|
}
|
|
if v, ok := raw["actor"].(map[string]any); ok {
|
|
env.Actor = v
|
|
}
|
|
if v, ok := raw["auth"].(map[string]any); ok {
|
|
env.Auth = v
|
|
}
|
|
if v, ok := raw["payload"].(map[string]any); ok {
|
|
env.Payload = v
|
|
}
|
|
if v, ok := raw["meta"].(map[string]any); ok {
|
|
env.Meta = v
|
|
}
|
|
if errValue, ok := raw["error"].(map[string]any); ok {
|
|
envErr := EnvelopeError{}
|
|
if v, ok := errValue["code"].(string); ok {
|
|
envErr.Code = v
|
|
}
|
|
if v, ok := errValue["message"].(string); ok {
|
|
envErr.Message = v
|
|
}
|
|
if v, ok := errValue["retryable"].(bool); ok {
|
|
envErr.Retryable = v
|
|
}
|
|
if v, ok := errValue["details"].(map[string]any); ok {
|
|
envErr.Details = v
|
|
}
|
|
env.Error = &envErr
|
|
}
|
|
return env, nil
|
|
}
|