// 指定使用 proto3 语法。 syntax = "proto3"; // 定义包名。在 Go 中,这会影响生成的代码所在的目录结构和包声明。 package relay; // 指定生成的 Go 代码的包路径。 option go_package = "relay_server/proto"; // ----------------------------------------------------------------------------- // 服务定义 (Service Definition) // ----------------------------------------------------------------------------- // InternalRelay 服务定义了服务器实例之间内部通信的 RPC 方法。 service InternalRelay { // ProxyRequest 是一个双向流式 RPC。 // "stream" 关键字表示客户端和服务器都可以连续地发送一系列消息, // 这对于传输大文件或实时数据流(如视频)至关重要,可以避免将整个内容加载到内存中。 rpc ProxyRequest(stream ProxyRequestMessage) returns (stream ProxyResponseMessage); } // ----------------------------------------------------------------------------- // 请求消息定义 (Request Messages) // ----------------------------------------------------------------------------- // ProxyRequestMessage 是从“代理实例”(接收App请求的实例) // 发送到“目标实例”(持有设备连接的实例)的消息。 // // 使用 `oneof` 结构可以确保每个消息要么是请求头,要么是请求体的一部分, // 这使得在接收端处理消息时逻辑更清晰、更安全。 message ProxyRequestMessage { oneof payload { ProxyRequestHeader header = 1; ProxyRequestBodyChunk body_chunk = 2; } } // ProxyRequestHeader 包含了重建原始 HTTP 请求所需的所有元数据。 // 这个消息必须是客户端发送的第一个消息。 message ProxyRequestHeader { // HTTP 方法, 例如 "GET", "POST", "PUT" 等。 string method = 1; // 完整的请求 URL 路径,包括查询参数。 // 例如 "/tunnel/DEVICE_SN_123/api/album?page=1&size=10" string url = 2; // 原始的 HTTP 请求头。 // `map` 类型非常适合用来表示键值对集合。 map headers = 3; // 原始 App 客户端的 IP 地址和端口,用于日志记录或 X-Forwarded-For 头。 string remote_addr = 4; // 经过认证的 App 用户的 ID,用于在目标实例上进行授权检查。 string app_user_id = 5; } // ProxyRequestBodyChunk 包含了一小块 HTTP 请求体的数据。 // 通过将请求体分割成多个 chunk 进行流式传输, // 我们可以处理任意大小的上传文件,而不会耗尽服务器内存。 message ProxyRequestBodyChunk { bytes data = 1; } // ----------------------------------------------------------------------------- // 响应消息定义 (Response Messages) // ----------------------------------------------------------------------------- // ProxyResponseMessage 是从“目标实例”发送回“代理实例”的消息。 // 同样使用 `oneof` 来区分响应头和响应体。 message ProxyResponseMessage { oneof payload { ProxyResponseHeader header = 1; ProxyResponseBodyChunk body_chunk = 2; } } // ProxyResponseHeader 包含了 HTTP 响应的元数据。 // 这个消息必须是服务器端在流中发送的第一个消息。 message ProxyResponseHeader { // HTTP 状态码, 例如 200, 404, 500。 int32 status_code = 1; // HTTP 响应头。 map headers = 2; } // ProxyResponseBodyChunk 包含了一小块 HTTP 响应体的数据。 // 这使得视频播放、大文件下载等场景可以实现流式传输, // App 客户端可以边接收数据边处理,而无需等待整个文件下载完成。 message ProxyResponseBodyChunk { bytes data = 1; }