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 |