| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 #ifndef CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_ | |
| 6 #define CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_ | |
| 7 | |
| 8 #include <deque> | |
| 9 | |
| 10 #include "base/synchronization/lock.h" | |
| 11 #include "ipc/ipc_channel_proxy.h" | |
| 12 | |
| 13 // Base class used to allow synchronous IPC messages to be sent and | |
| 14 // received in an asynchronous manner. To use this class add it as a filter to | |
| 15 // your IPC channel using ChannelProxy::AddFilter(). From then on, before | |
| 16 // sending a synchronous message, call SyncMessageReplyDispatcher::Push() with | |
| 17 // a callback and a key. This class will then handle the message response and | |
| 18 // will call the callback when it is received. | |
| 19 // | |
| 20 // This class is intended to be extended by classes implementing | |
| 21 // HandleMessageType with delegation for the messages they expect to receive in | |
| 22 // cases where you care about the return values of synchronous messages. | |
| 23 // | |
| 24 // Sample usage pattern: | |
| 25 // Define a class which inherits from SyncMessageCallContext which specifies | |
| 26 // the output_type tuple and has a Completed member function. | |
| 27 // class SampleContext | |
| 28 // : public SyncMessageReplyDispatcher::SyncMessageCallContext { | |
| 29 // public: | |
| 30 // typedef Tuple1<int> output_type; | |
| 31 // void Completed(int arg) {} | |
| 32 // }; | |
| 33 // | |
| 34 // // Add handling for desired message types. | |
| 35 // class SyncMessageReplyDispatcherImpl : public SyncMessageReplyDispatcher { | |
| 36 // virtual bool HandleMessageType(const IPC::Message& msg, | |
| 37 // SyncMessageReplyDispatcher* context) { | |
| 38 // switch (context->message_type()) { | |
| 39 // case AutomationMsg_CreateExternalTab::ID: | |
| 40 // InvokeCallback<CreateExternalTabContext>(msg, context); | |
| 41 // break; | |
| 42 // [HANDLING FOR OTHER EXPECTED MESSAGE TYPES] | |
| 43 // } | |
| 44 // } | |
| 45 // | |
| 46 // // Add the filter | |
| 47 // IPC::SyncChannel channel_; | |
| 48 // channel_.AddFilter(new SyncMessageReplyDispatcherImpl()); | |
| 49 // | |
| 50 // sync_->Push(msg, new SampleContext, this); | |
| 51 // channel_->ChannelProxy::Send(msg); | |
| 52 // | |
| 53 class SyncMessageReplyDispatcher : public IPC::ChannelProxy::MessageFilter { | |
| 54 public: | |
| 55 class SyncMessageCallContext { | |
| 56 public: | |
| 57 SyncMessageCallContext() | |
| 58 : id_(0), | |
| 59 message_type_(0), | |
| 60 key_(NULL) {} | |
| 61 | |
| 62 virtual ~SyncMessageCallContext() {} | |
| 63 | |
| 64 uint32 message_type() const { | |
| 65 return message_type_; | |
| 66 } | |
| 67 | |
| 68 private: | |
| 69 int id_; | |
| 70 uint32 message_type_; | |
| 71 void* key_; | |
| 72 | |
| 73 friend class SyncMessageReplyDispatcher; | |
| 74 }; | |
| 75 | |
| 76 SyncMessageReplyDispatcher() {} | |
| 77 void Push(IPC::SyncMessage* msg, SyncMessageCallContext* context, | |
| 78 void* key); | |
| 79 void Cancel(void* key); | |
| 80 | |
| 81 protected: | |
| 82 typedef std::deque<SyncMessageCallContext*> PendingSyncMessageQueue; | |
| 83 | |
| 84 SyncMessageCallContext* GetContext(const IPC::Message& msg); | |
| 85 | |
| 86 virtual bool OnMessageReceived(const IPC::Message& msg); | |
| 87 | |
| 88 // Child classes must implement a handler for the message types they are | |
| 89 // interested in handling responses for. If you don't care about the replies | |
| 90 // to any of the sync messages you are handling, then you don't have to | |
| 91 // implement this. | |
| 92 virtual bool HandleMessageType(const IPC::Message& msg, | |
| 93 SyncMessageCallContext* context); | |
| 94 | |
| 95 template <typename T> | |
| 96 void InvokeCallback(const IPC::Message& msg, | |
| 97 SyncMessageCallContext* call_context) { | |
| 98 if (!call_context || !call_context->key_) { | |
| 99 NOTREACHED() << "Invalid context parameter"; | |
| 100 return; | |
| 101 } | |
| 102 | |
| 103 T* context = static_cast<T*>(call_context); | |
| 104 T::output_type tmp; // Acts as "initializer" for output parameters. | |
| 105 IPC::ParamDeserializer<T::output_type> deserializer(tmp); | |
| 106 if (deserializer.MessageReplyDeserializer::SerializeOutputParameters(msg)) { | |
| 107 DispatchToMethod(context, &T::Completed, deserializer.out_); | |
| 108 delete context; | |
| 109 } else { | |
| 110 // TODO(stoyan): How to handle errors? | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 PendingSyncMessageQueue message_queue_; | |
| 115 base::Lock message_queue_lock_; | |
| 116 }; | |
| 117 | |
| 118 #endif // CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_ | |
| OLD | NEW |