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.
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"
15 class WebSocketInstance
: public pp::Instance
{
17 explicit WebSocketInstance(PP_Instance instance
)
18 : pp::Instance(instance
), websocket_(NULL
) {}
19 virtual ~WebSocketInstance() {}
20 virtual void HandleMessage(const pp::Var
& var_message
);
25 void Open(const std::string
& url
);
27 void SendAsBinary(const std::string
& message
);
28 void SendAsText(const std::string
& message
);
31 void OnConnectCompletion(int32_t result
);
32 void OnCloseCompletion(int32_t result
);
33 void OnReceiveCompletion(int32_t result
);
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
);
39 pp::WebSocket
* websocket_
;
43 #define MAX_TO_CONVERT 8
44 #define BYTES_PER_CHAR 4
45 #define TAIL_AND_NUL_SIZE 4
47 static std::string
ArrayToString(pp::VarArrayBuffer
& array
) {
48 char tmp
[MAX_TO_CONVERT
* BYTES_PER_CHAR
+ TAIL_AND_NUL_SIZE
];
50 uint8_t* data
= static_cast<uint8_t*>(array
.Map());
52 for (offs
= 0; offs
< array
.ByteLength() && offs
< MAX_TO_CONVERT
; offs
++)
53 sprintf(&tmp
[offs
* BYTES_PER_CHAR
], "%02Xh ", data
[offs
]);
55 sprintf(&tmp
[offs
* BYTES_PER_CHAR
], "...");
57 return std::string(tmp
);
60 void WebSocketInstance::HandleMessage(const pp::Var
& var_message
) {
61 if (!var_message
.is_string())
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] != ';')
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));
75 // The command 'c' requests to close without any argument like "c;"
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));
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));
91 bool WebSocketInstance::IsConnected() {
94 if (websocket_
->GetReadyState() != PP_WEBSOCKETREADYSTATE_OPEN
)
99 void WebSocketInstance::Open(const std::string
& url
) {
100 pp::CompletionCallback
callback(OnConnectCompletionCallback
, this);
101 websocket_
= new pp::WebSocket(this);
104 websocket_
->Connect(pp::Var(url
), NULL
, 0, callback
);
105 PostMessage(pp::Var("connecting..."));
108 void WebSocketInstance::Close() {
111 pp::CompletionCallback
callback(OnCloseCompletionCallback
, this);
113 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var("bye"), callback
);
116 void WebSocketInstance::SendAsBinary(const std::string
& message
) {
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
));
130 void WebSocketInstance::SendAsText(const std::string
& message
) {
133 websocket_
->SendMessage(pp::Var(message
));
134 PostMessage(pp::Var("send (text): " + message
));
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
);
144 void WebSocketInstance::OnConnectCompletion(int32_t result
) {
145 if (result
!= PP_OK
) {
146 PostMessage(pp::Var("connection failed"));
149 PostMessage(pp::Var("connected"));
153 void WebSocketInstance::OnCloseCompletion(int32_t result
) {
154 PostMessage(pp::Var(PP_OK
== result
? "closed" : "abnormally closed"));
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
);
165 PostMessage("receive (text): " + receive_var_
.AsString());
171 void WebSocketInstance::OnConnectCompletionCallback(void* user_data
,
173 WebSocketInstance
* instance
= static_cast<WebSocketInstance
*>(user_data
);
174 instance
->OnConnectCompletion(result
);
177 void WebSocketInstance::OnCloseCompletionCallback(void* user_data
,
179 WebSocketInstance
* instance
= static_cast<WebSocketInstance
*>(user_data
);
180 instance
->OnCloseCompletion(result
);
183 void WebSocketInstance::OnReceiveCompletionCallback(void* user_data
,
185 WebSocketInstance
* instance
= static_cast<WebSocketInstance
*>(user_data
);
186 instance
->OnReceiveCompletion(result
);
189 // The WebSocketModule provides an implementation of pp::Module that creates
190 // WebSocketInstance objects when invoked.
191 class WebSocketModule
: public pp::Module
{
193 WebSocketModule() : pp::Module() {}
194 virtual ~WebSocketModule() {}
196 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
197 return new WebSocketInstance(instance
);
201 // Implement the required pp::CreateModule function that creates our specific
204 Module
* CreateModule() { return new WebSocketModule(); }