1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/streaming/sender_message.h"
6
7 #include <utility>
8
9 #include "absl/strings/ascii.h"
10 #include "cast/streaming/message_fields.h"
11 #include "util/base64.h"
12 #include "util/enum_name_table.h"
13 #include "util/json/json_helpers.h"
14 #include "util/json/json_serialization.h"
15
16 namespace openscreen {
17 namespace cast {
18
19 namespace {
20
21 EnumNameTable<SenderMessage::Type, 4> kMessageTypeNames{
22 {{kMessageTypeOffer, SenderMessage::Type::kOffer},
23 {"GET_STATUS", SenderMessage::Type::kGetStatus},
24 {"GET_CAPABILITIES", SenderMessage::Type::kGetCapabilities},
25 {"RPC", SenderMessage::Type::kRpc}}};
26
GetMessageType(const Json::Value & root)27 SenderMessage::Type GetMessageType(const Json::Value& root) {
28 std::string type;
29 if (!json::ParseAndValidateString(root[kMessageType], &type)) {
30 return SenderMessage::Type::kUnknown;
31 }
32
33 absl::AsciiStrToUpper(&type);
34 ErrorOr<SenderMessage::Type> parsed = GetEnum(kMessageTypeNames, type);
35
36 return parsed.value(SenderMessage::Type::kUnknown);
37 }
38
39 } // namespace
40
41 // static
Parse(const Json::Value & value)42 ErrorOr<SenderMessage> SenderMessage::Parse(const Json::Value& value) {
43 if (!value) {
44 return Error(Error::Code::kParameterInvalid, "Empty JSON");
45 }
46
47 SenderMessage message;
48 message.type = GetMessageType(value);
49 if (!json::ParseAndValidateInt(value[kSequenceNumber],
50 &(message.sequence_number))) {
51 message.sequence_number = -1;
52 }
53
54 if (message.type == SenderMessage::Type::kOffer) {
55 ErrorOr<Offer> offer = Offer::Parse(value[kOfferMessageBody]);
56 if (offer.is_value()) {
57 message.body = std::move(offer.value());
58 message.valid = true;
59 }
60 } else if (message.type == SenderMessage::Type::kRpc) {
61 std::string rpc_body;
62 if (json::ParseAndValidateString(value[kRpcMessageBody], &rpc_body) &&
63 base64::Decode(rpc_body, &rpc_body)) {
64 message.body = rpc_body;
65 message.valid = true;
66 }
67 } else if (message.type == SenderMessage::Type::kGetStatus ||
68 message.type == SenderMessage::Type::kGetCapabilities) {
69 // These types of messages just don't have a body.
70 message.valid = true;
71 }
72
73 return message;
74 }
75
ToJson() const76 ErrorOr<Json::Value> SenderMessage::ToJson() const {
77 OSP_CHECK(type != SenderMessage::Type::kUnknown)
78 << "Trying to send an unknown message is a developer error";
79
80 Json::Value root;
81 ErrorOr<const char*> message_type = GetEnumName(kMessageTypeNames, type);
82 root[kMessageType] = message_type.value();
83 if (sequence_number >= 0) {
84 root[kSequenceNumber] = sequence_number;
85 }
86
87 switch (type) {
88 case SenderMessage::Type::kOffer:
89 root[kOfferMessageBody] = absl::get<Offer>(body).ToJson().value();
90 break;
91
92 case SenderMessage::Type::kRpc:
93 root[kRpcMessageBody] = base64::Encode(absl::get<std::string>(body));
94 break;
95
96 case SenderMessage::Type::kGetCapabilities: // fallthrough
97 case SenderMessage::Type::kGetStatus:
98 break;
99
100 default:
101 OSP_NOTREACHED();
102 }
103 return root;
104 }
105
106 } // namespace cast
107 } // namespace openscreen
108