Files
nucleic/guest/NucleicVMAgent/Sources/VMAgentCore/AgentWire.swift
T

43 lines
1.8 KiB
Swift

import Foundation
/// Wire constants for the host ⇄ agent protocol (docs/MACOS_VM_NATIVE_AGENT.md §3–§4).
///
/// The transport is NDJSON over vsock: one JSON request object per line, one JSON reply per line.
/// Requests carry an `op`; replies carry `ok` (plus op-specific fields, or `error` when `ok:false`).
///
/// The port constant is mirrored on the host side in `MacVMAgentWire`
/// (Sources/NucleicCore/MacVM/MacVMAgentClient.swift) — the two packages are deliberately separate
/// (different platform floors), so keep the values in lockstep.
public enum AgentWire {
/// The Nucleic-reserved vsock port the agent listens on and the host connects to.
public static let port: UInt32 = 2035
/// Protocol version reported in the `ping` reply, bumped on incompatible wire changes.
public static let version = 1
}
/// Accumulates raw bytes and yields complete newline-terminated lines — the NDJSON framing both
/// sides use (one request/reply object per line). Pure and unit-tested; the connection loop feeds
/// it whatever `read(2)` returns.
public struct LineSplitBuffer {
private var data = Data()
public init() {}
public mutating func append(_ chunk: Data) {
data.append(chunk)
}
/// The next complete line (without its trailing `\n`), or `nil` when no full line is buffered.
public mutating func nextLine() -> Data? {
guard let nl = data.firstIndex(of: 0x0A) else { return nil }
let line = data.subdata(in: data.startIndex..<nl)
data.removeSubrange(data.startIndex...nl)
// Tolerate CRLF framing from a debugging client.
if line.last == 0x0D { return line.dropLast() }
return line
}
/// Bytes currently buffered without a terminating newline — the runaway-line guard reads this.
public var pendingBytes: Int { data.count }
}