| // Copyright 2026 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package casmsg |
| |
| import ( |
| "sync" |
| |
| bspb "google.golang.org/genproto/googleapis/bytestream" |
| ) |
| |
| // ByteStreamAssembler is a stateful pipe that populates "Sticky ResourceNames" |
| // in a Bytestream Write stream. |
| type ByteStreamAssembler struct { |
| mu sync.Mutex |
| |
| // activeNames maps stream IDs to the last seen resource name for that stream. |
| // In the Bytestream Write protocol, the ResourceName is only required on the |
| // first message; subsequent messages in the same stream are assumed to belong |
| // to the same resource. This map allows the assembler to restore (rehydrate) |
| // that name into subsequent messages. |
| activeNames map[uint64]string |
| } |
| |
| // NewByteStreamAssembler creates a new ByteStreamAssembler. |
| func NewByteStreamAssembler() *ByteStreamAssembler { |
| return &ByteStreamAssembler{ |
| activeNames: make(map[uint64]string), |
| } |
| } |
| |
| // Assemble is a transformation function that restores missing resource names |
| // in a Bytestream Write sequence based on the stream's first message. |
| func (a *ByteStreamAssembler) Assemble(raw *RawWriteRequest) (*bspb.WriteRequest, bool) { |
| if raw == nil { |
| return nil, false |
| } |
| |
| a.mu.Lock() |
| defer a.mu.Unlock() |
| |
| // Handle Stream Closure: Clean up the remembered name for this stream. |
| if raw.IsClose { |
| delete(a.activeNames, raw.StreamID) |
| return nil, false |
| } |
| |
| // Restore Sticky Name: |
| // If this message has a name, remember it. If it doesn't, populate it |
| // from the previously remembered name for this stream. |
| if raw.Req.ResourceName != "" { |
| a.activeNames[raw.StreamID] = raw.Req.ResourceName |
| } else { |
| raw.Req.ResourceName = a.activeNames[raw.StreamID] |
| } |
| |
| return raw.Req, true |
| } |