summaryrefslogtreecommitdiffstats
path: root/native_client_sdk/src
diff options
context:
space:
mode:
authornoelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-15 07:25:02 +0000
committernoelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-15 07:25:02 +0000
commit7a42d9fed5e3b2041105d276c8734affa06dc28b (patch)
tree344510afc0c38b4ef262465c8ce39631ca68ccc8 /native_client_sdk/src
parentd8abf4b8c5efdcbe3ed923368f5d794137e2776a (diff)
downloadchromium_src-7a42d9fed5e3b2041105d276c8734affa06dc28b.zip
chromium_src-7a42d9fed5e3b2041105d276c8734affa06dc28b.tar.gz
chromium_src-7a42d9fed5e3b2041105d276c8734affa06dc28b.tar.bz2
Add WebSocket example.
Adds a websocket example to the NaCl SDK. 1- Add example to buildbot script 2- Add to main make example 3- Add examples sources 4- Update index.html to describe the example TBR= toyoshim@chromium.org Reviewed originally as: http://codereview.chromium.org/9310023/ BUG=112780 TEST=manual test is available from websocket.html Review URL: https://chromiumcodereview.appspot.com/9387022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122058 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk/src')
-rw-r--r--native_client_sdk/src/examples/Makefile2
-rw-r--r--native_client_sdk/src/examples/index.html7
-rw-r--r--native_client_sdk/src/examples/websocket/Makefile76
-rw-r--r--native_client_sdk/src/examples/websocket/websocket.cc165
-rw-r--r--native_client_sdk/src/examples/websocket/websocket.html104
-rw-r--r--native_client_sdk/src/examples/websocket/websocket.nmf6
6 files changed, 359 insertions, 1 deletions
diff --git a/native_client_sdk/src/examples/Makefile b/native_client_sdk/src/examples/Makefile
index 6f022d5..1c891c3 100644
--- a/native_client_sdk/src/examples/Makefile
+++ b/native_client_sdk/src/examples/Makefile
@@ -10,7 +10,7 @@
PROJECTS:=dlopen fullscreen_tumbler gamepad geturl hello_world_glibc
PROJECTS+=hello_world_interactive hello_world_newlib input_events load_progress
PROJECTS+=mouselock multithreaded_input_events pi_generator pong sine_synth
-PROJECTS+=tumbler
+PROJECTS+=tumbler websocket
# Define the default target
all:
diff --git a/native_client_sdk/src/examples/index.html b/native_client_sdk/src/examples/index.html
index a3d2a88..0ec82e0 100644
--- a/native_client_sdk/src/examples/index.html
+++ b/native_client_sdk/src/examples/index.html
@@ -162,6 +162,13 @@ mulithreading...</p></dd>
<p>Teaching focus: Mouse lock, Full-screen</p>
</dd>
+ <dt><a href="websocket/websocket.html">Websocket</a></dt>
+ <dd> The Websocket example demonstrates how to use the Websocket API. The
+ user first connects to the test server: ws://html5rocks.websocket.org/echo by
+ clicking on the 'Connect'' button. Then hitting Send' will cause the app to
+ send the message to the server and retrieve the reply.
+ <p>Teaching focus: Websockets</p>
+ </dd>
</dl>
</body>
</html>
diff --git a/native_client_sdk/src/examples/websocket/Makefile b/native_client_sdk/src/examples/websocket/Makefile
new file mode 100644
index 0000000..50692d7
--- /dev/null
+++ b/native_client_sdk/src/examples/websocket/Makefile
@@ -0,0 +1,76 @@
+# Copyright (c) 2011 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+#
+# GNU Make based build file.  For details on GNU Make see:
+#   http://www.gnu.org/software/make/manual/make.html
+#
+
+#
+# Project information
+#
+# These variables store project specific settings for the project name
+# build flags, files to copy or install.  In the examples it is typically
+# only the list of sources and project name that will actually change and
+# the rest of the makefile is boilerplate for defining build rules.
+#
+PROJECT:=websocket
+LDFLAGS:=-lppapi_cpp -lppapi
+CXX_SOURCES:=$(PROJECT).cc
+
+
+#
+# Get pepper directory for toolchain and includes.
+#
+# If PEPPER_ROOT is not set, then assume it can be found a two directories up,
+# from the default example directory location.
+#
+THIS_MAKEFILE:=$(abspath $(lastword $(MAKEFILE_LIST)))
+NACL_SDK_ROOT?=$(abspath $(dir $(THIS_MAKEFILE))../..)
+
+# Project Build flags
+WARNINGS:=-Wno-long-long -Wall -Wswitch-enum -pedantic -Werror
+CXXFLAGS:=-pthread -std=gnu++98 $(WARNINGS)
+
+#
+# Compute tool paths
+#
+#
+OSNAME:=$(shell python $(NACL_SDK_ROOT)/tools/getos.py)
+TC_PATH:=$(abspath $(NACL_SDK_ROOT)/toolchain/$(OSNAME)_x86_newlib)
+CXX:=$(TC_PATH)/bin/i686-nacl-g++
+
+#
+# Disable DOS PATH warning when using Cygwin based tools Windows
+#
+CYGWIN ?= nodosfilewarning
+export CYGWIN
+
+
+# Declare the ALL target first, to make the 'all' target the default build
+all: $(PROJECT)_x86_32.nexe $(PROJECT)_x86_64.nexe
+
+# Define 32 bit compile and link rules for C++ sources
+x86_32_OBJS:=$(patsubst %.cc,%_32.o,$(CXX_SOURCES))
+$(x86_32_OBJS) : %_32.o : %.cc $(THIS_MAKE)
+ $(CXX) -o $@ -c $< -m32 -O0 -g $(CXXFLAGS)
+
+$(PROJECT)_x86_32.nexe : $(x86_32_OBJS)
+ $(CXX) -o $@ $^ -m32 -O0 -g $(CXXFLAGS) $(LDFLAGS)
+
+# Define 64 bit compile and link rules for C++ sources
+x86_64_OBJS:=$(patsubst %.cc,%_64.o,$(CXX_SOURCES))
+$(x86_64_OBJS) : %_64.o : %.cc $(THIS_MAKE)
+ $(CXX) -o $@ -c $< -m64 -O0 -g $(CXXFLAGS)
+
+$(PROJECT)_x86_64.nexe : $(x86_64_OBJS)
+ $(CXX) -o $@ $^ -m64 -O0 -g $(CXXFLAGS) $(LDFLAGS)
+
+
+# Define a phony rule so it always runs, to build nexe and start up server.
+.PHONY: RUN
+RUN: all
+ python ../httpd.py
+
+
diff --git a/native_client_sdk/src/examples/websocket/websocket.cc b/native_client_sdk/src/examples/websocket/websocket.cc
new file mode 100644
index 0000000..87692e1
--- /dev/null
+++ b/native_client_sdk/src/examples/websocket/websocket.cc
@@ -0,0 +1,165 @@
+// 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.
+
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi/cpp/var_array_buffer.h"
+#include "ppapi/cpp/websocket.h"
+
+class WebSocketInstance : public pp::Instance {
+ public:
+ explicit WebSocketInstance(PP_Instance instance)
+ : pp::Instance(instance),
+ websocket_(NULL) {}
+ virtual ~WebSocketInstance() {}
+ virtual void HandleMessage(const pp::Var& var_message);
+
+ private:
+ bool IsConnected();
+
+ void Open(const std::string& url);
+ void Close();
+ void Send(const std::string& message);
+ void Receive();
+
+ void OnConnectCompletion(int32_t result);
+ void OnCloseCompletion(int32_t result);
+ void OnReceiveCompletion(int32_t result);
+
+ static void OnConnectCompletionCallback(void* user_data, int32_t result);
+ static void OnCloseCompletionCallback(void* user_data, int32_t result);
+ static void OnReceiveCompletionCallback(void* user_data, int32_t result);
+
+ pp::WebSocket* websocket_;
+ pp::Var receive_var_;
+};
+
+void WebSocketInstance::HandleMessage(const pp::Var& var_message) {
+ if (!var_message.is_string())
+ return;
+ std::string message = var_message.AsString();
+ // This message must contain a command character followed by ';' and
+ // arguments like "X;arguments".
+ if (message.length() < 2 || message[1] != ';')
+ return;
+ switch (message[0]) {
+ case 'o':
+ // The command 'o' requests to open the specified URL.
+ // URL is passed as an argument like "o;URL".
+ Open(message.substr(2));
+ break;
+ case 'c':
+ // The command 'c' requests to close without any argument like "c;"
+ Close();
+ break;
+ case 's':
+ // The command 's' requests to send a message as a text frame. The message
+ // is passed as an argument like "s;message".
+ Send(message.substr(2));
+ break;
+ }
+}
+
+bool WebSocketInstance::IsConnected() {
+ if (!websocket_)
+ return false;
+ if (websocket_->GetReadyState() != PP_WEBSOCKETREADYSTATE_OPEN)
+ return false;
+ return true;
+}
+
+void WebSocketInstance::Open(const std::string& url) {
+ pp::CompletionCallback callback(OnConnectCompletionCallback, this);
+ websocket_ = new pp::WebSocket(this);
+ if (!websocket_)
+ return;
+ websocket_->Connect(pp::Var(url), NULL, 0, callback);
+ PostMessage(pp::Var("connecting..."));
+}
+
+void WebSocketInstance::Close() {
+ if (!IsConnected())
+ return;
+ pp::CompletionCallback callback(OnCloseCompletionCallback, this);
+ websocket_->Close(
+ PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var("bye"), callback);
+}
+
+void WebSocketInstance::Send(const std::string& message) {
+ if (!IsConnected())
+ return;
+ websocket_->SendMessage(pp::Var(message));
+ PostMessage(pp::Var(std::string("send: ") + message));
+}
+
+void WebSocketInstance::Receive() {
+ pp::CompletionCallback callback(OnReceiveCompletionCallback, this);
+ // |receive_var_| must be valid until |callback| is invoked.
+ // Just use a member variable.
+ websocket_->ReceiveMessage(&receive_var_, callback);
+}
+
+void WebSocketInstance::OnConnectCompletion(int32_t result) {
+ if (result != PP_OK) {
+ PostMessage(pp::Var("connection failed"));
+ return;
+ }
+ PostMessage(pp::Var("connected"));
+ Receive();
+}
+
+void WebSocketInstance::OnCloseCompletion(int32_t result) {
+ PostMessage(pp::Var(PP_OK == result ? "closed" : "abnormally closed"));
+}
+
+void WebSocketInstance::OnReceiveCompletion(int32_t result) {
+ if (result == PP_OK) {
+ if (receive_var_.is_array_buffer())
+ PostMessage(pp::Var("receive: binary data"));
+ else
+ PostMessage(pp::Var(std::string("receive: ") + receive_var_.AsString()));
+ }
+ Receive();
+}
+
+void WebSocketInstance::OnConnectCompletionCallback(void* user_data,
+ int32_t result) {
+ WebSocketInstance* instance = static_cast<WebSocketInstance*>(user_data);
+ instance->OnConnectCompletion(result);
+}
+
+void WebSocketInstance::OnCloseCompletionCallback(void* user_data,
+ int32_t result) {
+ WebSocketInstance* instance = static_cast<WebSocketInstance*>(user_data);
+ instance->OnCloseCompletion(result);
+}
+
+void WebSocketInstance::OnReceiveCompletionCallback(void* user_data,
+ int32_t result) {
+ WebSocketInstance* instance = static_cast<WebSocketInstance*>(user_data);
+ instance->OnReceiveCompletion(result);
+}
+
+// The WebSocketModule provides an implementation of pp::Module that creates
+// WebSocketInstance objects when invoked.
+class WebSocketModule : public pp::Module {
+ public:
+ WebSocketModule() : pp::Module() {}
+ virtual ~WebSocketModule() {}
+
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new WebSocketInstance(instance);
+ }
+};
+
+
+// Implement the required pp::CreateModule function that creates our specific
+// kind of Module.
+namespace pp {
+Module* CreateModule() {
+ return new WebSocketModule();
+}
+} // namespace pp
diff --git a/native_client_sdk/src/examples/websocket/websocket.html b/native_client_sdk/src/examples/websocket/websocket.html
new file mode 100644
index 0000000..d2db565
--- /dev/null
+++ b/native_client_sdk/src/examples/websocket/websocket.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html>
+ <!--
+ 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.
+ -->
+<head>
+ <title>WebSocket</title>
+
+ <script type="text/javascript">
+ websocket = null; // Global application object.
+ statusText = 'NO-STATUS';
+
+ // Indicate success when the NaCl module has loaded.
+ function moduleDidLoad() {
+ websocket = document.getElementById('websocket');
+ updateStatus('SUCCESS');
+ }
+
+ // Handle a message coming from the NaCl module.
+ function handleMessage(message_event) {
+ console.log(message_event);
+ document.getElementById('log').value += message_event.data + '\n';
+ }
+
+ function pageDidLoad() {
+ if (websocket == null) {
+ updateStatus('LOADING...');
+ } else {
+ updateStatus();
+ }
+ }
+
+ function doConnect() {
+ // Send a request message. See also websocket.cc for the request format.
+ websocket.postMessage('o;' + document.getElementById('url').value);
+ }
+
+ function doSend() {
+ // Send a request message. See also websocket.cc for the request format.
+ websocket.postMessage(
+ 's;' + document.getElementById('message').value);
+ }
+
+ function doClose() {
+ // Send a request message. See also websocket.cc for the request format.
+ websocket.postMessage('c;');
+ }
+
+ function updateStatus(opt_message) {
+ if (opt_message)
+ statusText = opt_message;
+ var statusField = document.getElementById('statusField');
+ if (statusField) {
+ statusField.innerHTML = statusText;
+ }
+ }
+ </script>
+</head>
+<body onload="pageDidLoad()">
+
+<h1>WebSocket API Example</h1>
+<p>
+ <form action="#" onsubmit="doConnect(); return false;">
+ <input type="text" id="url"
+ value="ws://html5rocks.websocket.org/echo?encoding=text" />
+ <input type="submit" value="Connect" />
+ </form>
+
+ <form action="#" onsubmit="doSend(); return false;">
+ <input type="text" id="message" value="hello" />
+ <input type="submit" value="Send" />
+ </form>
+
+ <form action="#" onsubmit="doClose(); return false;">
+ <input type="submit" value="Close" />
+ </form>
+
+ <textarea id="log" rows="10" cols="80"></textarea>
+
+ <div id="listener">
+ <script type="text/javascript">
+ var listener = document.getElementById('listener')
+ listener.addEventListener('load', moduleDidLoad, true);
+ listener.addEventListener('message', handleMessage, true);
+ </script>
+
+ <embed name="nacl_module"
+ id="websocket"
+ width=0 height=0
+ src="websocket.nmf"
+ type="application/x-nacl" />
+ </div>
+</p>
+
+<p>Set a server URL, then push "Connect" button to establish a connection.</p>
+<p>"Send" button sends text message on the left text area.</p>
+<p>"Close" button closes the connection/</p>
+
+<h2>Status</h2>
+<div id="statusField">NO-STATUS</div>
+</body>
+</html>
diff --git a/native_client_sdk/src/examples/websocket/websocket.nmf b/native_client_sdk/src/examples/websocket/websocket.nmf
new file mode 100644
index 0000000..189344a
--- /dev/null
+++ b/native_client_sdk/src/examples/websocket/websocket.nmf
@@ -0,0 +1,6 @@
+{
+ "program": {
+ "x86-64": {"url": "websocket_x86_64.nexe"},
+ "x86-32": {"url": "websocket_x86_32.nexe"}
+ }
+}