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>
80 lines
3.0 KiB
Go
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
|
|
}
|