| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- /****************************************************************************
- Copyright (c) 2019 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
- #pragma once
- #include "base/ccConfig.h"
- #if (USE_SOCKET > 0) && (USE_WEBSOCKET_SERVER > 0)
- #include "uv.h"
- #include <string>
- #include <vector>
- #include <algorithm>
- #include <functional>
- #include <memory>
- #include <map>
- #include <list>
- #include <unordered_map>
- #include <thread>
- #include <mutex>
- #include <atomic>
- #include "platform/CCPlatformDefine.h"
- #include "websockets/libwebsockets.h"
- namespace cocos2d {
- namespace network {
- class WebSocketServer;
- class WebSocketServerConnection;
- /**
- * receive/send data buffer with reserved bytes
- */
- class DataFrame {
- public:
- DataFrame(const std::string& data);
- DataFrame(const void* data, int len, bool isBinary = true);
- virtual ~DataFrame();
- void append(unsigned char* p, int len);
- int slice(unsigned char** p, int len);
- int consume(int len);
- int remain() const;
- inline bool isBinary() const { return _isBinary; }
- inline bool isString() const { return !_isBinary; }
- inline bool isFront() const { return _consumed == 0; }
- void setCallback(std::function<void(const std::string&)> callback)
- {
- _callback = callback;
- }
- void onFinish(const std::string& message) {
- if (_callback) {
- _callback(message);
- }
- }
- inline int size() const { return _underlyingData.size() - LWS_PRE; }
- std::string toString();
- unsigned char* getData() { return _underlyingData.data() + LWS_PRE; }
- private:
- std::vector<unsigned char> _underlyingData;
- int _consumed = 0;
- bool _isBinary = false;
- std::function<void(const std::string&) > _callback;
- };
- class CC_DLL WebSocketServerConnection {
- public:
- WebSocketServerConnection(struct lws* wsi);
- virtual ~WebSocketServerConnection();
- enum ReadyState {
- CONNECTING = 1,
- OPEN = 2,
- CLOSING = 3,
- CLOSED = 4
- };
- void sendTextAsync(const std::string&, std::function<void(const std::string&)> callback);
-
- void sendBinaryAsync(const void*, size_t len, std::function<void(const std::string&)> callback);
- void closeAsync(int code, std::string reasson);
- /** stream is not implemented*/
- //bool beginBinary();
- /** should implement in JS */
- // bool send();
- // bool sendPing(std::string)
- //int getSocket();
- //std::shared_ptr<WebSocketServer>& getServer();
- //std::string& getPath();
- inline int getReadyState() const {
- return (int)_readyState;
- }
- std::map<std::string, std::string> getHeaders();
- std::vector<std::string> getProtocols();
- inline void setOnClose(std::function<void(int, const std::string&)> cb)
- {
- _onclose = cb;
- }
- inline void setOnError(std::function<void(const std::string&)> cb)
- {
- _onerror = cb;
- }
- inline void setOnText(std::function<void(std::shared_ptr<DataFrame>)> cb)
- {
- _ontext = cb;
- }
- inline void setOnBinary(std::function<void(std::shared_ptr<DataFrame>)> cb)
- {
- _onbinary = cb;
- }
- inline void setOnData(std::function<void(std::shared_ptr<DataFrame>)> cb)
- {
- _ondata = cb;
- }
- inline void setOnConnect(std::function<void()> cb)
- {
- _onconnect = cb;
- }
- inline void setOnEnd(std::function<void()> cb)
- {
- _onend = cb;
- }
- void onClientCloseInit();
- inline void setData(void* d) { _data = d; }
- inline void* getData() const { return _data; }
- private:
- bool send(std::shared_ptr<DataFrame> data);
- bool close(int code, std::string reasson);
- inline void scheduleSend() {
- if (_wsi)
- lws_callback_on_writable(_wsi);
- }
- void onConnected();
- void onDataReceive(void* in, int len);
- int onDrainData();
- void onHTTP();
- void onClientCloseInit(int code, const std::string& msg);
- void onDestroyClient();
- struct lws* _wsi = nullptr;
- std::map<std::string, std::string> _headers;
- std::list<std::shared_ptr<DataFrame>> _sendQueue;
- std::shared_ptr<DataFrame> _prevPkg;
- bool _closed = false;
- std::string _closeReason = "close connection";
- int _closeCode = 1000;
- std::atomic<ReadyState> _readyState{ReadyState::CLOSED};
- // Attention: do not reference **this** in callbacks
- std::function<void(int, const std::string&)> _onclose;
- std::function<void(const std::string&)> _onerror;
- std::function<void(std::shared_ptr<DataFrame>)> _ontext;
- std::function<void(std::shared_ptr<DataFrame>)> _onbinary;
- std::function<void(std::shared_ptr<DataFrame>)> _ondata;
- std::function<void()> _onconnect;
- std::function<void()> _onend;
- uv_async_t _async = {0};
- void* _data = nullptr;
- friend class WebSocketServer;
- };
- class CC_DLL WebSocketServer {
- public:
- WebSocketServer();
- virtual ~WebSocketServer();
- static void listenAsync(std::shared_ptr<WebSocketServer>& server, int port, const std::string& host, std::function<void(const std::string & errorMsg)> callback);
- void closeAsync(std::function<void(const std::string & errorMsg)> callback = nullptr);
- std::vector<std::shared_ptr<WebSocketServerConnection>> getConnections() const;
- void setOnListening(std::function<void(const std::string&)> cb)
- {
- _onlistening = cb;
- }
- void setOnError(std::function<void(const std::string&)> cb)
- {
- _onerror = cb;
- }
- void setOnClose(std::function<void(const std::string&)> cb)
- {
- _onclose = cb;
- }
- void setOnConnection(std::function<void(std::shared_ptr<WebSocketServerConnection>)> cb)
- {
- _onconnection = cb;
- }
- inline void setOnEnd(std::function<void()> cb)
- {
- _onend = cb;
- }
- inline void setOnBegin(std::function<void()> cb)
- {
- _onbegin = cb;
- }
- inline void setData(void* d) { _data = d; }
- inline void* getData() const { return _data; }
- protected:
- static void listen(std::shared_ptr<WebSocketServer> server, int port, const std::string& host, std::function<void(const std::string & errorMsg)> callback);
- bool close(std::function<void(const std::string & errorMsg)> callback = nullptr);
- void onCreateClient(struct lws* wsi);
- void onDestroyClient(struct lws* wsi);
- void onCloseClient(struct lws* wsi);
- void onCloseClientInit(struct lws* wsi, void* in, int len);
- void onClientReceive(struct lws* wsi, void* in, int len);
- int onServerWritable(struct lws* wsi);
- void onClientHTTP(struct lws* wsi);
- private:
- std::shared_ptr<WebSocketServerConnection> findConnection(struct lws *wsi);
- void destroyContext();
- std::string _host;
- lws_context* _ctx = nullptr;
- uv_async_t _async = {0};
- mutable std::mutex _connsMtx;
- std::unordered_map<struct lws*, std::shared_ptr<WebSocketServerConnection> > _conns;
- // Attention: do not reference **this** in callbacks
- std::function<void(const std::string&)> _onlistening;
- std::function<void(const std::string&)> _onerror;
- std::function<void(const std::string&)> _onclose;
- std::function<void(const std::string&)> _onclose_cb;
- std::function<void()> _onend;
- std::function<void()> _onbegin;
- std::function<void(std::shared_ptr<WebSocketServerConnection>)> _onconnection;
- enum class ServerThreadState{
- NOT_BOOTED,
- ST_ERROR,
- RUNNING,
- STOPPED,
- };
- std::atomic<ServerThreadState> _serverState {ServerThreadState::NOT_BOOTED};
- std::mutex _serverLock;
- void* _data = nullptr;
- public:
- static int _websocketServerCallback(struct lws* wsi, enum lws_callback_reasons reason,
- void* user, void* in, size_t len);
- };
- }
- }
- #endif //#if (USE_SOCKET > 0) && (USE_WEBSOCKET_SERVER > 0)
|