1/*
2 * Copyright (C) 2009 Google Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#ifndef ThreadableWebSocketChannelClientWrapper_h
32#define ThreadableWebSocketChannelClientWrapper_h
33
34#if ENABLE(WEB_SOCKETS)
35
36#include "PlatformString.h"
37#include "WebSocketChannelClient.h"
38#include <wtf/Forward.h>
39#include <wtf/PassRefPtr.h>
40#include <wtf/Threading.h>
41#include <wtf/Vector.h>
42
43namespace WebCore {
44
45class ThreadableWebSocketChannelClientWrapper : public ThreadSafeRefCounted<ThreadableWebSocketChannelClientWrapper> {
46public:
47    static PassRefPtr<ThreadableWebSocketChannelClientWrapper> create(WebSocketChannelClient* client)
48    {
49        return adoptRef(new ThreadableWebSocketChannelClientWrapper(client));
50    }
51
52    void clearSyncMethodDone()
53    {
54        m_syncMethodDone = false;
55    }
56    void setSyncMethodDone()
57    {
58        m_syncMethodDone = true;
59    }
60
61    bool syncMethodDone() const
62    {
63        return m_syncMethodDone;
64    }
65
66    bool sent() const
67    {
68        return m_sent;
69    }
70    void setSent(bool sent)
71    {
72        m_sent = sent;
73        m_syncMethodDone = true;
74    }
75
76    unsigned long bufferedAmount() const
77    {
78        return m_bufferedAmount;
79    }
80    void setBufferedAmount(unsigned long bufferedAmount)
81    {
82        m_bufferedAmount = bufferedAmount;
83        m_syncMethodDone = true;
84    }
85
86    void clearClient()
87    {
88        m_client = 0;
89    }
90
91    void didConnect()
92    {
93        m_pendingConnected = true;
94        if (!m_suspended)
95            processPendingEvents();
96    }
97
98    void didReceiveMessage(const String& msg)
99    {
100        m_pendingMessages.append(msg);
101        if (!m_suspended)
102            processPendingEvents();
103    }
104
105    void didClose(unsigned long unhandledBufferedAmount)
106    {
107        m_pendingClosed = true;
108        m_bufferedAmount = unhandledBufferedAmount;
109        if (!m_suspended)
110            processPendingEvents();
111    }
112
113    void suspend()
114    {
115        m_suspended = true;
116    }
117
118    void resume()
119    {
120        m_suspended = false;
121        processPendingEvents();
122    }
123
124protected:
125    ThreadableWebSocketChannelClientWrapper(WebSocketChannelClient* client)
126        : m_client(client)
127        , m_syncMethodDone(false)
128        , m_sent(false)
129        , m_bufferedAmount(0)
130        , m_suspended(false)
131        , m_pendingConnected(false)
132        , m_pendingClosed(false)
133    {
134    }
135
136    void processPendingEvents()
137    {
138        ASSERT(!m_suspended);
139        if (m_pendingConnected) {
140            m_pendingConnected = false;
141            if (m_client)
142                m_client->didConnect();
143        }
144
145        Vector<String> messages;
146        messages.swap(m_pendingMessages);
147        for (Vector<String>::const_iterator iter = messages.begin(); iter != messages.end(); ++iter) {
148            if (m_client)
149                m_client->didReceiveMessage(*iter);
150        }
151
152        if (m_pendingClosed) {
153            m_pendingClosed = false;
154            if (m_client)
155                m_client->didClose(m_bufferedAmount);
156        }
157    }
158
159    WebSocketChannelClient* m_client;
160    bool m_syncMethodDone;
161    bool m_sent;
162    unsigned long m_bufferedAmount;
163    bool m_suspended;
164    bool m_pendingConnected;
165    Vector<String> m_pendingMessages;
166    bool m_pendingClosed;
167};
168
169} // namespace WebCore
170
171#endif // ENABLE(WEB_SOCKETS)
172
173#endif // ThreadableWebSocketChannelClientWrapper_h
174