- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / examples / api / websocket / websocket.cc
1 // Copyright (c) 2012 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 <stdio.h>
6 #include <sstream>
7
8 #include "ppapi/cpp/completion_callback.h"
9 #include "ppapi/cpp/instance.h"
10 #include "ppapi/cpp/module.h"
11 #include "ppapi/cpp/var.h"
12 #include "ppapi/cpp/var_array_buffer.h"
13 #include "ppapi/cpp/websocket.h"
14
15 class WebSocketInstance : public pp::Instance {
16  public:
17   explicit WebSocketInstance(PP_Instance instance)
18       : pp::Instance(instance), websocket_(NULL) {}
19   virtual ~WebSocketInstance() {}
20   virtual void HandleMessage(const pp::Var& var_message);
21
22  private:
23   bool IsConnected();
24
25   void Open(const std::string& url);
26   void Close();
27   void SendAsBinary(const std::string& message);
28   void SendAsText(const std::string& message);
29   void Receive();
30
31   void OnConnectCompletion(int32_t result);
32   void OnCloseCompletion(int32_t result);
33   void OnReceiveCompletion(int32_t result);
34
35   static void OnConnectCompletionCallback(void* user_data, int32_t result);
36   static void OnCloseCompletionCallback(void* user_data, int32_t result);
37   static void OnReceiveCompletionCallback(void* user_data, int32_t result);
38
39   pp::WebSocket* websocket_;
40   pp::Var receive_var_;
41 };
42
43 #define MAX_TO_CONVERT 8
44 #define BYTES_PER_CHAR 4
45 #define TAIL_AND_NUL_SIZE 4
46
47 static std::string ArrayToString(pp::VarArrayBuffer& array) {
48   char tmp[MAX_TO_CONVERT * BYTES_PER_CHAR + TAIL_AND_NUL_SIZE];
49   uint32_t offs = 0;
50   uint8_t* data = static_cast<uint8_t*>(array.Map());
51
52   for (offs = 0; offs < array.ByteLength() && offs < MAX_TO_CONVERT; offs++)
53     sprintf(&tmp[offs * BYTES_PER_CHAR], "%02Xh ", data[offs]);
54
55   sprintf(&tmp[offs * BYTES_PER_CHAR], "...");
56   array.Unmap();
57   return std::string(tmp);
58 }
59
60 void WebSocketInstance::HandleMessage(const pp::Var& var_message) {
61   if (!var_message.is_string())
62     return;
63   std::string message = var_message.AsString();
64   // This message must contain a command character followed by ';' and
65   // arguments like "X;arguments".
66   if (message.length() < 2 || message[1] != ';')
67     return;
68   switch (message[0]) {
69     case 'o':
70       // The command 'o' requests to open the specified URL.
71       // URL is passed as an argument like "o;URL".
72       Open(message.substr(2));
73       break;
74     case 'c':
75       // The command 'c' requests to close without any argument like "c;"
76       Close();
77       break;
78     case 'b':
79       // The command 'b' requests to send a message as a binary frame. The
80       // message is passed as an argument like "b;message".
81       SendAsBinary(message.substr(2));
82       break;
83     case 't':
84       // The command 't' requests to send a message as a text frame. The message
85       // is passed as an argument like "t;message".
86       SendAsText(message.substr(2));
87       break;
88   }
89 }
90
91 bool WebSocketInstance::IsConnected() {
92   if (!websocket_)
93     return false;
94   if (websocket_->GetReadyState() != PP_WEBSOCKETREADYSTATE_OPEN)
95     return false;
96   return true;
97 }
98
99 void WebSocketInstance::Open(const std::string& url) {
100   pp::CompletionCallback callback(OnConnectCompletionCallback, this);
101   websocket_ = new pp::WebSocket(this);
102   if (!websocket_)
103     return;
104   websocket_->Connect(pp::Var(url), NULL, 0, callback);
105   PostMessage(pp::Var("connecting..."));
106 }
107
108 void WebSocketInstance::Close() {
109   if (!IsConnected())
110     return;
111   pp::CompletionCallback callback(OnCloseCompletionCallback, this);
112   websocket_->Close(
113       PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var("bye"), callback);
114 }
115
116 void WebSocketInstance::SendAsBinary(const std::string& message) {
117   if (!IsConnected())
118     return;
119   uint32_t size = message.size();
120   pp::VarArrayBuffer array_buffer(size);
121   char* data = static_cast<char*>(array_buffer.Map());
122   for (uint32_t i = 0; i < size; ++i)
123     data[i] = message[i];
124   array_buffer.Unmap();
125   websocket_->SendMessage(array_buffer);
126   std::string message_text = ArrayToString(array_buffer);
127   PostMessage(pp::Var("send (binary): " + message_text));
128 }
129
130 void WebSocketInstance::SendAsText(const std::string& message) {
131   if (!IsConnected())
132     return;
133   websocket_->SendMessage(pp::Var(message));
134   PostMessage(pp::Var("send (text): " + message));
135 }
136
137 void WebSocketInstance::Receive() {
138   pp::CompletionCallback callback(OnReceiveCompletionCallback, this);
139   // |receive_var_| must be valid until |callback| is invoked.
140   // Just use a member variable.
141   websocket_->ReceiveMessage(&receive_var_, callback);
142 }
143
144 void WebSocketInstance::OnConnectCompletion(int32_t result) {
145   if (result != PP_OK) {
146     PostMessage(pp::Var("connection failed"));
147     return;
148   }
149   PostMessage(pp::Var("connected"));
150   Receive();
151 }
152
153 void WebSocketInstance::OnCloseCompletion(int32_t result) {
154   PostMessage(pp::Var(PP_OK == result ? "closed" : "abnormally closed"));
155 }
156
157 void WebSocketInstance::OnReceiveCompletion(int32_t result) {
158   if (result == PP_OK) {
159     if (receive_var_.is_array_buffer()) {
160       pp::VarArrayBuffer array_buffer(receive_var_);
161       std::string message_text = ArrayToString(array_buffer);
162       PostMessage("receive (binary): " + message_text);
163     }
164     else {
165       PostMessage("receive (text): " + receive_var_.AsString());
166     }
167   }
168   Receive();
169 }
170
171 void WebSocketInstance::OnConnectCompletionCallback(void* user_data,
172                                                     int32_t result) {
173   WebSocketInstance* instance = static_cast<WebSocketInstance*>(user_data);
174   instance->OnConnectCompletion(result);
175 }
176
177 void WebSocketInstance::OnCloseCompletionCallback(void* user_data,
178                                                   int32_t result) {
179   WebSocketInstance* instance = static_cast<WebSocketInstance*>(user_data);
180   instance->OnCloseCompletion(result);
181 }
182
183 void WebSocketInstance::OnReceiveCompletionCallback(void* user_data,
184                                                     int32_t result) {
185   WebSocketInstance* instance = static_cast<WebSocketInstance*>(user_data);
186   instance->OnReceiveCompletion(result);
187 }
188
189 // The WebSocketModule provides an implementation of pp::Module that creates
190 // WebSocketInstance objects when invoked.
191 class WebSocketModule : public pp::Module {
192  public:
193   WebSocketModule() : pp::Module() {}
194   virtual ~WebSocketModule() {}
195
196   virtual pp::Instance* CreateInstance(PP_Instance instance) {
197     return new WebSocketInstance(instance);
198   }
199 };
200
201 // Implement the required pp::CreateModule function that creates our specific
202 // kind of Module.
203 namespace pp {
204 Module* CreateModule() { return new WebSocketModule(); }
205 }  // namespace pp