// 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 }