diff --git a/Sources/SwiftScaffolding/Client/ScaffoldingClient.swift b/Sources/SwiftScaffolding/Client/ScaffoldingClient.swift index 5022184..ff868ad 100644 --- a/Sources/SwiftScaffolding/Client/ScaffoldingClient.swift +++ b/Sources/SwiftScaffolding/Client/ScaffoldingClient.swift @@ -27,6 +27,7 @@ public final class ScaffoldingClient { } /// 使用指定的 EasyTier 创建连接到指定房间的 `ScaffoldingClient`。 + /// /// - Parameters: /// - easyTier: 使用的 EasyTier。 /// - playerName: 玩家名。 @@ -52,8 +53,9 @@ public final class ScaffoldingClient { } /// 连接到房间。 + /// /// 该方法返回后,必须每隔 5s 调用一次 `heartbeat()` 方法。 - /// https://github.com/Scaffolding-MC/Scaffolding-MC/blob/main/README.md#拓展协议 + /// [标准联机流程](https://github.com/Scaffolding-MC/Scaffolding-MC/blob/main/README.md#拓展协议) /// - Parameters: /// - roomCode: 房间码。 /// - checkServer: 是否检查联机中心返回的 Minecraft 服务器端口号。 @@ -120,8 +122,11 @@ public final class ScaffoldingClient { } /// 向联机中心发送请求。 + /// + /// 发送成功后,该方法会一直等待联机中心返回响应。 /// - Parameters: /// - name: 请求类型。 + /// - timeout: 超时时间。 /// - body: 请求体构造函数。 /// - Returns: 联机中心的响应。 @discardableResult diff --git a/Sources/SwiftScaffolding/EasyTier.swift b/Sources/SwiftScaffolding/EasyTier.swift index c508106..e83d366 100644 --- a/Sources/SwiftScaffolding/EasyTier.swift +++ b/Sources/SwiftScaffolding/EasyTier.swift @@ -18,6 +18,7 @@ public final class EasyTier { private var rpcPort: UInt16? /// 创建一个 EasyTier 实例。 + /// /// - Parameters: /// - coreURL: `easytier-core` 的路径。 /// - cliURL: `easytier-cli` 的路径。 @@ -31,6 +32,8 @@ public final class EasyTier { } /// 启动 EasyTier。 + /// + /// 如果已经启动了一个进程,旧进程会被杀死。 /// - Parameters: /// - args: `easytier-core` 的参数。 /// - terminationHandler: 进程退出回调,不会在正常 `terminate()` 时被调用。 @@ -83,9 +86,10 @@ public final class EasyTier { } /// 以 JSON 模式调用 `easytier-cli`。 - /// 如果 `easytier-cli` 报错,会抛出 `EasyTierError.cliError` 错误。 + /// /// - Parameter args: `easytier-cli` 的参数。 /// - Returns: 调用结果,不是 JSON 时为 `nil`。 + /// - Throws: 如果 `easytier-cli` 报错,会抛出 `EasyTierError.cliError` 错误。 @discardableResult public func callCLI(_ args: String...) throws -> JSON? { guard let rpcPort = self.rpcPort else { throw ConnectionError.failedToAllocatePort } @@ -144,6 +148,7 @@ public final class EasyTier { extension EasyTier { /// 添加端口转发规则。 + /// /// - Parameters: /// - protocol: 使用的协议类型,默认为 `tcp`。 /// - bind: 本地绑定地址。 @@ -154,6 +159,7 @@ extension EasyTier { } /// 移除端口转发规则。 + /// /// - Parameters: /// - protocol: 使用的协议类型,默认为 `tcp`。 /// - bind: 本地绑定地址。 diff --git a/Sources/SwiftScaffolding/Scaffolding.swift b/Sources/SwiftScaffolding/Scaffolding.swift index c29dc10..443becc 100644 --- a/Sources/SwiftScaffolding/Scaffolding.swift +++ b/Sources/SwiftScaffolding/Scaffolding.swift @@ -14,7 +14,8 @@ public final class Scaffolding { internal static let networkQueue: DispatchQueue = DispatchQueue(label: "SwiftScaffolding.Network") /// 根据设备的主板唯一标识符生成设备标识符。 - /// https://github.com/Scaffolding-MC/Scaffolding-MC/blob/main/README.md#machine_id + /// + /// [machine_id 文档](https://github.com/Scaffolding-MC/Scaffolding-MC/blob/main/README.md#machine_id) /// - Returns: 设备标识符。 public static func getMachineID(forHost: Bool = false) -> String { let service: io_service_t = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice")) @@ -26,7 +27,8 @@ public final class Scaffolding { } /// 发送 Scaffolding 请求。 - /// https://github.com/Scaffolding-MC/Scaffolding-MC/blob/main/README.md#联机信息获取协议 + /// + /// [协议文档](https://github.com/Scaffolding-MC/Scaffolding-MC/blob/main/README.md#联机信息获取协议) /// - Parameters: /// - type: 请求类型。 /// - connection: 到联机中心的连接。 @@ -94,6 +96,7 @@ public final class Scaffolding { } /// 检查本地指定端口是否存在一个 Minecraft 服务器。 + /// /// - Parameters: /// - port: 服务器端口。 public static func checkMinecraftServer(on port: UInt16, timeout: Double = 10) async -> Bool { @@ -119,6 +122,7 @@ public final class Scaffolding { public let data: Data /// 根据响应状态码与响应体创建响应。 + /// /// - Parameters: /// - status: 响应状态。 /// - data: 响应体。 @@ -128,6 +132,7 @@ public final class Scaffolding { } /// 根据响应状态码与响应体构造函数创建响应。 + /// /// - Parameters: /// - status: 响应状态。 /// - body: 响应体构造函数。 diff --git a/Sources/SwiftScaffolding/Server/RequestHandler.swift b/Sources/SwiftScaffolding/Server/RequestHandler.swift index bd3c5a8..64de81c 100644 --- a/Sources/SwiftScaffolding/Server/RequestHandler.swift +++ b/Sources/SwiftScaffolding/Server/RequestHandler.swift @@ -18,6 +18,11 @@ public class RequestHandler { } /// 注册请求处理器。 + /// + /// `handler` 闭包接受两个参数: + /// - `sender`:一个 `Sender` 对象,包含发送者的档案信息和连接对象。 + /// - `buffer`:一个用于读取请求体的 `ByteBuffer`。 + /// /// - Parameters: /// - type: 请求类型,例如 `c:ping`。 /// - handler: 请求处理函数。 diff --git a/Sources/SwiftScaffolding/Server/ScaffoldingServer.swift b/Sources/SwiftScaffolding/Server/ScaffoldingServer.swift index a05d8f5..185f0aa 100644 --- a/Sources/SwiftScaffolding/Server/ScaffoldingServer.swift +++ b/Sources/SwiftScaffolding/Server/ScaffoldingServer.swift @@ -26,7 +26,8 @@ public final class ScaffoldingServer { easyTier.terminate() } - /// 使用指定的 EasyTier 创建联机中心。 + /// 创建联机中心。 + /// /// - Parameters: /// - easyTier: 使用的 EasyTier。 /// - roomCode: 房间码。若不合法,将在 `createRoom()` 中抛出 `RoomError.invalidRoomCode` 错误。 @@ -54,8 +55,11 @@ public final class ScaffoldingServer { self.handler.server = self } - /// 启动连接监听器。 - public func startListener() async throws { + /// 启动联机中心监听器。 + /// + /// 默认会在 `13452` 端口监听。若该端口被占用,会重新申请一个端口。 + /// - Returns: 联机中心端口号。 + public func startListener() async throws -> UInt16 { let port: UInt16 = try ConnectionUtil.getPort(13452) listener = try NWListener(using: .tcp, on: .init(integerLiteral: port)) listener.newConnectionHandler = { connection in @@ -100,9 +104,12 @@ public final class ScaffoldingServer { listener.start(queue: Scaffolding.networkQueue) } Logger.info("ScaffoldingServer listener started at 127.0.0.1:\(port)") + return port } /// 创建 EasyTier 网络。 + /// + /// 如果只是本地测试,无需创建 EasyTier 网络,可以直接使用 `ScaffoldingClient.connectDirectly(port:)` 连接。 /// - Parameter terminationHandler: 进程退出回调,不会在正常关闭时被调用。 public func createRoom(terminationHandler: ((Process) -> Void)? = nil) throws { guard let listener = listener, diff --git a/Sources/SwiftScaffolding/Util/ByteBuffer.swift b/Sources/SwiftScaffolding/Util/ByteBuffer.swift index 2e66326..b6fec55 100644 --- a/Sources/SwiftScaffolding/Util/ByteBuffer.swift +++ b/Sources/SwiftScaffolding/Util/ByteBuffer.swift @@ -13,14 +13,13 @@ public class ByteBuffer { // MARK: - 初始化 - /// 构造一个 `ByteBuffer` 用于读取数据包内容 - /// - Parameter data: 数据包内容 + /// 构造一个 `ByteBuffer` 用于读取 `Data`。 public init(data: Data) { self.data = data self.index = 0 } - /// 构造一个 `ByteBuffer` 用于写入数据 + /// 构造一个 `ByteBuffer` 用于写入数据。 public init() { self.data = Data() self.index = 0 @@ -28,9 +27,11 @@ public class ByteBuffer { // MARK: - 读取 - /// 读取 `n` 个字节的数据 - /// - Parameter length: 读取的数据长度 - /// - Returns: 长度为 `length` 字节的 `Data` + /// 读取 `n` 个字节的数据。 + /// + /// - Parameter length: 读取的数据长度。 + /// - Returns: 长度为 `length` 字节的 `Data`。 + /// - Throws: 若剩余字节不足,抛出 `ConnectionError.notEnoughBytes` 错误。 public func readData(length: any BinaryInteger) throws -> Data { guard let intLength: Int = .init(exactly: length) else { throw ConnectionError.notEnoughBytes @@ -43,24 +44,27 @@ public class ByteBuffer { return data.subdata(in: index.. UInt8 { let data: Data = try readData(length: 1) let value: UInt8 = data.withUnsafeBytes { $0.load(as: UInt8.self) } return value } - /// 读取一个 `UInt16`(大端序) - /// - Returns: UInt16 + /// 读取一个 `UInt16`(大端序)。 + /// + /// - Throws: 若剩余字节不足,抛出 `ConnectionError.notEnoughBytes` 错误。 public func readUInt16() throws -> UInt16 { let data: Data = try readData(length: 2) let value: UInt16 = data.withUnsafeBytes { $0.load(as: UInt16.self).bigEndian } return value } - /// 读取一个 `UInt32`(大端序) - /// - Returns: UInt32 + /// 读取一个 `UInt32`(大端序)。 + /// + /// - Throws: 若剩余字节不足,抛出 `ConnectionError.notEnoughBytes` 错误。 public func readUInt32() throws -> UInt32 { let data: Data = try readData(length: 4) let value: UInt32 = data.withUnsafeBytes { $0.load(as: UInt32.self).bigEndian } @@ -70,6 +74,9 @@ public class ByteBuffer { /// 读取一个 **UTF-8** 字符串。 /// /// - Parameter length: 字符串长度。 + /// - Throws: + /// - 若剩余字节不足,抛出 `ConnectionError.notEnoughBytes` 错误。 + /// - 若解析字符串失败,抛出 `ConnectionError.failedToDecodeString` 错误。 public func readString(_ length: (any BinaryInteger)? = nil) throws -> String { let length: any BinaryInteger = length ?? data.count let data: Data = try readData(length: length) diff --git a/Sources/SwiftScaffolding/Util/ConnectionUtil.swift b/Sources/SwiftScaffolding/Util/ConnectionUtil.swift index 0c07e52..31ddf5f 100644 --- a/Sources/SwiftScaffolding/Util/ConnectionUtil.swift +++ b/Sources/SwiftScaffolding/Util/ConnectionUtil.swift @@ -10,6 +10,8 @@ import Network internal enum ConnectionUtil { /// 向目标地址创建一个 TCP 连接。 + /// + /// 该方法会在 `connection.state` 变为 `.ready` 时正常返回。 /// - Parameters: /// - host: 目标地址。 /// - port: 目标端口。 diff --git a/Sources/SwiftScaffolding/Util/RoomCode.swift b/Sources/SwiftScaffolding/Util/RoomCode.swift index bfff2bd..e61f864 100644 --- a/Sources/SwiftScaffolding/Util/RoomCode.swift +++ b/Sources/SwiftScaffolding/Util/RoomCode.swift @@ -7,11 +7,12 @@ import Foundation -/// https://github.com/Scaffolding-MC/Scaffolding-MC/blob/main/README.md#联机房间码 +/// 规范文档:[Scaffolding-MC/Scaffolding-MC](https://github.com/Scaffolding-MC/Scaffolding-MC/blob/main/README.md#联机房间码) public enum RoomCode { private static let charset: [Character] = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ".map { $0 } /// 生成符合 Scaffolding 规范的房间码。 + /// /// - Returns: 生成的房间码。 public static func generate() -> String { let b: Int = 34 @@ -40,6 +41,7 @@ public enum RoomCode { } /// 验证是否是符合 Scaffolding 规范的房间码。 + /// /// - Parameter code: 房间码。 /// - Returns: 一个布尔值,为 `true` 时代表该房间码符合 Scaffolding 规范。 public static func isValid(code: String) -> Bool {