109 lines
3.0 KiB
Swift
109 lines
3.0 KiB
Swift
import Foundation
|
||
|
||
/// 设备命令服务:发送 JSON 命令(fire-and-forget,响应由协议层回调处理)
|
||
final class DeviceInfoService {
|
||
private let protocolService: BleProtocolService
|
||
|
||
init(protocolService: BleProtocolService) {
|
||
self.protocolService = protocolService
|
||
}
|
||
|
||
// MARK: - Commands
|
||
|
||
func getDeviceInfo() throws {
|
||
try protocolService.sendJSON(
|
||
type: .getDeviceInfo,
|
||
payload: CommandPayload(type: CommandType.getDeviceInfo.rawValue)
|
||
)
|
||
}
|
||
|
||
func getDeviceVersion() throws {
|
||
try protocolService.sendJSON(
|
||
type: .getDeviceVersion,
|
||
payload: CommandPayload(type: CommandType.getDeviceVersion.rawValue)
|
||
)
|
||
}
|
||
|
||
func bindDevice(userId: String) throws {
|
||
try protocolService.sendJSON(
|
||
type: .bindDevice,
|
||
payload: BindPayload(type: CommandType.bindDevice.rawValue, userId: userId, loop: nil)
|
||
)
|
||
}
|
||
|
||
func unbindDevice(userId: String) throws {
|
||
try protocolService.sendJSON(
|
||
type: .unbindDevice,
|
||
payload: BindPayload(type: CommandType.unbindDevice.rawValue, userId: userId, loop: nil)
|
||
)
|
||
}
|
||
|
||
/// 切换播放模式(复用 BIND_DEVICE 命令字 0x0F,payload 携带 loop 字段)
|
||
func setPlayMode(userId: String, loop: PlayMode) throws {
|
||
try protocolService.sendJSON(
|
||
type: .bindDevice,
|
||
payload: BindPayload(
|
||
type: CommandType.bindDevice.rawValue,
|
||
userId: userId,
|
||
loop: UInt8(loop.rawValue)
|
||
)
|
||
)
|
||
}
|
||
|
||
func deleteFile(key: String) throws {
|
||
try protocolService.sendJSON(
|
||
type: .deleteFile,
|
||
payload: FileKeyPayload(type: CommandType.deleteFile.rawValue, key: key)
|
||
)
|
||
}
|
||
|
||
func prepareTransfer(key: String, size: Int) throws {
|
||
try protocolService.sendJSON(
|
||
type: .prepareTransfer,
|
||
payload: PrepareTransferPayload(
|
||
type: CommandType.prepareTransfer.rawValue,
|
||
key: key,
|
||
size: size
|
||
)
|
||
)
|
||
}
|
||
}
|
||
|
||
// MARK: - Command Payloads
|
||
|
||
private struct CommandPayload: Encodable {
|
||
let type: UInt8
|
||
}
|
||
|
||
/// 绑定 / 解绑 / 切模式 共用 payload。
|
||
/// `loop == nil` 时严格省略该字段(不写 null),与 Expo 端 zod.optional 行为对齐。
|
||
struct BindPayload: Encodable {
|
||
let type: UInt8
|
||
let userId: String
|
||
let loop: UInt8?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case type, userId, loop
|
||
}
|
||
|
||
func encode(to encoder: Encoder) throws {
|
||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||
try container.encode(type, forKey: .type)
|
||
try container.encode(userId, forKey: .userId)
|
||
if let loop = loop {
|
||
try container.encode(loop, forKey: .loop)
|
||
}
|
||
}
|
||
}
|
||
|
||
private struct FileKeyPayload: Encodable {
|
||
let type: UInt8
|
||
let key: String
|
||
}
|
||
|
||
private struct PrepareTransferPayload: Encodable {
|
||
let type: UInt8
|
||
let key: String
|
||
let size: Int
|
||
}
|