feat: persist fenced client command events

This commit is contained in:
2026-09-06 09:17:04 +00:00
parent 69a7e01f9d
commit 4e339ebe14
9 changed files with 147 additions and 18 deletions
+63
View File
@@ -241,7 +241,70 @@ func (server *AgentServer) serveConnection(parent context.Context, connection *w
server.close(connection, websocket.StatusPolicyViolation, "invalid command acceptance")
return
}
continue
}
if event := envelope.GetCommandEvent(); event != nil {
appendEvent, eventErr := eventAppendFromWire(event, hello.GetClientId(), server.now())
if eventErr != nil {
server.close(connection, websocket.StatusPolicyViolation, "invalid command event")
return
}
appended, eventErr := server.Store.AppendCommandEvent(sessionContext, appendEvent)
if eventErr != nil {
server.close(connection, websocket.StatusPolicyViolation, "command event was not accepted")
return
}
ack, eventErr := proto.Marshal(&rvboxv1.AgentEnvelope{SessionId: encodedSessionID, SessionGeneration: registration.Generation, Payload: &rvboxv1.AgentEnvelope_EventAck{EventAck: &rvboxv1.EventAck{IssueUuid: event.GetIssueUuid(), ThroughEventSeq: appended.ThroughEventSeq}}})
if eventErr != nil || queue.EnqueueControl(Frame{Kind: FrameControl, Payload: ack}) != nil {
server.close(connection, websocket.StatusInternalError, "could not acknowledge command event")
return
}
}
}
}
func eventAppendFromWire(event *rvboxv1.CommandEvent, clientID string, receipt time.Time) (store.EventAppend, error) {
issue, err := domain.ParseUUIDv7(event.GetIssueUuid())
if err != nil {
return store.EventAppend{}, err
}
payload, err := proto.MarshalOptions{Deterministic: true}.Marshal(event)
if err != nil {
return store.EventAppend{}, err
}
var immutable [32]byte
copy(immutable[:], event.GetImmutableEventSha256())
result := store.EventAppend{IssueUUID: [16]byte(issue), ClientID: clientID, EventSeq: event.GetEventSeq(), ObservedUnixNano: event.GetObservedAt().AsTime().UnixNano(), ReceiptUnixNano: receipt.UnixNano(), EventType: eventType(event), Compression: 1, RawLength: uint64(len(payload)), Payload: payload, ImmutableSHA256: immutable}
if output := event.GetOutput(); output != nil {
result.Stream = uint16(output.GetStream())
result.Output = true
}
if result.EventType == 0 {
return store.EventAppend{}, errors.New("unsupported command event")
}
return result, nil
}
func eventType(event *rvboxv1.CommandEvent) uint16 {
switch event.Payload.(type) {
case *rvboxv1.CommandEvent_Lifecycle:
return 4
case *rvboxv1.CommandEvent_Output:
return 5
case *rvboxv1.CommandEvent_Resource:
return 6
case *rvboxv1.CommandEvent_StdinAck:
return 7
case *rvboxv1.CommandEvent_SignalResult:
return 8
case *rvboxv1.CommandEvent_ScriptStatus:
return 9
case *rvboxv1.CommandEvent_OutputTruncation:
return 10
case *rvboxv1.CommandEvent_OutputIncomplete:
return 11
default:
return 0
}
}