Reputation: 1064
The server I'm talking to expects a message in the format:
{
"command": "subscribe",
"identifier": "{\"channel\": \"UserChannel\"}",
"data": "{\"key\": \"value\"}"
}
Where the identifier
and data
values is an escaped json string.
I have this so far:
struct ActionCableMessage<Message: Encodable>: Encodable {
let command: Command
let identifier: CableChannel
let data: Message?
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(command, forKey: .command)
try container.encode(identifier, forKey: .identifier) // ????
}
private enum CodingKeys: String, CodingKey {
case command, identifier, data
}
}
But I don't know what to do from here. I think I need a protocol
that CableChannel
and Message
can conform to, with a provided extension
func that implements encode (to encoder: Encoder)
, which ensures Encoder
must be a JSONEncoder
, and if so, uses that to rewrite it's own value as a escaped json string.
I also need to decode this back to the ActionCableMessage
struct, but I haven't gotten that far yet.
Upvotes: 4
Views: 1066
Reputation: 273540
I think I need a protocol that CableChannel and Message can conform to
Well, that protocol is Encodable
(or Codable
if you prefer).
// just implement these as you normally would
extension CableChannel : Encodable { ... }
extension Message : Encodable { ... }
Then in ActionCableMessage
, you use another encoder to encode the inner objects to JSON data, then convert that to string, then encode that string:
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(command, forKey: .command)
let subencoder = JSONEncoder()
let identifierString = try String(data: subencoder.encode(identifier), encoding: .utf8)
try container.encode(identifierString, forKey: .identifier)
// do the same for "data"
}
Similarly for decoding:
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
command = try container.decode(String.self, forKey: .command)
let identifierJSONString = try container.decode(String.self, forKey: .identifier)
// do the same for "data"
let subdecoder = JSONDecoder()
identifier = try subdecoder.decode(CableChannel.self, from: identifierJSONString.data(using: .utf8)!)
// do the same for "data"
}
Upvotes: 2