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