Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions control.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const (
CtrlEntitlementViolation ControlType = "entitlement_violation"
CtrlPushNotify ControlType = "push_notify"
CtrlPushNotifyResult ControlType = "push_notify_result"
CtrlTerminateSession ControlType = "terminate_session"
CtrlTerminateSessionAck ControlType = "terminate_session_ack"
)

// ControlMessage is the wire format for relay control protocol messages.
Expand Down Expand Up @@ -99,6 +101,23 @@ type DeactivateDeveloperPayload struct {
DeveloperID string `json:"developer_id"`
}

// TerminateSessionPayload is sent by the relay to a daemon when an operator
// terminates a single relay session from the dashboard. Unlike developer
// deactivation, this is scoped to one relay session and should stop reconnects
// for that relay session identity.
type TerminateSessionPayload struct {
SessionID string `json:"session_id"`
Reason string `json:"reason,omitempty"`
}

// TerminateSessionAckPayload is sent by the daemon after it has accepted a
// terminate_session control message. The relay treats it as observability; the
// durable termination tombstone is the reconnect-blocking authority.
type TerminateSessionAckPayload struct {
SessionID string `json:"session_id"`
Stopped int `json:"stopped,omitempty"`
}

// ClientConnectedPayload is sent by the relay to the daemon when a PWA client
// connects or reconnects. The daemon uses this to replay message history.
type ClientConnectedPayload struct {
Expand Down
8 changes: 8 additions & 0 deletions protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,12 @@ func TestDeactivateDeveloperPayloadRoundtrip(t *testing.T) {
assertRoundtrip(t, protocol.DeactivateDeveloperPayload{DeveloperID: "dev-1"})
}

func TestTerminateSessionPayloadRoundtrip(t *testing.T) {
t.Parallel()
assertRoundtrip(t, protocol.TerminateSessionPayload{SessionID: "relay-1", Reason: "operator"})
assertRoundtrip(t, protocol.TerminateSessionAckPayload{SessionID: "relay-1", Stopped: 2})
}

func TestClientConnectedPayloadRoundtrip(t *testing.T) {
t.Parallel()
assertRoundtrip(t, protocol.ClientConnectedPayload{SessionID: "sess-123"})
Expand Down Expand Up @@ -557,6 +563,8 @@ func TestControlTypeConstants(t *testing.T) {
protocol.CtrlEntitlementViolation: "entitlement_violation",
protocol.CtrlPushNotify: "push_notify",
protocol.CtrlPushNotifyResult: "push_notify_result",
protocol.CtrlTerminateSession: "terminate_session",
protocol.CtrlTerminateSessionAck: "terminate_session_ack",
}
for ct, want := range expected {
if string(ct) != want {
Expand Down
Loading