feat(protocol): negotiate registered gateway profiles
Verify Protocol / verify (push) Canceled after 0s
Verify Protocol / module (push) Successful in 2m29s

This commit is contained in:
sechmachine
2026-07-30 04:47:52 +07:00
parent d26f8b60f8
commit e58f1c7c48
17 changed files with 227 additions and 67 deletions
+15 -10
View File
@@ -1,7 +1,7 @@
// Code generated by tools/generate.py; DO NOT EDIT.
import Foundation
public typealias JSONObject = [String: String]
public let schemaSHA256 = "fe4d6be69665f09f04e2cd89273ebc5d2dddf4cde98b94a9d8c4f726504ffe1b"
public let schemaSHA256 = "3aec8dd72bdbb6b9657c8df3160252c93034c7c1032d471e01eae2ef91e47716"
public let currentWireVersion = "1"
public let nMinus1WireVersion = "0"
public let nMinus2WireVersion = "-1"
@@ -247,7 +247,7 @@ public struct CapabilityProfile: Codable, Equatable {
public let media: String
public let audio: String
public let sourceRateControl: String
public let clientDecode: String
public let clientDecode: [String]
enum CodingKeys: String, CodingKey {
case transport = "transport"
case framing = "framing"
@@ -257,7 +257,7 @@ public struct CapabilityProfile: Codable, Equatable {
case clientDecode = "client_decode"
}
public init(transport: String, framing: String, media: String, audio: String, sourceRateControl: String, clientDecode: String) throws {
public init(transport: String, framing: String, media: String, audio: String, sourceRateControl: String, clientDecode: [String]) throws {
self.transport = transport
self.framing = framing
self.media = media
@@ -271,7 +271,7 @@ public struct CapabilityProfile: Codable, Equatable {
let all = try decoder.container(keyedBy: AnyCodingKey.self)
for key in all.allKeys where CodingKeys(stringValue: key.stringValue) == nil { throw ContractValidationError(field: key.stringValue, code: "unknown_field") }
let c = try decoder.container(keyedBy: CodingKeys.self)
try self.init(transport: try c.decode(String.self, forKey: .transport), framing: try c.decode(String.self, forKey: .framing), media: try c.decode(String.self, forKey: .media), audio: try c.decode(String.self, forKey: .audio), sourceRateControl: try c.decode(String.self, forKey: .sourceRateControl), clientDecode: try c.decode(String.self, forKey: .clientDecode))
try self.init(transport: try c.decode(String.self, forKey: .transport), framing: try c.decode(String.self, forKey: .framing), media: try c.decode(String.self, forKey: .media), audio: try c.decode(String.self, forKey: .audio), sourceRateControl: try c.decode(String.self, forKey: .sourceRateControl), clientDecode: try c.decode([String].self, forKey: .clientDecode))
}
public func validate() throws {
@@ -290,9 +290,10 @@ public struct CapabilityProfile: Codable, Equatable {
if self.sourceRateControl.isEmpty { throw ContractValidationError(field: "source_rate_control", code: "required") }
if !self.sourceRateControl.isEmpty && self.sourceRateControl.utf8.count < 1 { throw ContractValidationError(field: "source_rate_control", code: "min_length") }
if self.sourceRateControl.utf8.count > 64 { throw ContractValidationError(field: "source_rate_control", code: "max_length") }
if self.clientDecode.isEmpty { throw ContractValidationError(field: "client_decode", code: "required") }
if !self.clientDecode.isEmpty && self.clientDecode.utf8.count < 1 { throw ContractValidationError(field: "client_decode", code: "min_length") }
if self.clientDecode.utf8.count > 64 { throw ContractValidationError(field: "client_decode", code: "max_length") }
if self.clientDecode.count < 1 { throw ContractValidationError(field: "client_decode", code: "min_items") }
if self.clientDecode.count > 2 { throw ContractValidationError(field: "client_decode", code: "max_items") }
for item in self.clientDecode where !["h264-opus", "hevc-opus"].contains(item) { throw ContractValidationError(field: "client_decode", code: "invalid_item") }
if Set(self.clientDecode).count != self.clientDecode.count { throw ContractValidationError(field: "client_decode", code: "duplicate_item") }
}
public static func decodeJSON(_ data: Data) throws -> Self { try JSONDecoder().decode(Self.self, from: data) }
@@ -2321,7 +2322,8 @@ public struct VersionNegotiation: Codable, Equatable {
public extension TunnelAdmissionRequest {
func deviceAdmissionTranscript() -> Data {
let fields = [sessionId, gatewayId, audience, grant, String(reconnectSequence), clientNonce, capabilities.transport, capabilities.framing, capabilities.media, capabilities.audio, capabilities.sourceRateControl, capabilities.clientDecode]
var fields = [sessionId, gatewayId, audience, grant, String(reconnectSequence), clientNonce, capabilities.transport, capabilities.framing, capabilities.media, capabilities.audio, capabilities.sourceRateControl, String(capabilities.clientDecode.count)]
fields.append(contentsOf: capabilities.clientDecode)
var transcript = "versevdi/tunnel-admission/v1"
for field in fields { transcript += "\(field.utf8.count):\(field)" }
return Data(transcript.utf8)
@@ -2332,10 +2334,13 @@ public extension CapabilityProfile {
static func intersection(_ profiles: [CapabilityProfile]) throws -> CapabilityProfile {
guard let selected = profiles.first else { throw ContractValidationError(field: "capabilities", code: "no_overlap") }
try selected.validate()
var common = selected.clientDecode
for profile in profiles.dropFirst() {
try profile.validate()
if profile != selected { throw ContractValidationError(field: "capabilities", code: "no_overlap") }
if profile.transport != selected.transport || profile.framing != selected.framing || profile.media != selected.media || profile.audio != selected.audio || profile.sourceRateControl != selected.sourceRateControl { throw ContractValidationError(field: "capabilities", code: "no_overlap") }
common = common.filter { profile.clientDecode.contains($0) }
if common.isEmpty { throw ContractValidationError(field: "capabilities", code: "no_overlap") }
}
return selected
return try CapabilityProfile(transport: selected.transport, framing: selected.framing, media: selected.media, audio: selected.audio, sourceRateControl: selected.sourceRateControl, clientDecode: common)
}
}