Skip to content

Commit ddc8f84

Browse files
authored
Merge pull request #44 from orchetect/from-address
Remote host & port provided in event receive handlers
2 parents 9b838f0 + 4212583 commit ddc8f84

File tree

27 files changed

+391
-184
lines changed

27 files changed

+391
-184
lines changed

.swiftpm/xcode/xcshareddata/xcschemes/OSCKit-CI.xcscheme

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@
8282
</BuildableReference>
8383
</TestableReference>
8484
<TestableReference
85-
skipped = "NO">
85+
skipped = "NO"
86+
parallelizable = "NO">
8687
<BuildableReference
8788
BuildableIdentifier = "primary"
8889
BlueprintIdentifier = "OSCKitTests"

Examples/Basic Example/Basic Example/OSCManager.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ extension OSCManager {
2626
do { try client.start() } catch { print(error) }
2727

2828
// setup server
29-
server.setHandler { [weak self] message, timeTag in
30-
self?.handle(message: message, timeTag: timeTag)
29+
server.setHandler { [weak self] message, timeTag, host, port in
30+
self?.handle(message: message, timeTag: timeTag, host: host, port: port)
3131
}
3232
do { try server.start() } catch { print(error) }
3333
}
@@ -41,8 +41,8 @@ extension OSCManager {
4141
// MARK: - Receive
4242

4343
extension OSCManager {
44-
func handle(message: OSCMessage, timeTag: OSCTimeTag) {
45-
print("\(message) with time tag: \(timeTag)")
44+
func handle(message: OSCMessage, timeTag: OSCTimeTag, host: String, port: UInt16) {
45+
print("\(message) with time tag: \(timeTag) from: \(host):\(port)")
4646
}
4747
}
4848

Examples/Custom Type Example/Custom Type Example/OSCManager.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ extension OSCManager {
3232
do { try client.start() } catch { print(error) }
3333

3434
// setup server
35-
server.setHandler { [weak self] message, timeTag in
36-
self?.handle(message: message, timeTag: timeTag)
35+
server.setHandler { [weak self] message, timeTag, host, port in
36+
self?.handle(message: message, timeTag: timeTag, host: host, port: port)
3737
}
3838
do { try server.start() } catch { print(error) }
3939
}
@@ -47,15 +47,15 @@ extension OSCManager {
4747
// MARK: - Receive
4848

4949
extension OSCManager {
50-
func handle(message: OSCMessage, timeTag: OSCTimeTag) {
50+
func handle(message: OSCMessage, timeTag: OSCTimeTag, host: String, port: UInt16) {
5151
do {
5252
let customTypeValue = try message.values.masked(CustomType.self)
5353

5454
let msg = message.addressPattern.stringValue
5555
let id = customTypeValue.id
5656
let name = customTypeValue.name
5757
print(
58-
"OSC message with address \"\(msg)\" with CustomType value containing id:\(id) and name:\(name)"
58+
"OSC message from \(host):\(port), address \"\(msg)\", CustomType value containing id:\(id) and name:\(name)"
5959
)
6060
} catch {
6161
print("OSC message received that did not have exactly one value of type CustomType.")

Examples/Method Blocks Example/Method Blocks Example/OSCManager.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ extension OSCManager {
2727
do { try client.start() } catch { print(error) }
2828

2929
// setup server
30-
server.setHandler { [weak self] message, timeTag in
30+
server.setHandler { [weak self] message, timeTag, host, port in
3131
do {
32-
try self?.receiver.handle(message: message, timeTag: timeTag)
32+
try self?.receiver.handle(message: message, timeTag: timeTag, host: host, port: port)
3333
} catch {
3434
print(error)
3535
}

Examples/Method Blocks Example/Method Blocks Example/OSCReceiver.swift

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,25 @@ final class OSCReceiver: Sendable {
1515

1616
public init() {
1717
// Register local OSC method and supply a closure block
18-
addressSpace.register(localAddress: "/methodA") { values in
18+
addressSpace.register(localAddress: "/methodA") { values, host, port in
1919
guard let str = try? values.masked(String.self) else { return }
20-
print("Received methodA with value: \"\(str)\"")
20+
print("Received methodA from \(host):\(port) with value: \"\(str)\"")
2121
}
2222

2323
// Register local OSC method and supply a closure block
24-
addressSpace.register(localAddress: "/some/address/methodB") { values in
24+
addressSpace.register(localAddress: "/some/address/methodB") { values, host, port in
2525
guard let (str, int) = try? values.masked(String.self, Int.self) else { return }
26-
print("Received methodB with values: [\"\(str)\", \(int)]")
26+
print("Received methodB from \(host):\(port) with values: [\"\(str)\", \(int)]")
2727
}
2828

2929
// Instead of supplying a closure, it's also possible to forward to a function:
3030

3131
// Option 1: weak reference (recommended):
3232
addressSpace.register(
3333
localAddress: "/some/address/methodC",
34-
block: { [weak self] in self?.handleMethodC($0) }
34+
block: { [weak self] values, host, port in
35+
self?.handleMethodC(values: values, host: host, port: port)
36+
}
3537
)
3638

3739
// Option 2: strong reference (discouraged):
@@ -41,14 +43,14 @@ final class OSCReceiver: Sendable {
4143
// )
4244
}
4345

44-
private func handleMethodC(_ values: OSCValues) {
46+
private func handleMethodC(values: OSCValues, host: String, port: UInt16) {
4547
guard let (str, dbl) = try? values.masked(String.self, Double?.self) else { return }
46-
print("Received methodC with values: [\"\(str)\", \(dbl as Any)]")
48+
print("Received methodC from \(host):\(port) with values: [\"\(str)\", \(dbl as Any)]")
4749
}
4850

49-
public func handle(message: OSCMessage, timeTag: OSCTimeTag) throws {
51+
public func handle(message: OSCMessage, timeTag: OSCTimeTag, host: String, port: UInt16) throws {
5052
// Execute closures for matching methods, and returns the matching method IDs
51-
let methodIDs = addressSpace.dispatch(message)
53+
let methodIDs = addressSpace.dispatch(message: message, host: host, port: port)
5254

5355
// If no IDs are returned, it means that the OSC message address pattern did not match any
5456
// that were registered

Examples/Method IDs Example/Method IDs Example/OSCManager.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ extension OSCManager {
2727
do { try client.start() } catch { print(error) }
2828

2929
// setup server
30-
server.setHandler { [weak self] message, timeTag in
30+
server.setHandler { [weak self] message, timeTag, host, port in
3131
do {
32-
try self?.receiver.handle(message: message, timeTag: timeTag)
32+
try self?.receiver.handle(message: message, timeTag: timeTag, host: host, port: port)
3333
} catch {
3434
print(error)
3535
}

Examples/Method IDs Example/Method IDs Example/OSCReceiver.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ final class OSCReceiver: Sendable {
2424
idMethodC = addressSpace.register(localAddress: "/some/address/methodC")
2525
}
2626

27-
public func handle(message: OSCMessage, timeTag: OSCTimeTag) throws {
27+
public func handle(message: OSCMessage, timeTag: OSCTimeTag, host: String, port: UInt16) throws {
2828
let ids = addressSpace.methods(matching: message.addressPattern)
2929

3030
guard !ids.isEmpty else {
@@ -33,7 +33,7 @@ final class OSCReceiver: Sendable {
3333
return
3434
}
3535

36-
try ids.forEach { id in
36+
for id in ids {
3737
switch id {
3838
case idMethodA:
3939
let str = try message.values.masked(String.self)

Examples/Socket Example/Socket Example/OSCManager.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ extension OSCManager {
3636
)
3737
socket = newSocket
3838

39-
newSocket.setHandler { message, timeTag in
40-
print(message, "with time tag: \(timeTag)")
39+
newSocket.setHandler { message, timeTag, host, port in
40+
print("\(host):\(port) - \(message) with time tag: \(timeTag)")
4141
}
4242

4343
try newSocket.start()
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//
2+
// OSCKit-API-1.2.0.swift
3+
// OSCKit • https://github.com/orchetect/OSCKit
4+
// © 2020-2025 Steffan Andrews • Licensed under MIT License
5+
//
6+
7+
#if !os(watchOS)
8+
9+
import Foundation
10+
11+
/// Received-message handler closure used by OSCKit socket classes.
12+
@_documentation(visibility: internal)
13+
@available(*, deprecated, renamed: "OSCHandlerBlock")
14+
public typealias LegacyOSCHandlerBlock = @Sendable (
15+
_ message: OSCMessage,
16+
_ timeTag: OSCTimeTag
17+
) -> Void
18+
19+
extension OSCServer {
20+
@_documentation(visibility: internal)
21+
@available(
22+
*,
23+
deprecated,
24+
message: "Handler closure now takes 4 parameters: message, timeTag, host, port."
25+
)
26+
@_disfavoredOverload
27+
public convenience init(
28+
port: UInt16 = 8000,
29+
timeTagMode: OSCTimeTagMode = .ignore,
30+
receiveQueue: DispatchQueue? = nil,
31+
handler: @escaping LegacyOSCHandlerBlock
32+
) {
33+
self.init(
34+
port: port,
35+
timeTagMode: timeTagMode,
36+
receiveQueue: receiveQueue,
37+
handler: { message, timeTag, _, _ in handler(message, timeTag) }
38+
)
39+
}
40+
41+
@_documentation(visibility: internal)
42+
@available(
43+
*,
44+
deprecated,
45+
message: "Handler closure now takes 4 parameters: message, timeTag, host, port."
46+
)
47+
@_disfavoredOverload
48+
public func setHandler(
49+
_ handler: @escaping LegacyOSCHandlerBlock
50+
) {
51+
setHandler { message, timeTag, _, _ in handler(message, timeTag) }
52+
}
53+
}
54+
55+
extension OSCSocket {
56+
@_documentation(visibility: internal)
57+
@available(
58+
*,
59+
deprecated,
60+
message: "Handler closure now takes 4 parameters: message, timeTag, host, port."
61+
)
62+
@_disfavoredOverload
63+
public convenience init(
64+
localPort: UInt16? = nil,
65+
remoteHost: String? = nil,
66+
remotePort: UInt16? = nil,
67+
timeTagMode: OSCTimeTagMode = .ignore,
68+
isIPv4BroadcastEnabled: Bool = false,
69+
receiveQueue: DispatchQueue? = nil,
70+
handler: @escaping LegacyOSCHandlerBlock
71+
) {
72+
self.init(
73+
localPort: localPort,
74+
remoteHost: remoteHost,
75+
remotePort: remotePort,
76+
timeTagMode: timeTagMode,
77+
isIPv4BroadcastEnabled: isIPv4BroadcastEnabled,
78+
receiveQueue: nil,
79+
handler: { message, timeTag, _, _ in handler(message, timeTag) }
80+
)
81+
}
82+
83+
@_documentation(visibility: internal)
84+
@available(
85+
*,
86+
deprecated,
87+
message: "Handler closure now takes 4 parameters: message, timeTag, host, port."
88+
)
89+
@_disfavoredOverload
90+
public func setHandler(
91+
_ handler: @escaping LegacyOSCHandlerBlock
92+
) {
93+
setHandler { message, timeTag, _, _ in handler(message, timeTag) }
94+
}
95+
}
96+
97+
#endif

Sources/OSCKit/OSCHandlerBlock.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ import OSCKitCore
1010
/// Received-message handler closure used by OSCKit socket classes.
1111
public typealias OSCHandlerBlock = @Sendable (
1212
_ message: OSCMessage,
13-
_ timeTag: OSCTimeTag
13+
_ timeTag: OSCTimeTag,
14+
_ host: String,
15+
_ port: UInt16
1416
) -> Void

Sources/OSCKit/OSCKit.docc/OSC-Address-Pattern-Parsing.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ potential destinations of OSC messages received by the OSC server and correspond
2020
points of control that the application makes available.
2121

2222
The `methodname` path component is the method name in the following address examples:
23-
```
24-
/methodname
25-
/container1/container2/methodname
26-
```
23+
24+
```
25+
/methodname
26+
/container1/container2/methodname
27+
```
2728

2829
Any other path components besides the last are referred to as _containers_.
2930

@@ -35,7 +36,7 @@ Simple matching can be performed using the ``OSCAddressPattern/matches(localAddr
3536

3637
```swift
3738
// example: received OSC message with address "/{some,other}/address/*"
38-
private func handle(received message: OSCMessage) throws {
39+
private func handle(message: OSCMessage, host: String, port: UInt16) throws {
3940
let pattern = message.addressPattern
4041
if pattern.matches(localAddress: "/some/address/methodA") {
4142
// (will match in this example)
@@ -76,10 +77,10 @@ let idMethodB = addressSpace.register(localAddress: "/some/address/methodB")
7677
```
7778

7879
```swift
79-
func handle(message: OSCMessage) throws {
80+
func handle(message: OSCMessage, host: String, port: UInt16) throws {
8081
let ids = addressSpace.methods(matching: message.addressPattern)
8182

82-
try ids.forEach { id in
83+
for id in ids {
8384
switch id {
8485
case idMethodA:
8586
let str = try message.values.masked(String.self)
@@ -101,27 +102,27 @@ func performMethodB(_ str: String, _ int: Int?) { }
101102

102103
- When registering a local method, it can also store a closure. This closure can be executed automatically when matching against a received OSC message's address pattern.
103104
- When an OSC message is received:
104-
- Pass its address pattern to the ``OSCAddressSpace/dispatch(_:)``.
105+
- Pass its address pattern to the ``OSCAddressSpace/dispatch(message:host:port:)``.
105106
- This method will pattern-match it against all registered local addresses and execute their closures.
106107
- It also returns an array of local method IDs that match exactly like ``OSCAddressSpace/methods(matching:)`` (which may be discarded if handling of unregistered/unrecognized methods is not needed).
107108
- If the returned method ID array is empty, that indicates that no methods matched the address pattern. In this case you may want to handle the unhandled message in a special way.
108109

109110
```swift
110111
// instance address space and register methods only once, usually at app startup.
111112
let addressSpace = OSCAddressSpace()
112-
addressSpace.register(localAddress: "/methodA") { values in
113+
addressSpace.register(localAddress: "/methodA") { values, host, port in
113114
guard let str = try? message.values.masked(String.self) else { return }
114115
performMethodA(str)
115116
}
116-
addressSpace.register(localAddress: "/some/address/methodB") { values in
117+
addressSpace.register(localAddress: "/some/address/methodB") { values, host, port in
117118
guard let (str, int) = try message.values.masked(String.self, Int?.self) else { return }
118119
performMethodB(str, int)
119120
}
120121
```
121122

122123
```swift
123-
func handle(message: OSCMessage) throws {
124-
let ids = addressSpace.dispatch(message)
124+
func handle(message: OSCMessage, host: String, port: UInt16) throws {
125+
let ids = addressSpace.dispatch(message: message, host: host, port: port)
125126
if ids.isEmpty {
126127
print("Received unhandled OSC message:", message)
127128
}

Sources/OSCKit/OSCKit.docc/OSC-Value-Parsing.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ print(str, int, dbl) // String, Int32?, Double?
7373
It may be desired to imperatively validate and cast values when their expected mask may be unknown.
7474

7575
```swift
76-
oscMessage.values.forEach { oscValue in
77-
switch oscValue {
76+
for value in oscMessage.values {
77+
switch value {
7878
case let val as String:
7979
print(val)
8080
case let val as Int32:
@@ -85,8 +85,6 @@ oscMessage.values.forEach { oscValue in
8585
}
8686
```
8787

88-
##
89-
9088
## Topics
9189

9290
- ``OSCValueToken``

Sources/OSCKit/OSCKit.docc/OSCServer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
let oscServer: OSCServer
77

88
init() {
9-
oscServer = OSCServer(port: 8000) { [weak self] message, timeTag in
9+
oscServer = OSCServer(port: 8000) { [weak self] message, timeTag, host, port in
1010
print("Received \(message)")
1111
}
1212
}

Sources/OSCKit/OSCKit.docc/OSCSocket.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ init() {
1616
oscSocket = OSCSocket(
1717
remoteHost: "192.168.0.2",
1818
remotePort: 10023
19-
) { [weak self] message, timeTag in
19+
) { [weak self] message, timeTag, host, port in
2020
print("Received \(message)")
2121
}
2222
}

Sources/OSCKit/OSCKit.docc/Receiving-OSC.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ Both ``OSCServer`` and ``OSCSocket`` are capable of receiving messages using the
99
If not already set during initialization, you may set the receiver handler using the ``OSCServer/setHandler(_:)`` or ``OSCSocket/setHandler(_:)`` method.
1010

1111
```swift
12-
oscServer.setHandler { [weak self] oscMessage, timeTag in
12+
oscServer.setHandler { [weak self] message, timeTag, host, port in
1313
do {
14-
try self?.handle(received: oscMessage)
14+
try self?.handle(message: message, host: host, port: port)
1515
} catch {
1616
print(error)
1717
}
1818
}
1919

20-
private func handle(received oscMessage: OSCMessage) throws {
20+
private func handle(message: OSCMessage, host: String, port: UInt16) throws {
2121
// handle received messages here
2222
}
2323
```

0 commit comments

Comments
 (0)