iop/apps/node/internal/transport/frame.go
toki 2d6fde0876 기능: IOP 모노레포 스캐폴드 초기 구현
apps/node 중심 구현 — TCP+JSON transport, Hexagonal Architecture,
mock/cli adapter, fx DI, SQLite 실행 이력 저장.
edge/control-plane/worker는 cobra placeholder.
유닛 테스트 및 통합 테스트 클라이언트 계획서 추가.
2026-05-02 13:20:35 +09:00

63 lines
1.5 KiB
Go

// Package transport implements IOP's TCP framing layer.
//
// Wire format (same endianness as proto-socket):
// [4 bytes big-endian uint32: payload length] [payload bytes]
//
// Payload is a JSON-encoded Envelope (see codec.go).
// TODO: switch payload encoding to protobuf once proto/gen is available.
package transport
import (
"encoding/binary"
"fmt"
"io"
)
const (
frameLenBytes = 4
maxFrameSize = 64 << 20 // 64 MiB — same limit as proto-socket
)
// readFrame reads one length-prefixed frame from r.
func readFrame(r io.Reader) ([]byte, error) {
hdr := make([]byte, frameLenBytes)
if _, err := io.ReadFull(r, hdr); err != nil {
return nil, err
}
length := binary.BigEndian.Uint32(hdr)
if length == 0 {
return []byte{}, nil
}
if length > maxFrameSize {
return nil, fmt.Errorf("frame too large: %d bytes (max %d)", length, maxFrameSize)
}
buf := make([]byte, length)
if _, err := io.ReadFull(r, buf); err != nil {
return nil, err
}
return buf, nil
}
// writeFrame writes payload as a length-prefixed frame to w.
func writeFrame(w io.Writer, payload []byte) error {
hdr := make([]byte, frameLenBytes)
binary.BigEndian.PutUint32(hdr, uint32(len(payload)))
if err := writeFull(w, hdr); err != nil {
return err
}
return writeFull(w, payload)
}
func writeFull(w io.Writer, b []byte) error {
for len(b) > 0 {
n, err := w.Write(b)
if err != nil {
return err
}
if n == 0 {
return io.ErrShortWrite
}
b = b[n:]
}
return nil
}