Skip to content
This repository has been archived by the owner on Jun 28, 2024. It is now read-only.

Commit

Permalink
Refactor Metadata type into conforming to Codable (#6)
Browse files Browse the repository at this point in the history
Co-authored-by: Pawel Gil <>
  • Loading branch information
pawelgil authored Aug 23, 2022
1 parent 82782c9 commit 4f1f9b1
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public class PhoenixTransport: EventTransport {

/// listen for media events
self.channel!.on("mediaEvent", callback: { message in
guard let event: ReceivableEvent = Events.deserialize(payload: message.payload) else {
guard let event: ReceivableEvent = Events.deserialize(payload: Payload(message.payload)) else {
return
}

Expand Down Expand Up @@ -86,7 +86,7 @@ public class PhoenixTransport: EventTransport {
return
}

let data = try! JSONSerialization.data(withJSONObject: event.serialize(), options: JSONSerialization.WritingOptions())
let data = try! JSONEncoder().encode(event.serialize())

guard let dataPayload = String(data: data, encoding: .utf8) else {
return
Expand Down
26 changes: 13 additions & 13 deletions MembraneRTC/Sources/MembraneRTC/Events/Event.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

public typealias Payload = [String: Any?]
public typealias Payload = AnyJson

/// Protocol for outgoing `MembraneRTC` events
public protocol SendableEvent {
Expand Down Expand Up @@ -171,10 +171,10 @@ struct JoinEvent: SendableEvent {
}

func serialize() -> Payload {
return [
return .init([
"type": "join",
"data": ["metadata": metadata],
]
])
}
}

Expand All @@ -190,7 +190,7 @@ struct SdpOfferEvent: SendableEvent {
}

func serialize() -> Payload {
return [
return .init([
"type": "custom",
"data": [
"type": "sdpOffer",
Expand All @@ -203,7 +203,7 @@ struct SdpOfferEvent: SendableEvent {
"midToTrackId": midToTrackId,
],
],
]
])
}
}

Expand All @@ -217,7 +217,7 @@ struct LocalCandidateEvent: SendableEvent {
}

func serialize() -> Payload {
return [
return .init([
"type": "custom",
"data": [
"type": "candidate",
Expand All @@ -226,20 +226,20 @@ struct LocalCandidateEvent: SendableEvent {
"sdpMLineIndex": sdpMLineIndex,
],
],
]
])
}
}

struct RenegotiateTracksEvent: SendableEvent {
init() {}

func serialize() -> Payload {
return [
return .init([
"type": "custom",
"data": [
"type": "renegotiateTracks",
],
]
])
}
}

Expand Down Expand Up @@ -268,10 +268,10 @@ struct UpdatePeerMetadata: SendableEvent {
}

func serialize() -> Payload {
return [
return .init([
"type": "updatePeerMetadata",
"data": ["metadata": metadata]
]
])
}
}

Expand All @@ -285,10 +285,10 @@ struct UpdateTrackMetadata: SendableEvent {
}

func serialize() -> Payload {
return [
return .init([
"type": "updateTrackMetadata",
"data": ["trackId": trackId, "trackMetadata": trackMetadata]
]
])
}
}

Expand Down
2 changes: 1 addition & 1 deletion MembraneRTC/Sources/MembraneRTC/MembraneRTC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public class MembraneRTC: MulticastDelegate<MembraneRTCDelegate>, ObservableObje

private var localTracks: [LocalTrack] = []

private var localPeer = Peer(id: "", metadata: [:], trackIdToMetadata: [:])
private var localPeer = Peer(id: "", metadata: .init([:]), trackIdToMetadata: [:])

// mapping from peer's id to itself
private var remotePeers: [String: Peer] = [:]
Expand Down
206 changes: 206 additions & 0 deletions MembraneRTC/Sources/MembraneRTC/Types/AnyJson.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
public struct AnyJson: Codable {
private var store: [String: Any]

public init(_ dict: [String: Any] = [:]) {
self.store = dict
}

public subscript(key: String) -> Any? {
get { store[key] }
set { store[key] = newValue }
}

public var keys: Dictionary<String, Any>.Keys {
store.keys
}

// MARK: Decoding

public init(from decoder: Decoder) throws {
var container = try decoder.container(keyedBy: JSONCodingKey.self)
self.store = try Self.decodeDictionary(from: &container)
}

static func decodeDictionary(from container: inout KeyedDecodingContainer<JSONCodingKey>) throws -> [String: Any] {
var dict = [String: Any]()
for key in container.allKeys {
let value = try decode(from: &container, forKey: key)
dict[key.stringValue] = value
}
return dict
}

static func decodeArray(from container: inout UnkeyedDecodingContainer) throws -> [Any] {
var arr: [Any] = []
while !container.isAtEnd {
let value = try decode(from: &container)
arr.append(value)
}
return arr
}

static func decode(from container: inout KeyedDecodingContainer<JSONCodingKey>, forKey key: JSONCodingKey) throws -> Any {
if let value = try? container.decode(Bool.self, forKey: key) {
return value
}
if let value = try? container.decode(Int.self, forKey: key) {
return value
}
if let value = try? container.decode(Double.self, forKey: key) {
return value
}
if let value = try? container.decode(String.self, forKey: key) {
return value
}
if let value = try? container.decodeNil(forKey: key) {
if value { return Optional<Any>.none as Any }
}
if var container = try? container.nestedUnkeyedContainer(forKey: key) {
return try decodeArray(from: &container)
}
if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key) {
return try decodeDictionary(from: &container)
}
throw DecodingError.typeMismatch(AnyJson.self, .init(codingPath: container.codingPath,
debugDescription: "Couldn't parse object to Metadata: unknown type!"))
}

static func decode(from container: inout UnkeyedDecodingContainer) throws -> Any {
if let value = try? container.decode(Bool.self) {
return value
}
if let value = try? container.decode(Int.self) {
return value
}
if let value = try? container.decode(Double.self) {
return value
}
if let value = try? container.decode(String.self) {
return value
}
if let value = try? container.decodeNil() {
if value { return Optional<Any>.none as Any }
}
if var container = try? container.nestedUnkeyedContainer() {
return try decodeArray(from: &container)
}
if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self) {
return try decodeDictionary(from: &container)
}
throw DecodingError.typeMismatch(AnyJson.self, .init(codingPath: container.codingPath,
debugDescription: "Couldn't parse object to Metadata: decoding from container failed"))
}

// MARK: Encoding

public func encode(to encoder: Swift.Encoder) throws {
var container = encoder.container(keyedBy: JSONCodingKey.self)
try Self.encode(to: &container, dictionary: store)
}

static func encode(to container: inout KeyedEncodingContainer<JSONCodingKey>, dictionary: [String: Any]) throws {
for (key, value) in dictionary {
let key = JSONCodingKey(stringValue: key)!
if let value = value as? Bool {
try container.encode(value, forKey: key)
} else if let value = value as? Int {
try container.encode(value, forKey: key)
} else if let value = value as? Int16 {
try container.encode(value, forKey: key)
} else if let value = value as? Int32 {
try container.encode(value, forKey: key)
} else if let value = value as? Int64 {
try container.encode(value, forKey: key)
} else if let value = value as? Double {
try container.encode(value, forKey: key)
} else if let value = value as? String {
try container.encode(value, forKey: key)
} else if let value = value as? [Any] {
var container = container.nestedUnkeyedContainer(forKey: key)
try encode(to: &container, array: value)
} else if let value = value as? [String: Any] {
var container = container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key)
try encode(to: &container, dictionary: value)
} else if let value = value as? AnyJson {
var container = container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key)
try encode(to: &container, dictionary: value.store)
} else {
if case Optional<Any>.none = value {
try container.encodeNil(forKey: key)
} else {
throw DecodingError.typeMismatch(AnyJson.self, .init(codingPath: container.codingPath,
debugDescription: "Couldn't parse object to Metadata: unexpected type to encode: \(String(describing: value))"))
}
}
}
}

static func encode(to container: inout UnkeyedEncodingContainer, array: [Any]) throws {
for value in array {
if let value = value as? Bool {
try container.encode(value)
} else if let value = value as? Int {
try container.encode(value)
} else if let value = value as? Int32 {
try container.encode(value)
} else if let value = value as? Int64 {
try container.encode(value)
} else if let value = value as? Int16 {
try container.encode(value)
} else if let value = value as? Double {
try container.encode(value)
} else if let value = value as? String {
try container.encode(value)
} else if let value = value as? [Any] {
var container = container.nestedUnkeyedContainer()
try encode(to: &container, array: value)
} else if let value = value as? [String: Any] {
var container = container.nestedContainer(keyedBy: JSONCodingKey.self)
try encode(to: &container, dictionary: value)
} else {
if case Optional<Any>.none = value {
try container.encodeNil()
} else {
throw DecodingError.typeMismatch(AnyJson.self, .init(codingPath: container.codingPath,
debugDescription: "Couldn't parse object to Metadata: unexpected type to encode: \(String(describing: value))"))
}
}
}
}

static func encode(to container: inout SingleValueEncodingContainer, value: Any) throws {
if let value = value as? Bool {
try container.encode(value)
} else if let value = value as? Int {
try container.encode(value)
} else if let value = value as? Int32 {
try container.encode(value)
} else if let value = value as? Int64 {
try container.encode(value)
} else if let value = value as? Int16 {
try container.encode(value)
} else if let value = value as? Double {
try container.encode(value)
} else if let value = value as? String {
try container.encode(value)
} else {
if case Optional<Any>.none = value {
try container.encodeNil()
} else {
throw DecodingError.typeMismatch(AnyJson.self, .init(codingPath: container.codingPath,
debugDescription: "Couldn't parse object to Metadata: unexpected type to encode: \(String(describing: value))"))
}
}
}

// MARK: Coding keys

class JSONCodingKey : CodingKey {
let key: String
required init?(intValue: Int) { return nil }
required init?(stringValue: String) { key = stringValue }
var intValue: Int? { return nil }
var stringValue: String { return key }
}
}

6 changes: 1 addition & 5 deletions MembraneRTC/Sources/MembraneRTC/Types/Metadata.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
/// By default swift is not able to decode type of [String: Any] as
/// `Any` is not decodable. For now we will assume that the metadata is a dictionary
/// consisting of keys and values all being strings. Once this is wrong please consider
/// refactoring the json serialization/deserialization or consider making the related type explicit.
public typealias Metadata = [String: String]
public typealias Metadata = AnyJson

0 comments on commit 4f1f9b1

Please sign in to comment.