rble 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +169 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +514 -0
  5. data/exe/rble +14 -0
  6. data/ext/macos_ble/Package.swift +20 -0
  7. data/ext/macos_ble/Sources/RBLEHelper/BLEManager.swift +783 -0
  8. data/ext/macos_ble/Sources/RBLEHelper/Protocol.swift +173 -0
  9. data/ext/macos_ble/Sources/RBLEHelper/main.swift +645 -0
  10. data/ext/macos_ble/extconf.rb +73 -0
  11. data/lib/rble/backend/base.rb +181 -0
  12. data/lib/rble/backend/bluez.rb +1279 -0
  13. data/lib/rble/backend/corebluetooth.rb +653 -0
  14. data/lib/rble/backend.rb +193 -0
  15. data/lib/rble/bluez/adapter.rb +169 -0
  16. data/lib/rble/bluez/async_call.rb +85 -0
  17. data/lib/rble/bluez/async_connection_operations.rb +492 -0
  18. data/lib/rble/bluez/async_gatt_operations.rb +249 -0
  19. data/lib/rble/bluez/async_introspection.rb +151 -0
  20. data/lib/rble/bluez/dbus_connection.rb +64 -0
  21. data/lib/rble/bluez/dbus_session.rb +344 -0
  22. data/lib/rble/bluez/device.rb +86 -0
  23. data/lib/rble/bluez/event_loop.rb +153 -0
  24. data/lib/rble/bluez/gatt_operation_queue.rb +129 -0
  25. data/lib/rble/bluez/pairing_agent.rb +132 -0
  26. data/lib/rble/bluez/pairing_session.rb +212 -0
  27. data/lib/rble/bluez/retry_policy.rb +55 -0
  28. data/lib/rble/bluez.rb +33 -0
  29. data/lib/rble/characteristic.rb +237 -0
  30. data/lib/rble/cli/adapter.rb +88 -0
  31. data/lib/rble/cli/characteristic_helpers.rb +154 -0
  32. data/lib/rble/cli/doctor.rb +309 -0
  33. data/lib/rble/cli/formatters/json.rb +122 -0
  34. data/lib/rble/cli/formatters/text.rb +157 -0
  35. data/lib/rble/cli/hex_dump.rb +48 -0
  36. data/lib/rble/cli/monitor.rb +129 -0
  37. data/lib/rble/cli/pair.rb +103 -0
  38. data/lib/rble/cli/paired.rb +22 -0
  39. data/lib/rble/cli/read.rb +55 -0
  40. data/lib/rble/cli/scan.rb +88 -0
  41. data/lib/rble/cli/show.rb +109 -0
  42. data/lib/rble/cli/status.rb +25 -0
  43. data/lib/rble/cli/unpair.rb +39 -0
  44. data/lib/rble/cli/value_parser.rb +211 -0
  45. data/lib/rble/cli/write.rb +196 -0
  46. data/lib/rble/cli.rb +152 -0
  47. data/lib/rble/company_ids.rb +90 -0
  48. data/lib/rble/connection.rb +539 -0
  49. data/lib/rble/device.rb +54 -0
  50. data/lib/rble/errors.rb +317 -0
  51. data/lib/rble/gatt/uuid_database.rb +395 -0
  52. data/lib/rble/scanner.rb +219 -0
  53. data/lib/rble/service.rb +41 -0
  54. data/lib/rble/tasks/check.rake +154 -0
  55. data/lib/rble/tasks/integration.rake +242 -0
  56. data/lib/rble/tasks.rb +8 -0
  57. data/lib/rble/version.rb +5 -0
  58. data/lib/rble.rb +62 -0
  59. metadata +120 -0
@@ -0,0 +1,173 @@
1
+ import Foundation
2
+
3
+ // MARK: - Standard JSON-RPC Error Codes
4
+ enum ErrorCode {
5
+ static let parseError = -32700 // Invalid JSON
6
+ static let invalidRequest = -32600 // Invalid request object
7
+ static let methodNotFound = -32601 // Method not found
8
+ static let invalidParams = -32602 // Invalid method parameters
9
+ static let internalError = -32603 // Internal error
10
+ }
11
+
12
+ // MARK: - Request (Ruby -> Swift)
13
+ struct Request: Codable {
14
+ let id: Int
15
+ let method: String
16
+ let params: [String: AnyCodable]?
17
+ }
18
+
19
+ // MARK: - Response (Swift -> Ruby)
20
+ struct Response: Codable {
21
+ let id: Int
22
+ let result: [String: AnyCodable]?
23
+ let error: ResponseError?
24
+
25
+ init(id: Int, result: [String: AnyCodable]? = nil, error: ResponseError? = nil) {
26
+ self.id = id
27
+ self.result = result
28
+ self.error = error
29
+ }
30
+
31
+ static func success(id: Int, result: [String: AnyCodable]) -> Response {
32
+ Response(id: id, result: result, error: nil)
33
+ }
34
+
35
+ static func error(id: Int, code: Int, message: String, data: [String: String]? = nil) -> Response {
36
+ Response(id: id, result: nil, error: ResponseError(code: code, message: message, data: data))
37
+ }
38
+ }
39
+
40
+ // MARK: - Response Error
41
+ struct ResponseError: Codable {
42
+ let code: Int
43
+ let message: String
44
+ let data: [String: String]?
45
+
46
+ init(code: Int, message: String, data: [String: String]? = nil) {
47
+ self.code = code
48
+ self.message = message
49
+ self.data = data
50
+ }
51
+ }
52
+
53
+ // MARK: - Event (Swift -> Ruby, asynchronous notifications)
54
+ struct Event: Codable {
55
+ let method: String
56
+ let params: [String: AnyCodable]
57
+
58
+ init(method: String, params: [String: AnyCodable]) {
59
+ self.method = method
60
+ self.params = params
61
+ }
62
+ }
63
+
64
+ // MARK: - AnyCodable Type-Erased Wrapper
65
+ /// A type-erased Codable wrapper that handles common JSON types:
66
+ /// String, Int, Double, Bool, Array, Dictionary, and null
67
+ struct AnyCodable: Codable {
68
+ let value: Any
69
+
70
+ init(_ value: Any) {
71
+ self.value = value
72
+ }
73
+
74
+ init(from decoder: Decoder) throws {
75
+ let container = try decoder.singleValueContainer()
76
+
77
+ if container.decodeNil() {
78
+ value = NSNull()
79
+ } else if let bool = try? container.decode(Bool.self) {
80
+ value = bool
81
+ } else if let int = try? container.decode(Int.self) {
82
+ value = int
83
+ } else if let double = try? container.decode(Double.self) {
84
+ value = double
85
+ } else if let string = try? container.decode(String.self) {
86
+ value = string
87
+ } else if let array = try? container.decode([AnyCodable].self) {
88
+ value = array.map { $0.value }
89
+ } else if let dict = try? container.decode([String: AnyCodable].self) {
90
+ value = dict.mapValues { $0.value }
91
+ } else {
92
+ throw DecodingError.dataCorruptedError(
93
+ in: container,
94
+ debugDescription: "AnyCodable cannot decode value"
95
+ )
96
+ }
97
+ }
98
+
99
+ func encode(to encoder: Encoder) throws {
100
+ var container = encoder.singleValueContainer()
101
+
102
+ if value is NSNull {
103
+ try container.encodeNil()
104
+ } else if let bool = value as? Bool {
105
+ try container.encode(bool)
106
+ } else if let int = value as? Int {
107
+ try container.encode(int)
108
+ } else if let double = value as? Double {
109
+ try container.encode(double)
110
+ } else if let string = value as? String {
111
+ try container.encode(string)
112
+ } else if let array = value as? [Any] {
113
+ try container.encode(array.map { AnyCodable($0) })
114
+ } else if let dict = value as? [String: Any] {
115
+ try container.encode(dict.mapValues { AnyCodable($0) })
116
+ } else {
117
+ throw EncodingError.invalidValue(
118
+ value,
119
+ EncodingError.Context(
120
+ codingPath: encoder.codingPath,
121
+ debugDescription: "AnyCodable cannot encode value of type \(type(of: value))"
122
+ )
123
+ )
124
+ }
125
+ }
126
+ }
127
+
128
+ // MARK: - AnyCodable Convenience Extensions
129
+ extension AnyCodable: ExpressibleByStringLiteral {
130
+ init(stringLiteral value: String) {
131
+ self.value = value
132
+ }
133
+ }
134
+
135
+ extension AnyCodable: ExpressibleByIntegerLiteral {
136
+ init(integerLiteral value: Int) {
137
+ self.value = value
138
+ }
139
+ }
140
+
141
+ extension AnyCodable: ExpressibleByFloatLiteral {
142
+ init(floatLiteral value: Double) {
143
+ self.value = value
144
+ }
145
+ }
146
+
147
+ extension AnyCodable: ExpressibleByBooleanLiteral {
148
+ init(booleanLiteral value: Bool) {
149
+ self.value = value
150
+ }
151
+ }
152
+
153
+ extension AnyCodable: ExpressibleByArrayLiteral {
154
+ init(arrayLiteral elements: Any...) {
155
+ self.value = elements
156
+ }
157
+ }
158
+
159
+ extension AnyCodable: ExpressibleByDictionaryLiteral {
160
+ init(dictionaryLiteral elements: (String, Any)...) {
161
+ var dict: [String: Any] = [:]
162
+ for (key, value) in elements {
163
+ dict[key] = value
164
+ }
165
+ self.value = dict
166
+ }
167
+ }
168
+
169
+ extension AnyCodable: ExpressibleByNilLiteral {
170
+ init(nilLiteral: ()) {
171
+ self.value = NSNull()
172
+ }
173
+ }