summaryrefslogtreecommitdiffstats
path: root/ppapi/utility/websocket/websocket_api.cc
blob: db4e01aa36e592e3da11b4d47abe8acf0d042f23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// 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/utility/websocket/websocket_api.h"

#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_macros.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/module_impl.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/websocket.h"
#include "ppapi/utility/completion_callback_factory.h"

namespace pp {

class WebSocketAPI::Implement : public WebSocket {
 public:
  Implement(Instance* instance, WebSocketAPI* api)
      : WebSocket(instance),
        api_(api),
        callback_factory_(PP_ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
  }

  virtual ~Implement() {}

  int32_t Connect(const Var& url, const Var protocols[],
                  uint32_t protocol_count) {
    CompletionCallback callback =
        callback_factory_.NewOptionalCallback(&Implement::DidConnect);
    int32_t result =
        WebSocket::Connect(url, protocols, protocol_count, callback);
    if (result != PP_OK_COMPLETIONPENDING) {
      // In synchronous cases, consumes callback here and invokes callback
      // with PP_ERROR_ABORTED instead of result in order to avoid side effects
      // in DidConnect. DidConnect ignores this invocation and doesn't call
      // any delegate virtual method.
      callback.Run(PP_ERROR_ABORTED);
    }
    return result;
  }

  int32_t Close(uint16_t code, const Var& reason) {
    CompletionCallback callback =
        callback_factory_.NewOptionalCallback(&Implement::DidClose);
    int32_t result = WebSocket::Close(code, reason, callback);
    if (result != PP_OK_COMPLETIONPENDING) {
      // In synchronous cases, consumes callback here and invokes callback
      // with PP_ERROR_ABORTED instead of result in order to avoid side effects
      // in DidConnect. DidConnect ignores this invocation and doesn't call
      // any delegate virtual method.
      callback.Run(PP_ERROR_ABORTED);
    }
    return result;
  }

  void Receive() {
    int32_t result;
    do {
      CompletionCallback callback =
          callback_factory_.NewOptionalCallback(&Implement::DidReceive);
      result = WebSocket::ReceiveMessage(&receive_message_var_, callback);
      if (result != PP_OK_COMPLETIONPENDING)
        callback.Run(result);
    } while (result == PP_OK);
  }

  void DidConnect(int32_t result) {
    if (result == PP_OK) {
      api_->WebSocketDidOpen();
      Receive();
    } else if (result != PP_ERROR_ABORTED) {
      DidClose(result);
    }
  }

  void DidReceive(int32_t result) {
    if (result == PP_OK) {
      api_->HandleWebSocketMessage(receive_message_var_);
      Receive();
    } else if (result != PP_ERROR_ABORTED) {
      DidClose(result);
    }
  }

  void DidClose(int32_t result) {
    if (result == PP_ERROR_ABORTED)
      return;
    bool was_clean = GetCloseWasClean();
    if (!was_clean)
      api_->HandleWebSocketError();
    api_->WebSocketDidClose(was_clean, GetCloseCode(), GetCloseReason());
  }

 private:
  WebSocketAPI* api_;
  CompletionCallbackFactory<Implement> callback_factory_;
  Var receive_message_var_;
};

WebSocketAPI::WebSocketAPI(Instance* instance)
    : impl_(new Implement(instance, PP_ALLOW_THIS_IN_INITIALIZER_LIST(this))) {
}

WebSocketAPI::~WebSocketAPI() {
  delete impl_;
}

int32_t WebSocketAPI::Connect(const Var& url, const Var protocols[],
                              uint32_t protocol_count) {
  return impl_->Connect(url, protocols, protocol_count);
}

int32_t WebSocketAPI::Close(uint16_t code, const Var& reason) {
  return impl_->Close(code, reason);
}

int32_t WebSocketAPI::Send(const Var& data) {
  return impl_->SendMessage(data);
}

uint64_t WebSocketAPI::GetBufferedAmount() {
  return impl_->GetBufferedAmount();
}

Var WebSocketAPI::GetExtensions() {
  return impl_->GetExtensions();
}

Var WebSocketAPI::GetProtocol() {
  return impl_->GetProtocol();
}

PP_WebSocketReadyState WebSocketAPI::GetReadyState() {
  return impl_->GetReadyState();
}

Var WebSocketAPI::GetURL() {
  return impl_->GetURL();
}

}  // namespace pp