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/session_messager.h"
6
7 #include "absl/strings/ascii.h"
8 #include "cast/common/public/message_port.h"
9 #include "cast/streaming/message_fields.h"
10 #include "util/json/json_helpers.h"
11 #include "util/json/json_serialization.h"
12 #include "util/osp_logging.h"
13
14 namespace openscreen {
15 namespace cast {
16
SessionMessager(MessagePort * message_port,std::string source_id,ErrorCallback cb)17 SessionMessager::SessionMessager(MessagePort* message_port,
18 std::string source_id,
19 ErrorCallback cb)
20 : message_port_(message_port), error_callback_(std::move(cb)) {
21 OSP_DCHECK(message_port_);
22 message_port_->SetClient(this, source_id);
23 }
24
~SessionMessager()25 SessionMessager::~SessionMessager() {
26 message_port_->ResetClient();
27 }
28
SetHandler(std::string message_type,SessionMessager::MessageCallback cb)29 void SessionMessager::SetHandler(std::string message_type,
30 SessionMessager::MessageCallback cb) {
31 OSP_DCHECK(std::none_of(
32 callbacks_.begin(), callbacks_.end(),
33 [message_type](std::pair<std::string, MessageCallback> pair) {
34 return pair.first == message_type;
35 }));
36
37 callbacks_.emplace_back(message_type, std::move(cb));
38 }
39
SendMessage(SessionMessager::Message message)40 Error SessionMessager::SendMessage(SessionMessager::Message message) {
41 if (message.message_namespace != kCastWebrtcNamespace) {
42 return Error(Error::Code::kParameterInvalid, "Invalid namespace");
43 }
44 if (message.body.isNull()) {
45 return Error(Error::Code::kParameterInvalid, "No body");
46 }
47 message.body[kSequenceNumber] = message.sequence_number;
48
49 auto body_or_error = json::Stringify(message.body);
50 if (body_or_error.is_error()) {
51 return std::move(body_or_error.error());
52 }
53
54 OSP_DVLOG << "Sending message: DESTINATION[" << message.sender_id
55 << "], NAMESPACE[" << message.message_namespace << "], BODY:\n"
56 << body_or_error.value();
57 message_port_->PostMessage(message.sender_id, message.message_namespace,
58 body_or_error.value());
59 return Error::None();
60 }
61
OnMessage(const std::string & source_id,const std::string & message_namespace,const std::string & message)62 void SessionMessager::OnMessage(const std::string& source_id,
63 const std::string& message_namespace,
64 const std::string& message) {
65 ErrorOr<Json::Value> message_json = json::Parse(message);
66 if (message_namespace != kCastWebrtcNamespace) {
67 OSP_DLOG_WARN << "Received message with unknown namespace: "
68 << message_namespace;
69 return;
70 }
71
72 if (!message_json) {
73 OSP_DLOG_WARN << "Received an invalid message: " << message;
74 error_callback_(Error::Code::kJsonParseError);
75 return;
76 }
77 OSP_DVLOG << "Received a message: " << message;
78
79 int sequence_number;
80 if (!json::ParseAndValidateInt(message_json.value()[kSequenceNumber],
81 &sequence_number)) {
82 OSP_DLOG_WARN << "Invalid message sequence number";
83 return;
84 }
85
86 std::string type;
87 if (!json::ParseAndValidateString(message_json.value()[kMessageType],
88 &type)) {
89 OSP_DLOG_WARN << "Invalid message key";
90 return;
91 }
92
93 // Not all messages have results, but if they do the result must be OK.
94 std::string result;
95 if (!json::ParseAndValidateString(message_json.value()[kResult], &result)) {
96 result.clear();
97 }
98
99 for (const auto& pair : callbacks_) {
100 if (pair.first == type) {
101 // Currently all body keys are the lowercase version of the message type
102 // key. This may need to be refactored if this is no longer the case.
103 absl::AsciiStrToLower(&type);
104 Json::Value body;
105 if (result.empty() || result == kResultOk) {
106 body = message_json.value()[type];
107 } else {
108 body = message_json.value()[kErrorMessageBody];
109 }
110 pair.second(Message{source_id.data(), message_namespace.data(),
111 sequence_number, std::move(body)});
112 return;
113 }
114 }
115 }
116
OnError(Error error)117 void SessionMessager::OnError(Error error) {
118 OSP_DLOG_WARN << "Received an error in the session messager: " << error;
119 }
120
121 } // namespace cast
122 } // namespace openscreen
123