Files
Chase CichorzandClaude Opus 5.5 2651b5e9bd Add Remote Braille IPC to the host and both SDKs
remote.braille requests and events carry a typed op under a
braille-stream lease: the controller's width and gestures for a
controlled reader, rendered cells back to its child, and cells, local
geometry and display gestures for a controller. Direction is validated
per role; a full mailbox revokes the lease. No display owner is
attached yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 16:06:38 -05:00

80 lines
3.0 KiB
Go

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package tentacle
import (
"context"
"encoding/json"
"git.stormux.org/storm/cthulhu/internal/tentaclewire"
)
// RemoteBrailleDelivery is admitted Braille work for the reader's owner.
// The owner must recheck Context and RemoteContext(braille-stream) and its own
// display policy before any effect. Role is the lease's core-assigned role.
type RemoteBrailleDelivery struct {
Context context.Context
Lease tentaclewire.RemoteLease
Role string
Sequence uint64
Braille tentaclewire.RemoteBraille
}
// EnableRemoteBraille attaches one reader-owned Braille mailbox. It performs
// no display setup and grants no authority.
func (session *Session) EnableRemoteBraille() <-chan RemoteBrailleDelivery {
session.mutex.Lock()
defer session.mutex.Unlock()
if session.remoteBraille == nil {
session.remoteBraille = make(chan RemoteBrailleDelivery, tentaclewire.RemoteBrailleQueueSize)
}
return session.remoteBraille
}
func (session *Session) remote_braille_locked(params json.RawMessage) (any, *RPCError) {
var request tentaclewire.RemoteBrailleRequest
if decode_strict(params, &request) != nil {
return nil, &RPCError{Code: -32602, Message: "Invalid session parameters"}
}
lease := tentaclewire.RemoteLease{Lease: request.Lease, Epoch: request.Epoch}
access := session.remote_access_locked(lease, "braille-stream")
if access == nil || request.Sequence <= access.sequence || !tentaclewire.ValidRemoteBrailleFor(access.role, true, request.Braille) {
return nil, &RPCError{Code: -32001, Message: "Session permission denied"}
}
if session.remoteBraille == nil {
return nil, &RPCError{Code: -32601, Message: "Remote Braille owner unavailable"}
}
access.sequence = request.Sequence
select {
case session.remoteBraille <- RemoteBrailleDelivery{Context: access.ctx, Lease: lease, Role: access.role, Sequence: request.Sequence, Braille: request.Braille}:
return struct{}{}, nil
default:
session.revoke_remote_locked("local", true)
return nil, &RPCError{Code: -32002, Message: "Remote Braille queue full"}
}
}
// PublishRemoteBraille sends one Braille operation to the child. The owner
// supplies only rendered cells (controlled), local geometry or local display
// gestures (controller); never text, routing identities or native handles.
func (session *Session) PublishRemoteBraille(lease tentaclewire.RemoteLease, value tentaclewire.RemoteBraille) error {
session.mutex.Lock()
defer session.mutex.Unlock()
access := session.remote_access_locked(lease, "braille-stream")
if access == nil || !tentaclewire.ValidRemoteBrailleFor(access.role, false, value) {
return ErrPermission
}
value.Cells = append([]int(nil), value.Cells...)
if len(value.Cells) == 0 {
value.Cells = nil
}
event := tentaclewire.SessionEvent{Kind: "remote.braille", Lease: lease.Lease, Epoch: lease.Epoch, Braille: &value}
if !session.remote_event_locked(&event) {
session.fail_locked(ErrLimit)
return ErrLimit
}
return nil
}