diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-17 18:50:52 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-17 18:50:52 +0000 |
commit | efd7cc50c34a77e0168f2233784912f68f60aaeb (patch) | |
tree | 69a03f2d4d9f48486b05d1d8b1b5594e8f07a64e | |
parent | 450f839ae7c238932230f624cbdf9468a5cb78e5 (diff) | |
download | chromium_src-efd7cc50c34a77e0168f2233784912f68f60aaeb.zip chromium_src-efd7cc50c34a77e0168f2233784912f68f60aaeb.tar.gz chromium_src-efd7cc50c34a77e0168f2233784912f68f60aaeb.tar.bz2 |
Implement support for messaging interface in the client plugin.
This adds support for messaging interface in the plugin. The old
interface (based on ScriptableObject) is still supported.
BUG=88353
Review URL: https://chromiumcodereview.appspot.com/9365067
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122540 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | remoting/client/plugin/chromoting_instance.cc | 336 | ||||
-rw-r--r-- | remoting/client/plugin/chromoting_instance.h | 86 | ||||
-rw-r--r-- | remoting/client/plugin/chromoting_scriptable_object.cc | 162 | ||||
-rw-r--r-- | remoting/client/plugin/chromoting_scriptable_object.h | 43 | ||||
-rw-r--r-- | remoting/client/plugin/pepper_view.cc | 35 | ||||
-rw-r--r-- | remoting/client/plugin/pepper_xmpp_proxy.cc | 10 | ||||
-rw-r--r-- | remoting/client/plugin/pepper_xmpp_proxy.h | 11 |
7 files changed, 447 insertions, 236 deletions
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index d961e1b..1b0b52b 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc @@ -8,10 +8,14 @@ #include <vector> #include "base/bind.h" +#include "base/callback.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/message_loop.h" #include "base/stringprintf.h" +#include "base/string_split.h" #include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" @@ -35,8 +39,53 @@ #include "remoting/protocol/host_stub.h" #include "remoting/protocol/key_event_tracker.h" +// Windows defines 'PostMessage', so we have to undef it. +#if defined(PostMessage) +#undef PostMessage +#endif + namespace remoting { +namespace { + +const int kPerfStatsIntervalMs = 1000; + +std::string ConnectionStateToString(ChromotingInstance::ConnectionState state) { + switch (state) { + case ChromotingInstance::STATE_CONNECTING: + return "CONNECTING"; + case ChromotingInstance::STATE_INITIALIZING: + return "INITIALIZING"; + case ChromotingInstance::STATE_CONNECTED: + return "CONNECTED"; + case ChromotingInstance::STATE_CLOSED: + return "CLOSED"; + case ChromotingInstance::STATE_FAILED: + return "FAILED"; + } + NOTREACHED(); + return ""; +} + +std::string ConnectionErrorToString(ChromotingInstance::ConnectionError error) { + switch (error) { + case ChromotingInstance::ERROR_NONE: + return "NONE"; + case ChromotingInstance::ERROR_HOST_IS_OFFLINE: + return "HOST_IS_OFFLINE"; + case ChromotingInstance::ERROR_SESSION_REJECTED: + return "SESSION_REJECTED"; + case ChromotingInstance::ERROR_INCOMPATIBLE_PROTOCOL: + return "INCOMPATIBLE_PROTOCOL"; + case ChromotingInstance::ERROR_NETWORK_FAILURE: + return "NETWORK_FAILURE"; + } + NOTREACHED(); + return ""; +} + +} // namespace + // This flag blocks LOGs to the UI if we're already in the middle of logging // to the UI. This prevents a potential infinite loop if we encounter an error // while sending the log message to the UI. @@ -48,19 +97,49 @@ static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; static base::LazyInstance<base::Lock>::Leaky g_logging_lock = LAZY_INSTANCE_INITIALIZER; +bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str, + ClientConfig* config) { + if (auth_methods_str == "v1_token") { + config->use_v1_authenticator = true; + } else { + config->use_v1_authenticator = false; + + std::vector<std::string> auth_methods; + base::SplitString(auth_methods_str, ',', &auth_methods); + for (std::vector<std::string>::iterator it = auth_methods.begin(); + it != auth_methods.end(); ++it) { + protocol::AuthenticationMethod authentication_method = + protocol::AuthenticationMethod::FromString(*it); + if (authentication_method.is_valid()) + config->authentication_methods.push_back(authentication_method); + } + if (config->authentication_methods.empty()) { + LOG(ERROR) << "No valid authentication methods specified."; + return false; + } + } + + return true; +} + ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) : pp::InstancePrivate(pp_instance), initialized_(false), plugin_message_loop_( new PluginMessageLoopProxy(&plugin_thread_delegate_)), context_(plugin_message_loop_), - scale_to_fit_(false), thread_proxy_(new ScopedThreadProxy(plugin_message_loop_)) { RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); // Resister this instance to handle debug log messsages. RegisterLoggingInstance(); + + // Send hello message. + scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); + data->SetInteger("apiVersion", kApiVersion); + data->SetInteger("apiMinVersion", kApiMinMessagingVersion); + PostChromotingMessage("hello", data.Pass()); } ChromotingInstance::~ChromotingInstance() { @@ -129,6 +208,129 @@ bool ChromotingInstance::Init(uint32_t argc, return true; } +void ChromotingInstance::HandleMessage(const pp::Var& message) { + if (!message.is_string()) { + LOG(ERROR) << "Received a message that is not a string."; + return; + } + + scoped_ptr<base::Value> json( + base::JSONReader::Read(message.AsString(), true)); + base::DictionaryValue* message_dict = NULL; + std::string method; + base::DictionaryValue* data = NULL; + if (!json.get() || + !json->GetAsDictionary(&message_dict) || + !message_dict->GetString("method", &method) || + !message_dict->GetDictionary("data", &data)) { + LOG(ERROR) << "Received invalid message:" << message.AsString(); + return; + } + + if (method == "connect") { + ClientConfig config; + std::string auth_methods; + if (!data->GetString("hostJid", &config.host_jid) || + !data->GetString("hostPublicKey", &config.host_public_key) || + !data->GetString("localJid", &config.local_jid) || + !data->GetString("sharedSecret", &config.shared_secret) || + !data->GetString("authenticationMethods", &auth_methods) || + !ParseAuthMethods(auth_methods, &config) || + !data->GetString("authenticationTag", &config.authentication_tag)) { + LOG(ERROR) << "Invalid connect() data."; + return; + } + + Connect(config); + } else if (method == "disconnect") { + Disconnect(); + } else if (method == "incomingIq") { + std::string iq; + if (!data->GetString("iq", &iq)) { + LOG(ERROR) << "Invalid onIq() data."; + return; + } + OnIncomingIq(iq); + } else if (method == "releaseAllKeys") { + ReleaseAllKeys(); + } +} + +void ChromotingInstance::DidChangeView(const pp::Rect& position, + const pp::Rect& clip) { + DCHECK(plugin_message_loop_->BelongsToCurrentThread()); + + SkISize new_size = SkISize::Make(position.width(), position.height()); + if (view_->SetViewSize(new_size)) { + if (mouse_input_filter_.get()) { + mouse_input_filter_->set_input_size(new_size); + } + rectangle_decoder_->SetOutputSize(new_size); + } + + rectangle_decoder_->UpdateClipRect( + SkIRect::MakeXYWH(clip.x(), clip.y(), clip.width(), clip.height())); +} + +bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) { + DCHECK(plugin_message_loop_->BelongsToCurrentThread()); + + if (!input_handler_.get()) + return false; + + // TODO(wez): When we have a good hook into Host dimensions changes, move + // this there. + // If |input_handler_| is valid, then |mouse_input_filter_| must also be + // since they are constructed together as part of the input pipeline + mouse_input_filter_->set_output_size(view_->get_host_size()); + + return input_handler_->HandleInputEvent(event); +} + +pp::Var ChromotingInstance::GetInstanceObject() { + if (instance_object_.is_undefined()) { + ChromotingScriptableObject* object = + new ChromotingScriptableObject(this, plugin_message_loop_); + object->Init(); + + // The pp::Var takes ownership of object here. + instance_object_ = pp::VarPrivate(this, object); + } + + return instance_object_; +} + +void ChromotingInstance::SetDesktopSize(int width, int height) { + scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); + data->SetInteger("width", width); + data->SetInteger("height", height); + PostChromotingMessage("onDesktopSize", data.Pass()); + + GetScriptableObject()->SetDesktopSize(width, height); +} + +void ChromotingInstance::SetConnectionState( + ConnectionState state, + ConnectionError error) { + scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); + data->SetString("state", ConnectionStateToString(state)); + data->SetString("error", ConnectionErrorToString(error)); + PostChromotingMessage("onConnectionStatus", data.Pass()); + + GetScriptableObject()->SetConnectionStatus(state, error); +} + +ChromotingScriptableObject* ChromotingInstance::GetScriptableObject() { + pp::VarPrivate object = GetInstanceObject(); + if (!object.is_undefined()) { + pp::deprecated::ScriptableObject* so = object.AsScriptableObject(); + DCHECK(so != NULL); + return static_cast<ChromotingScriptableObject*>(so); + } + LOG(ERROR) << "Unable to get ScriptableObject for Chromoting plugin."; + return NULL; +} + void ChromotingInstance::Connect(const ClientConfig& config) { DCHECK(plugin_message_loop_->BelongsToCurrentThread()); @@ -151,20 +353,21 @@ void ChromotingInstance::Connect(const ClientConfig& config) { << ". Local jid: " << config.local_jid << "."; // Setup the XMPP Proxy. - ChromotingScriptableObject* scriptable_object = GetScriptableObject(); - scoped_refptr<PepperXmppProxy> xmpp_proxy = - new PepperXmppProxy(scriptable_object->AsWeakPtr(), - plugin_message_loop_, - context_.network_message_loop()); - scriptable_object->AttachXmppProxy(xmpp_proxy); + xmpp_proxy_ = new PepperXmppProxy( + base::Bind(&ChromotingInstance::SendOutgoingIq, AsWeakPtr()), + plugin_message_loop_, + context_.network_message_loop()); // Kick off the connection. - client_->Start(xmpp_proxy); + client_->Start(xmpp_proxy_); + + // Start timer that periodically sends perf stats. + plugin_message_loop_->PostDelayedTask( + FROM_HERE, base::Bind(&ChromotingInstance::SendPerfStats, AsWeakPtr()), + kPerfStatsIntervalMs); VLOG(1) << "Connection status: Initializing"; - GetScriptableObject()->SetConnectionStatus( - ChromotingScriptableObject::STATUS_INITIALIZING, - ChromotingScriptableObject::ERROR_NONE); + SetConnectionState(STATE_INITIALIZING, ERROR_NONE); } void ChromotingInstance::Disconnect() { @@ -185,51 +388,64 @@ void ChromotingInstance::Disconnect() { mouse_input_filter_.reset(); host_connection_.reset(); - GetScriptableObject()->SetConnectionStatus( - ChromotingScriptableObject::STATUS_CLOSED, - ChromotingScriptableObject::ERROR_NONE); + SetConnectionState(STATE_CLOSED, ERROR_NONE); } -void ChromotingInstance::DidChangeView(const pp::Rect& position, - const pp::Rect& clip) { - DCHECK(plugin_message_loop_->BelongsToCurrentThread()); +void ChromotingInstance::OnIncomingIq(const std::string& iq) { + xmpp_proxy_->OnIq(iq); +} - SkISize new_size = SkISize::Make(position.width(), position.height()); - if (view_->SetViewSize(new_size)) { - if (mouse_input_filter_.get()) { - mouse_input_filter_->set_input_size(new_size); - } - rectangle_decoder_->SetOutputSize(new_size); +void ChromotingInstance::ReleaseAllKeys() { + if (key_event_tracker_.get()) { + key_event_tracker_->ReleaseAllKeys(); } +} - rectangle_decoder_->UpdateClipRect( - SkIRect::MakeXYWH(clip.x(), clip.y(), clip.width(), clip.height())); +ChromotingStats* ChromotingInstance::GetStats() { + if (!client_.get()) + return NULL; + return client_->GetStats(); } -bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) { - DCHECK(plugin_message_loop_->BelongsToCurrentThread()); +void ChromotingInstance::PostChromotingMessage( + const std::string& method, + scoped_ptr<base::DictionaryValue> data) { + scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue()); + message->SetString("method", method); + message->Set("data", data.release()); - if (!input_handler_.get()) - return false; + std::string message_json; + base::JSONWriter::Write(message.get(), false, &message_json); + PostMessage(pp::Var(message_json)); +} - // TODO(wez): When we have a good hook into Host dimensions changes, move - // this there. - // If |input_handler_| is valid, then |mouse_input_filter_| must also be - // since they are constructed together as part of the input pipeline - mouse_input_filter_->set_output_size(view_->get_host_size()); +void ChromotingInstance::SendOutgoingIq(const std::string& iq) { + scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); + data->SetString("iq", iq); + PostChromotingMessage("sendOutgoingIq", data.Pass()); - return input_handler_->HandleInputEvent(event); + GetScriptableObject()->SendIq(iq); } -ChromotingScriptableObject* ChromotingInstance::GetScriptableObject() { - pp::VarPrivate object = GetInstanceObject(); - if (!object.is_undefined()) { - pp::deprecated::ScriptableObject* so = object.AsScriptableObject(); - DCHECK(so != NULL); - return static_cast<ChromotingScriptableObject*>(so); +void ChromotingInstance::SendPerfStats() { + if (!client_.get()) { + return; } - LOG(ERROR) << "Unable to get ScriptableObject for Chromoting plugin."; - return NULL; + + plugin_message_loop_->PostDelayedTask( + FROM_HERE, base::Bind(&ChromotingInstance::SendPerfStats, AsWeakPtr()), + kPerfStatsIntervalMs); + + scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); + ChromotingStats* stats = client_->GetStats(); + data->SetDouble("videoBandwidth", stats->video_bandwidth()->Rate()); + data->SetDouble("videoFrameRate", stats->video_frame_rate()->Rate()); + data->SetDouble("captureLatency", stats->video_capture_ms()->Average()); + data->SetDouble("encodeLatency", stats->video_encode_ms()->Average()); + data->SetDouble("decodeLatency", stats->video_decode_ms()->Average()); + data->SetDouble("renderLatency", stats->video_paint_ms()->Average()); + data->SetDouble("roundtripLatency", stats->round_trip_ms()->Average()); + PostChromotingMessage("onPerfStats", data.Pass()); } // static @@ -321,35 +537,15 @@ void ChromotingInstance::ProcessLogToUI(const std::string& message) { // new tasks while we're in the middle of servicing a LOG call. This can // happen if the call to LogDebugInfo tries to LOG anything. g_logging_to_plugin = true; - ChromotingScriptableObject* cso = GetScriptableObject(); - if (cso) - cso->LogDebugInfo(message); - g_logging_to_plugin = false; -} - -pp::Var ChromotingInstance::GetInstanceObject() { - if (instance_object_.is_undefined()) { - ChromotingScriptableObject* object = - new ChromotingScriptableObject(this, plugin_message_loop_); - object->Init(); - - // The pp::Var takes ownership of object here. - instance_object_ = pp::VarPrivate(this, object); - } - - return instance_object_; -} - -ChromotingStats* ChromotingInstance::GetStats() { - if (!client_.get()) - return NULL; - return client_->GetStats(); -} + ChromotingScriptableObject* scriptable_object = GetScriptableObject(); + if (scriptable_object) { + scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); + data->SetString("message", message); + PostChromotingMessage("logDebugMessage", data.Pass()); -void ChromotingInstance::ReleaseAllKeys() { - if (key_event_tracker_.get()) { - key_event_tracker_->ReleaseAllKeys(); + scriptable_object->LogDebugInfo(message); } + g_logging_to_plugin = false; } } // namespace remoting diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h index 5c72bf1..734c574 100644 --- a/remoting/client/plugin/chromoting_instance.h +++ b/remoting/client/plugin/chromoting_instance.h @@ -12,17 +12,28 @@ #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_rect.h" #include "ppapi/c/pp_resource.h" #include "ppapi/cpp/var.h" + +// Windows defines 'PostMessage', so we have to undef it before we +// include instance_private.h +#if defined(PostMessage) +#undef PostMessage +#endif + #include "ppapi/cpp/private/instance_private.h" #include "remoting/base/scoped_thread_proxy.h" #include "remoting/client/client_context.h" -#include "remoting/client/plugin/chromoting_scriptable_object.h" #include "remoting/client/plugin/pepper_plugin_thread_delegate.h" #include "remoting/protocol/connection_to_host.h" +namespace base { +class DictionaryBase; +} // namespace base + namespace pp { class InputEvent; class Module; @@ -36,18 +47,60 @@ class KeyEventTracker; } // namespace protocol class ChromotingClient; +class ChromotingScriptableObject; class ChromotingStats; class ClientContext; class FrameConsumerProxy; class MouseInputFilter; class PepperInputHandler; class PepperView; +class PepperXmppProxy; class RectangleUpdateDecoder; struct ClientConfig; -class ChromotingInstance : public pp::InstancePrivate { +class ChromotingInstance : + public pp::InstancePrivate, + public base::SupportsWeakPtr<ChromotingInstance> { public: + // These state values are duplicated in the JS code. Remember to + // update both copies when making changes. + enum ConnectionState { + STATE_CONNECTING = 1, + STATE_INITIALIZING, + STATE_CONNECTED, + STATE_CLOSED, + STATE_FAILED, + }; + + // These values are duplicated in the JS code. Remember to update + // both copies when making changes. + enum ConnectionError { + ERROR_NONE = 0, + ERROR_HOST_IS_OFFLINE, + ERROR_SESSION_REJECTED, + ERROR_INCOMPATIBLE_PROTOCOL, + ERROR_NETWORK_FAILURE, + }; + + // Plugin API version. This should be incremented whenever the API + // interface changes. + static const int kApiVersion = 5; + + // Backward-compatibility version used by for the messaging + // interface. Should be updated whenever we remove support for + // an older version of the API. + static const int kApiMinMessagingVersion = 5; + + // Backward-compatibility version used by for the ScriptableObject + // interface. Should be updated whenever we remove support for + // an older version of the API. + static const int kApiMinScriptableVersion = 2; + + // Helper method to parse authentication_methods parameter. + static bool ParseAuthMethods(const std::string& auth_methods, + ClientConfig* config); + explicit ChromotingInstance(PP_Instance instance); virtual ~ChromotingInstance(); @@ -56,29 +109,30 @@ class ChromotingInstance : public pp::InstancePrivate { const pp::Rect& clip) OVERRIDE; virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) OVERRIDE; + virtual void HandleMessage(const pp::Var& message) OVERRIDE; virtual bool HandleInputEvent(const pp::InputEvent& event) OVERRIDE; // pp::InstancePrivate interface. virtual pp::Var GetInstanceObject() OVERRIDE; + // Called by PepperView. + void SetDesktopSize(int width, int height); + void SetConnectionState(ConnectionState state, ConnectionError error); + // Convenience wrapper to get the ChromotingScriptableObject. ChromotingScriptableObject* GetScriptableObject(); - // Initiates and cancels connections. + // Message handlers for messages that come from JavaScript. Called + // from HandleMessage() and ChromotingScriptableObject. void Connect(const ClientConfig& config); void Disconnect(); - - // Called by ChromotingScriptableObject to set scale-to-fit. - void SetScaleToFit(bool scale_to_fit); + void OnIncomingIq(const std::string& iq); + void ReleaseAllKeys(); // Return statistics record by ChromotingClient. // If no connection is currently active then NULL will be returned. ChromotingStats* GetStats(); - void ReleaseAllKeys(); - - bool DoScaling() const { return scale_to_fit_; } - // Registers a global log message handler that redirects the log output to // our plugin instance. // This is called by the plugin's PPP_InitializeModule. @@ -104,6 +158,15 @@ class ChromotingInstance : public pp::InstancePrivate { private: FRIEND_TEST_ALL_PREFIXES(ChromotingInstanceTest, TestCaseSetup); + // Helper method to post messages to the webapp. + void PostChromotingMessage(const std::string& method, + scoped_ptr<base::DictionaryValue> data); + + // Callback for PepperXmppProxy. + void SendOutgoingIq(const std::string& iq); + + void SendPerfStats(); + void ProcessLogToUI(const std::string& message); bool initialized_; @@ -114,9 +177,6 @@ class ChromotingInstance : public pp::InstancePrivate { scoped_ptr<protocol::ConnectionToHost> host_connection_; scoped_ptr<PepperView> view_; - // True if scale to fit is enabled. - bool scale_to_fit_; - scoped_refptr<FrameConsumerProxy> consumer_proxy_; scoped_refptr<RectangleUpdateDecoder> rectangle_decoder_; scoped_ptr<MouseInputFilter> mouse_input_filter_; diff --git a/remoting/client/plugin/chromoting_scriptable_object.cc b/remoting/client/plugin/chromoting_scriptable_object.cc index 9028bf7..a6dbf0e 100644 --- a/remoting/client/plugin/chromoting_scriptable_object.cc +++ b/remoting/client/plugin/chromoting_scriptable_object.cc @@ -5,10 +5,10 @@ #include "remoting/client/plugin/chromoting_scriptable_object.h" #include "base/bind.h" +#include "base/callback.h" #include "base/logging.h" #include "base/message_loop_proxy.h" #include "base/string_split.h" -// TODO(wez): Remove this when crbug.com/86353 is complete. #include "ppapi/cpp/private/var_private.h" #include "remoting/base/auth_token_util.h" #include "remoting/client/client_config.h" @@ -56,34 +56,38 @@ void ChromotingScriptableObject::Init() { // Property addition order should match the interface description at the // top of chromoting_scriptable_object.h. - // Plugin API version. - // This should be incremented whenever the API interface changes. - AddAttribute(kApiVersionAttribute, Var(4)); + AddAttribute(kApiVersionAttribute, Var(ChromotingInstance::kApiVersion)); - // This should be updated whenever we remove support for an older version - // of the API. - AddAttribute(kApiMinVersionAttribute, Var(2)); + AddAttribute(kApiMinVersionAttribute, + Var(ChromotingInstance::kApiMinScriptableVersion)); // Connection status. - AddAttribute(kStatusAttribute, Var(STATUS_UNKNOWN)); + AddAttribute(kStatusAttribute, Var(0)); // STATUS_UNKNOWN // Connection status values. - AddAttribute("STATUS_UNKNOWN", Var(STATUS_UNKNOWN)); - AddAttribute("STATUS_CONNECTING", Var(STATUS_CONNECTING)); - AddAttribute("STATUS_INITIALIZING", Var(STATUS_INITIALIZING)); - AddAttribute("STATUS_CONNECTED", Var(STATUS_CONNECTED)); - AddAttribute("STATUS_CLOSED", Var(STATUS_CLOSED)); - AddAttribute("STATUS_FAILED", Var(STATUS_FAILED)); + // TODO(jamiewalch): Remove STATUS_UNKNOWN once all web-apps that might try + // to access it have been upgraded. + AddAttribute("STATUS_UNKNOWN", Var(0)); + AddAttribute("STATUS_CONNECTING", Var(ChromotingInstance::STATE_CONNECTING)); + AddAttribute("STATUS_INITIALIZING", + Var(ChromotingInstance::STATE_INITIALIZING)); + AddAttribute("STATUS_CONNECTED", Var(ChromotingInstance::STATE_CONNECTED)); + AddAttribute("STATUS_CLOSED", Var(ChromotingInstance::STATE_CLOSED)); + AddAttribute("STATUS_FAILED", Var(ChromotingInstance::STATE_FAILED)); // Connection error. - AddAttribute(kErrorAttribute, Var(ERROR_NONE)); - - // Connection status values. - AddAttribute("ERROR_NONE", Var(ERROR_NONE)); - AddAttribute("ERROR_HOST_IS_OFFLINE", Var(ERROR_HOST_IS_OFFLINE)); - AddAttribute("ERROR_SESSION_REJECTED", Var(ERROR_SESSION_REJECTED)); - AddAttribute("ERROR_INCOMPATIBLE_PROTOCOL", Var(ERROR_INCOMPATIBLE_PROTOCOL)); - AddAttribute("ERROR_FAILURE_NONE", Var(ERROR_NETWORK_FAILURE)); + AddAttribute(kErrorAttribute, Var(ChromotingInstance::ERROR_NONE)); + + // Connection error values. + AddAttribute("ERROR_NONE", Var(ChromotingInstance::ERROR_NONE)); + AddAttribute("ERROR_HOST_IS_OFFLINE", + Var(ChromotingInstance::ERROR_HOST_IS_OFFLINE)); + AddAttribute("ERROR_SESSION_REJECTED", + Var(ChromotingInstance::ERROR_SESSION_REJECTED)); + AddAttribute("ERROR_INCOMPATIBLE_PROTOCOL", + Var(ChromotingInstance::ERROR_INCOMPATIBLE_PROTOCOL)); + AddAttribute("ERROR_FAILURE_NONE", + Var(ChromotingInstance::ERROR_NETWORK_FAILURE)); // Debug info to display. AddAttribute(kConnectionInfoUpdate, Var()); @@ -231,14 +235,15 @@ Var ChromotingScriptableObject::Call(const Var& method_name, } void ChromotingScriptableObject::SetConnectionStatus( - ConnectionStatus status, ConnectionError error) { - VLOG(1) << "Connection status is updated: " << status; + ChromotingInstance::ConnectionState state, + ChromotingInstance::ConnectionError error) { + VLOG(1) << "Connection status is updated: " << state; bool signal = false; int status_index = property_names_[kStatusAttribute]; - if (properties_[status_index].attribute.AsInt() != status) { - properties_[status_index].attribute = Var(status); + if (properties_[status_index].attribute.AsInt() != state) { + properties_[status_index].attribute = Var(state); signal = true; } @@ -248,21 +253,27 @@ void ChromotingScriptableObject::SetConnectionStatus( signal = true; } - if (signal) - SignalConnectionInfoChange(status, error); + if (signal) { + plugin_message_loop_->PostTask( + FROM_HERE, base::Bind( + &ChromotingScriptableObject::DoSignalConnectionInfoChange, + AsWeakPtr(), state, error)); + } } void ChromotingScriptableObject::LogDebugInfo(const std::string& info) { Var exception; VarPrivate cb = GetProperty(Var(kDebugInfo), &exception); - // Var() means call the object directly as a function rather than calling - // a method in the object. - cb.Call(Var(), Var(info), &exception); + if (!cb.is_undefined()) { + // Var() means call the object directly as a function rather than calling + // a method in the object. + cb.Call(Var(), Var(info), &exception); - if (!exception.is_undefined()) { - LOG(WARNING) << "Exception when invoking debugInfo JS callback: " - << exception.DebugString(); + if (!exception.is_undefined()) { + LOG(WARNING) << "Exception when invoking debugInfo JS callback: " + << exception.DebugString(); + } } } @@ -274,16 +285,15 @@ void ChromotingScriptableObject::SetDesktopSize(int width, int height) { properties_[height_index].attribute.AsInt() != height) { properties_[width_index].attribute = Var(width); properties_[height_index].attribute = Var(height); - SignalDesktopSizeChange(); + plugin_message_loop_->PostTask( + FROM_HERE, base::Bind( + &ChromotingScriptableObject::DoSignalDesktopSizeChange, + AsWeakPtr())); } VLOG(1) << "Update desktop size to: " << width << " x " << height; } -void ChromotingScriptableObject::AttachXmppProxy(PepperXmppProxy* xmpp_proxy) { - xmpp_proxy_ = xmpp_proxy; -} - void ChromotingScriptableObject::SendIq(const std::string& message_xml) { plugin_message_loop_->PostTask( FROM_HERE, base::Bind( @@ -302,43 +312,32 @@ void ChromotingScriptableObject::AddMethod(const std::string& name, properties_.push_back(PropertyDescriptor(name, handler)); } -void ChromotingScriptableObject::SignalConnectionInfoChange(int status, - int error) { - plugin_message_loop_->PostTask( - FROM_HERE, base::Bind( - &ChromotingScriptableObject::DoSignalConnectionInfoChange, - AsWeakPtr(), status, error)); -} - -void ChromotingScriptableObject::SignalDesktopSizeChange() { - plugin_message_loop_->PostTask( - FROM_HERE, base::Bind( - &ChromotingScriptableObject::DoSignalDesktopSizeChange, - AsWeakPtr())); -} - -void ChromotingScriptableObject::DoSignalConnectionInfoChange(int status, +void ChromotingScriptableObject::DoSignalConnectionInfoChange(int state, int error) { Var exception; VarPrivate cb = GetProperty(Var(kConnectionInfoUpdate), &exception); - // |this| must not be touched after Call() returns. - cb.Call(Var(), Var(status), Var(error), &exception); + if (!cb.is_undefined()) { + // |this| must not be touched after Call() returns. + cb.Call(Var(), Var(state), Var(error), &exception); - if (!exception.is_undefined()) - LOG(ERROR) << "Exception when invoking connectionInfoUpdate JS callback."; + if (!exception.is_undefined()) + LOG(ERROR) << "Exception when invoking connectionInfoUpdate JS callback."; + } } void ChromotingScriptableObject::DoSignalDesktopSizeChange() { Var exception; VarPrivate cb = GetProperty(Var(kDesktopSizeUpdate), &exception); - // |this| must not be touched after Call() returns. - cb.Call(Var(), &exception); + if (!cb.is_undefined()) { + // |this| must not be touched after Call() returns. + cb.Call(Var(), &exception); - if (!exception.is_undefined()) { - LOG(ERROR) << "Exception when invoking JS callback" - << exception.DebugString(); + if (!exception.is_undefined()) { + LOG(ERROR) << "Exception when invoking JS callback" + << exception.DebugString(); + } } } @@ -346,11 +345,13 @@ void ChromotingScriptableObject::DoSendIq(const std::string& message_xml) { Var exception; VarPrivate cb = GetProperty(Var(kSendIq), &exception); - // |this| must not be touched after Call() returns. - cb.Call(Var(), Var(message_xml), &exception); + if (!cb.is_undefined()) { + // |this| must not be touched after Call() returns. + cb.Call(Var(), Var(message_xml), &exception); - if (!exception.is_undefined()) - LOG(ERROR) << "Exception when invoking sendiq JS callback."; + if (!exception.is_undefined()) + LOG(ERROR) << "Exception when invoking sendiq JS callback."; + } } Var ChromotingScriptableObject::DoConnect(const std::vector<Var>& args, @@ -400,25 +401,10 @@ Var ChromotingScriptableObject::DoConnect(const std::vector<Var>& args, return Var(); } - std::string as_string = args[arg++].AsString(); - if (as_string == "v1_token") { - config.use_v1_authenticator = true; - } else { - config.use_v1_authenticator = false; - - std::vector<std::string> auth_methods; - base::SplitString(as_string, ',', &auth_methods); - for (std::vector<std::string>::iterator it = auth_methods.begin(); - it != auth_methods.end(); ++it) { - protocol::AuthenticationMethod authentication_method = - protocol::AuthenticationMethod::FromString(*it); - if (authentication_method.is_valid()) - config.authentication_methods.push_back(authentication_method); - } - if (config.authentication_methods.empty()) { - *exception = Var("No valid authentication methods specified."); - return Var(); - } + if (!ChromotingInstance::ParseAuthMethods( + args[arg++].AsString(), &config)) { + *exception = Var("No valid authentication methods specified."); + return Var(); } } @@ -467,7 +453,7 @@ Var ChromotingScriptableObject::DoOnIq(const std::vector<Var>& args, return Var(); } - xmpp_proxy_->OnIq(args[0].AsString()); + instance_->OnIncomingIq(args[0].AsString()); return Var(); } diff --git a/remoting/client/plugin/chromoting_scriptable_object.h b/remoting/client/plugin/chromoting_scriptable_object.h index 8e50797..f040ee5 100644 --- a/remoting/client/plugin/chromoting_scriptable_object.h +++ b/remoting/client/plugin/chromoting_scriptable_object.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -105,6 +105,7 @@ #include "base/memory/weak_ptr.h" #include "ppapi/cpp/dev/scriptable_object_deprecated.h" #include "ppapi/cpp/var.h" +#include "remoting/client/plugin/chromoting_instance.h" namespace base { class MessageLoopProxy; @@ -112,36 +113,12 @@ class MessageLoopProxy; namespace remoting { -class ChromotingInstance; -class PepperXmppProxy; - +// TODO(sergeyu): Remove this class when migration to messaging +// interface is finished (crbug.com/86353). class ChromotingScriptableObject : public pp::deprecated::ScriptableObject, public base::SupportsWeakPtr<ChromotingScriptableObject> { public: - // These state values are duplicated in the JS code. Remember to update both - // copies when making changes. - enum ConnectionStatus { - // TODO(jamiewalch): Remove STATUS_UNKNOWN once all web-apps that might try - // to access it have been upgraded. - STATUS_UNKNOWN = 0, - STATUS_CONNECTING, - STATUS_INITIALIZING, - STATUS_CONNECTED, - STATUS_CLOSED, - STATUS_FAILED, - }; - - // These state values are duplicated in the JS code. Remember to update both - // copies when making changes. - enum ConnectionError { - ERROR_NONE = 0, - ERROR_HOST_IS_OFFLINE, - ERROR_SESSION_REJECTED, - ERROR_INCOMPATIBLE_PROTOCOL, - ERROR_NETWORK_FAILURE, - }; - ChromotingScriptableObject( ChromotingInstance* instance, base::MessageLoopProxy* plugin_message_loop); @@ -162,14 +139,11 @@ class ChromotingScriptableObject const std::vector<pp::Var>& args, pp::Var* exception) OVERRIDE; - void SetConnectionStatus(ConnectionStatus status, ConnectionError error); + void SetConnectionStatus(ChromotingInstance::ConnectionState state, + ChromotingInstance::ConnectionError error); void LogDebugInfo(const std::string& info); void SetDesktopSize(int width, int height); - // Attaches the XmppProxy used for issuing and receivng IQ stanzas for - // initializing a jingle connection from within the sandbox. - void AttachXmppProxy(PepperXmppProxy* xmpp_proxy); - // Sends an IQ stanza, serialized as an xml string, into Javascript for // handling. void SendIq(const std::string& request_xml); @@ -202,13 +176,13 @@ class ChromotingScriptableObject void AddAttribute(const std::string& name, pp::Var attribute); void AddMethod(const std::string& name, MethodHandler handler); - void SignalConnectionInfoChange(int status, int error); + void SignalConnectionInfoChange(int state, int error); void SignalDesktopSizeChange(); // Calls to these methods are posted to the plugin thread so that we // call JavaScript with clean stack. This is necessary because // JavaScript event handlers may destroy the plugin. - void DoSignalConnectionInfoChange(int status, int error); + void DoSignalConnectionInfoChange(int state, int error); void DoSignalDesktopSizeChange(); void DoSendIq(const std::string& message_xml); @@ -229,7 +203,6 @@ class ChromotingScriptableObject PropertyNameMap property_names_; std::vector<PropertyDescriptor> properties_; - scoped_refptr<PepperXmppProxy> xmpp_proxy_; ChromotingInstance* instance_; diff --git a/remoting/client/plugin/pepper_view.cc b/remoting/client/plugin/pepper_view.cc index fe404c2..b466fa6 100644 --- a/remoting/client/plugin/pepper_view.cc +++ b/remoting/client/plugin/pepper_view.cc @@ -22,22 +22,22 @@ namespace remoting { namespace { -ChromotingScriptableObject::ConnectionError ConvertConnectionError( +ChromotingInstance::ConnectionError ConvertConnectionError( protocol::ConnectionToHost::Error error) { switch (error) { case protocol::ConnectionToHost::OK: - return ChromotingScriptableObject::ERROR_NONE; + return ChromotingInstance::ERROR_NONE; case protocol::ConnectionToHost::HOST_IS_OFFLINE: - return ChromotingScriptableObject::ERROR_HOST_IS_OFFLINE; + return ChromotingInstance::ERROR_HOST_IS_OFFLINE; case protocol::ConnectionToHost::SESSION_REJECTED: - return ChromotingScriptableObject::ERROR_SESSION_REJECTED; + return ChromotingInstance::ERROR_SESSION_REJECTED; case protocol::ConnectionToHost::INCOMPATIBLE_PROTOCOL: - return ChromotingScriptableObject::ERROR_INCOMPATIBLE_PROTOCOL; + return ChromotingInstance::ERROR_INCOMPATIBLE_PROTOCOL; case protocol::ConnectionToHost::NETWORK_FAILURE: - return ChromotingScriptableObject::ERROR_NETWORK_FAILURE; + return ChromotingInstance::ERROR_NETWORK_FAILURE; } DLOG(FATAL) << "Unknown error code" << error; - return ChromotingScriptableObject::ERROR_NONE; + return ChromotingInstance::ERROR_NONE; } } // namespace @@ -106,8 +106,7 @@ void PepperView::SetHostSize(const SkISize& host_size) { host_size_ = host_size; // Submit an update of desktop size to Javascript. - instance_->GetScriptableObject()->SetDesktopSize( - host_size.width(), host_size.height()); + instance_->SetDesktopSize(host_size.width(), host_size.height()); } void PepperView::PaintFrame(media::VideoFrame* frame, const SkRegion& region) { @@ -229,34 +228,32 @@ void PepperView::SetConnectionState(protocol::ConnectionToHost::State state, protocol::ConnectionToHost::Error error) { DCHECK(context_->main_message_loop()->BelongsToCurrentThread()); - // TODO(hclam): Re-consider the way we communicate with Javascript. - ChromotingScriptableObject* scriptable_obj = instance_->GetScriptableObject(); switch (state) { case protocol::ConnectionToHost::CONNECTING: SetSolidFill(kCreatedColor); - scriptable_obj->SetConnectionStatus( - ChromotingScriptableObject::STATUS_CONNECTING, + instance_->SetConnectionState( + ChromotingInstance::STATE_CONNECTING, ConvertConnectionError(error)); break; case protocol::ConnectionToHost::CONNECTED: UnsetSolidFill(); - scriptable_obj->SetConnectionStatus( - ChromotingScriptableObject::STATUS_CONNECTED, + instance_->SetConnectionState( + ChromotingInstance::STATE_CONNECTED, ConvertConnectionError(error)); break; case protocol::ConnectionToHost::CLOSED: SetSolidFill(kDisconnectedColor); - scriptable_obj->SetConnectionStatus( - ChromotingScriptableObject::STATUS_CLOSED, + instance_->SetConnectionState( + ChromotingInstance::STATE_CLOSED, ConvertConnectionError(error)); break; case protocol::ConnectionToHost::FAILED: SetSolidFill(kFailedColor); - scriptable_obj->SetConnectionStatus( - ChromotingScriptableObject::STATUS_FAILED, + instance_->SetConnectionState( + ChromotingInstance::STATE_FAILED, ConvertConnectionError(error)); break; } diff --git a/remoting/client/plugin/pepper_xmpp_proxy.cc b/remoting/client/plugin/pepper_xmpp_proxy.cc index f167e6e..5ab0689 100644 --- a/remoting/client/plugin/pepper_xmpp_proxy.cc +++ b/remoting/client/plugin/pepper_xmpp_proxy.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,15 +7,14 @@ #include "base/bind.h" #include "base/location.h" #include "base/message_loop_proxy.h" -#include "remoting/client/plugin/chromoting_scriptable_object.h" namespace remoting { PepperXmppProxy::PepperXmppProxy( - base::WeakPtr<ChromotingScriptableObject> scriptable_object, + const SendIqCallback& send_iq_callback, base::MessageLoopProxy* plugin_message_loop, base::MessageLoopProxy* callback_message_loop) - : scriptable_object_(scriptable_object), + : send_iq_callback_(send_iq_callback), plugin_message_loop_(plugin_message_loop), callback_message_loop_(callback_message_loop) { DCHECK(plugin_message_loop_->BelongsToCurrentThread()); @@ -40,8 +39,7 @@ void PepperXmppProxy::SendIq(const std::string& request_xml) { return; } - if (scriptable_object_) - scriptable_object_->SendIq(request_xml); + send_iq_callback_.Run(request_xml); } void PepperXmppProxy::OnIq(const std::string& response_xml) { diff --git a/remoting/client/plugin/pepper_xmpp_proxy.h b/remoting/client/plugin/pepper_xmpp_proxy.h index cc3e690..40ba4ba 100644 --- a/remoting/client/plugin/pepper_xmpp_proxy.h +++ b/remoting/client/plugin/pepper_xmpp_proxy.h @@ -1,10 +1,11 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef REMOTING_CLIENT_PLUGIN_PEPPER_XMPP_PROXY_H_ #define REMOTING_CLIENT_PLUGIN_PEPPER_XMPP_PROXY_H_ +#include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "remoting/jingle_glue/xmpp_proxy.h" @@ -15,12 +16,12 @@ class MessageLoopProxy; namespace remoting { -class ChromotingScriptableObject; - class PepperXmppProxy : public XmppProxy { public: + typedef base::Callback<void(const std::string&)> SendIqCallback; + PepperXmppProxy( - base::WeakPtr<ChromotingScriptableObject> scriptable_object, + const SendIqCallback& send_iq_callback, base::MessageLoopProxy* plugin_message_loop, base::MessageLoopProxy* callback_message_loop); @@ -43,7 +44,7 @@ class PepperXmppProxy : public XmppProxy { private: virtual ~PepperXmppProxy(); - base::WeakPtr<ChromotingScriptableObject> scriptable_object_; + SendIqCallback send_iq_callback_; scoped_refptr<base::MessageLoopProxy> plugin_message_loop_; scoped_refptr<base::MessageLoopProxy> callback_message_loop_; |