root/native_client_sdk/src/examples/api/websocket/websocket.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. websocket_
  2. ArrayToString
  3. HandleMessage
  4. IsConnected
  5. Open
  6. Close
  7. SendAsBinary
  8. SendAsText
  9. Receive
  10. OnConnectCompletion
  11. OnCloseCompletion
  12. OnReceiveCompletion
  13. OnConnectCompletionCallback
  14. OnCloseCompletionCallback
  15. OnReceiveCompletionCallback
  16. CreateInstance
  17. CreateModule

// 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 <stdio.h>
#include <sstream>

#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 SendAsBinary(const std::string& message);
  void SendAsText(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_;
};

#define MAX_TO_CONVERT 8
#define BYTES_PER_CHAR 4
#define TAIL_AND_NUL_SIZE 4

static std::string ArrayToString(pp::VarArrayBuffer& array) {
  char tmp[MAX_TO_CONVERT * BYTES_PER_CHAR + TAIL_AND_NUL_SIZE];
  uint32_t offs = 0;
  uint8_t* data = static_cast<uint8_t*>(array.Map());

  for (offs = 0; offs < array.ByteLength() && offs < MAX_TO_CONVERT; offs++)
    sprintf(&tmp[offs * BYTES_PER_CHAR], "%02Xh ", data[offs]);

  sprintf(&tmp[offs * BYTES_PER_CHAR], "...");
  array.Unmap();
  return std::string(tmp);
}

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 'b':
      // The command 'b' requests to send a message as a binary frame. The
      // message is passed as an argument like "b;message".
      SendAsBinary(message.substr(2));
      break;
    case 't':
      // The command 't' requests to send a message as a text frame. The message
      // is passed as an argument like "t;message".
      SendAsText(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::SendAsBinary(const std::string& message) {
  if (!IsConnected())
    return;
  uint32_t size = message.size();
  pp::VarArrayBuffer array_buffer(size);
  char* data = static_cast<char*>(array_buffer.Map());
  for (uint32_t i = 0; i < size; ++i)
    data[i] = message[i];
  array_buffer.Unmap();
  websocket_->SendMessage(array_buffer);
  std::string message_text = ArrayToString(array_buffer);
  PostMessage(pp::Var("send (binary): " + message_text));
}

void WebSocketInstance::SendAsText(const std::string& message) {
  if (!IsConnected())
    return;
  websocket_->SendMessage(pp::Var(message));
  PostMessage(pp::Var("send (text): " + 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()) {
      pp::VarArrayBuffer array_buffer(receive_var_);
      std::string message_text = ArrayToString(array_buffer);
      PostMessage("receive (binary): " + message_text);
    }
    else {
      PostMessage("receive (text): " + 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

/* [<][>][^][v][top][bottom][index][help] */