diff --git a/API.md b/API.md new file mode 100644 index 00000000..fc76b7b2 --- /dev/null +++ b/API.md @@ -0,0 +1,196 @@ +## API +### *Overview* +There're just 3 roles in this library - `socket`,`client` and `message`. + +`client` is for physical connection while `socket` is for "namespace"(which is like a logical channel), which means one `socket` paired with one namespace, and one `client` paired with one physical connection. + +Since a physical connection can have multiple namespaces (which is called multiplex), a `client` object may have multiple `socket` objects, each is bind to a distinct `namespace`. + +Use `client` to setup the connection to the server, manange the connection status, also session id for the connection. + +Use `socket` to send messages under namespace and receives messages in the namespace, also handle special types of message. + +The `message` is just about the content you want to send, with text,binary or structured combinations. + +### *Socket* +#### Constructors +Sockets are all managed by `client`, no public constructors. + +You can get it's pointer by `client.socket(namespace)`. + +#### Event Emitter +`void emit(std::string const& name, message::list const& msglist, std::function const& ack)` + +Universal event emition interface, by applying implicit conversion magic, it is backward compatible with all previous `emit` interfaces. + +#### Event Bindings +`void on(std::string const& event_name,event_listener const& func)` + +`void on(std::string const& event_name,event_listener_aux const& func)` + +Bind a callback to specified event name. Same as `socket.on()` function in JS, `event_listener` is for full content event object,`event_listener_aux` is for convinience. + +`void off(std::string const& event_name)` + +Unbind the event callback with specified name. + +`void off_all()` + +Clear all event bindings (not including the error listener). + +`void on_error(error_listener const& l)` + +Bind the error handler for socket.io error messages. + +`void off_error()` + +Unbind the error handler. + +```C++ +//event object: +class event +{ +public: + const std::string& get_nsp() const; + + const std::string& get_name() const; + + const message::ptr& get_message() const; + + bool need_ack() const; + + void put_ack_message(message::ptr const& ack_message); + + message::ptr const& get_ack_message() const; + ... +}; +//event listener declare: +typedef std::function event_listener_aux; + +typedef std::function event_listener; + +typedef std::function error_listener; + +``` + +#### Connect and close socket +`connect` will happen for existing `socket`s automatically when `client` have opened up the physical connection. + +`socket` opened with connected `client` will connect to its namespace immediately. + +`void close()` + +Positively disconnect from namespace. + +#### Get name of namespace +`std::string const& get_namespace() const` + +Get current namespace name which the client is inside. + +### *Client* +#### Constructors +`client()` default constructor. + +#### Connection Listeners +`void set_open_listener(con_listener const& l)` + +Call when websocket is open, especially means good connectivity. + +`void set_fail_listener(con_listener const& l)` + +Call when failed in connecting. + +`void set_close_listener(close_listener const& l)` + +Call when closed or drop. See `client::close_reason` + +```C++ +//connection listener declare: +enum close_reason +{ + close_reason_normal, + close_reason_drop +}; +typedef std::function con_listener; + +typedef std::function close_listener; +``` +#### Socket listeners +`void set_socket_open_listener(socket_listener const& l)` + +Set listener for socket connect event, called when any sockets being ready to send message. + +`void set_socket_close_listener(socket_listener const& l)` + +Set listener for socket close event, called when any sockets being closed, afterward, corresponding `socket` object will be cleared from client. + +```C++ + //socket_listener declare: + typedef std::function socket_listener; +``` + +#### Connect and Close +`void connect(const std::string& uri)` + +Connect to socket.io server, eg. `client.connect("ws://localhost:3000");` + +`void close()` + +Close the client, return immediately. + +`void sync_close()` + +Close the client, return until it is really closed. + +`bool opened() const` + +Check if client's connection is opened. + +#### Transparent reconnecting +`void set_reconnect_attempts(int attempts)` + +Set max reconnect attempts, set to 0 to disable transparent reconnecting. + +`void set_reconnect_delay(unsigned millis)` + +Set minimum delay for reconnecting, this is the delay for 1st reconnecting attempt, +then the delay duration grows by attempts made. + +`void set_reconnect_delay_max(unsigned millis)` + +Set maximum delay for reconnecting. + +`void set_reconnecting_listener(con_listener const& l)` + +Set listener for reconnecting is in process. + +`void set_reconnect_listener(reconnect_listener const& l)` + +Set listener for reconnecting event, called once a delayed connecting is scheduled. + +#### Namespace +`socket::ptr socket(std::string const& nsp)` + +Get a pointer to a socket which is paired with the specified namespace. + +#### Session ID +`std::string const& get_sessionid() const` + +Get socket.io session id. + +### *Message* +`message` Base class of all message object. + +`int_message` message contains a 64-bit integer. + +`double_message` message contains a double. + +`string_message` message contains a string. + +`array_message` message contains a `vector`. + +`object_message` message contains a `map`. + +`message::ptr` pointer to `message` object, it will be one of its derived classes, judge by `message.get_flag()`. + +All designated constructor of `message` objects is hidden, you need to create message and get the `message::ptr` by `[derived]_message:create()`. diff --git a/BOOST.md b/BOOST.md new file mode 100644 index 00000000..d9c46460 --- /dev/null +++ b/BOOST.md @@ -0,0 +1,21 @@ +## Boost setup + +1. Download boost from [boost.org](http://www.boost.org/). +1. Unpack boost to some place. +1. Run either .\bootstrap.bat (on Windows), or ./bootstrap.sh (on other operating systems) under boost folder. + +## Boost build (Build the necessary subset only) + +#### Windows (or other mainstream desktop platforms shall work too): +Run with following script will build the necessary subset: + +```bash +bjam install --prefix="" --with-system --with-date_time --with-random link=static runtime-link=shared threading=multi +``` +Optionally You can merge all output .lib files into a fat one,especially if you're not using cmake. + +In output folder, run: + +```bash +lib.exe /OUT:boost.lib * +``` diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 00000000..614280df --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,48 @@ +## Install + +### With CMake +1. Install boost, see [Boost setup](#boost_setup) section. +2. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo. +3. Run `cmake -DBOOST_ROOT:STRING= -DBOOST_VER:STRING= ./` +4. Run `make install`(if makefile generated) or open generated project (if project file generated) to build. +5. Outputs is under `./build`, link with the all static libs under `./build/lib` and include headers under `./build/include` in your client code where you want to use it. + +* If you're using boost without install,you can specify `boost include dir` and `boost lib dir` separately by: +```bash +cmake +-DBOOST_INCLUDEDIR= +-DBOOST_LIBRARYDIR= +-DBOOST_VER:STRING= +./ +``` +* CMake didn't allow merging static libraries,but they're all copied to `./build/lib`, you can DIY if you like. + +### Without CMake +1. Install boost, see [Boost setup](#boost_setup) section. +2. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo. +3. Add `/include`,`./lib/websocketpp` and `./lib/rapidjson/include` to headers search path. +4. Include all files under `./src` in your project, add `sio_client.cpp`,`sio_socket.cpp`,`internal/sio_client_impl.cpp`, `internal/sio_packet.cpp` to source list. +5. Add `/lib` to library search path, add `boost.lib`(Win32) or `-lboost`(Other) link option. +6. Include `sio_client.h` in your client code where you want to use it. + +## Boost setup + +1. Download boost from [boost.org](http://www.boost.org/). +1. Unpack boost to some place. +1. Run either .\bootstrap.bat (on Windows), or ./bootstrap.sh (on other operating systems) under boost folder. + +## Boost build (Build the necessary subset only) +Windows (or other mainstream desktop platforms shall work too): + +The following script will build the necessary subset: + +```bash +bjam install --prefix="" --with-system --with-date_time --with-random link=static runtime-link=shared threading=multi +``` +Optionally You can merge all output .lib files into a fat one, especially if you're not using cmake. + +In output folder, run: + +```bash +lib.exe /OUT:boost.lib * +``` diff --git a/INSTALL_IOS.md b/INSTALL_IOS.md new file mode 100644 index 00000000..881b2085 --- /dev/null +++ b/INSTALL_IOS.md @@ -0,0 +1,33 @@ +## iOS + +### Option 1: Cocoapods + +``` +pod 'SocketIO-Client-CPP' +``` + +### Option 2: Create a static library + +1. Create a static library +1. Copy the header files into xcode + +Use the static libraries generated by the example project [iOS example project](examples/iOS) + +Create one for +- release iphoneos +- release simulator +- debug iphoneos +- debug simulator + +Join the debug libraries and the release libraries with e.g. +``` +libtool -static -o libUniversalRelease.a Release-iphoneos/libsioclient.a Release-iphonesimulator/libsioclient.a +libtool -static -o libUniversalDebug.a Debug-iphoneos/libsioclient.a Debug-iphonesimulator/libsioclient.a +``` + + +### Option 3: Manual integration + +Use this [shell](https://gist.github.com/melode11/a90114a2abf009ca22ea) to download and build boost completely automattically. It installs boost to `/prefix`. + +See the [iOS example project](examples/iOS) for how to integrate the rest. diff --git a/README.md b/README.md index 9fc2e83a..038fb244 100755 --- a/README.md +++ b/README.md @@ -1,93 +1,89 @@ # Socket.IO C++ Client [![Build Status](https://travis-ci.org/socketio/socket.io-client-cpp.svg)](https://travis-ci.org/socketio/socket.io-client-cpp) -This repository contains the Socket.IO C++ client. It depends on [websocket++](https://github.com/zaphoyd/websocketpp) and is inspired by [socket.io-clientpp](https://github.com/ebshimizu/socket.io-clientpp). - -By virtue of being written in C++, this client works in several different platforms. The [examples](https://github.com/socketio/socket.io-client-cpp/tree/master/examples) folder contains an iPhone, QT and Console example chat client! +By virtue of being written in C++, this client works in several different platforms. The [examples](https://github.com/socketio/socket.io-client-cpp/tree/master/examples) folder contains an iPhone, QT and Console example chat client! It depends on [websocket++](https://github.com/zaphoyd/websocketpp) and is inspired by [socket.io-clientpp](https://github.com/ebshimizu/socket.io-clientpp). [![Clients with iPhone, QT, Console and web](https://cldup.com/ukvVVZmvYV.png)](https://github.com/socketio/socket.io-client-cpp/tree/master/examples) ## Features - 100% written in modern C++11 -- Compatible with 1.0+ protocol +- Compatible with socket.io 1.0+ protocol - Binary support - Automatic JSON encoding - Multiplex support - Similar API to the Socket.IO JS client +- Cross platform -## How to use -### With CMake -1. Install boost, see [Boost setup](#boost_setup) section. -2. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo. -3. Run `cmake -DBOOST_ROOT:STRING= -DBOOST_VER:STRING= ./` -4. Run `make install`(if makefile generated) or open generated project (if project file generated) to build. -5. Outputs is under `./build`, link with the all static libs under `./build/lib` and include headers under `./build/include` in your client code where you want to use it. +## Installation alternatives -* If you're using boost without install,you can specify `boost include dir` and `boost lib dir` separately by: -```bash -cmake --DBOOST_INCLUDEDIR= --DBOOST_LIBRARYDIR= --DBOOST_VER:STRING= -./ -``` -* CMake didn't allow merging static libraries,but they're all copied to `./build/lib`, you can DIY if you like. +* [With CMAKE](./INSTALL.md#with-cmake) +* [Without CMAKE](./INSTALL.md#without-cmake) +* [iOS and OS X](./INSTALL_IOS.md) + * Option 1: Cocoapods + * Option 2: Create a static library + * Option 3: Manual integration + + +## Quickstart -### Without CMake -1. Install boost, see [Boost setup](#boost_setup) section. -2. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo. -3. Add `/include`,`./lib/websocketpp` and `./lib/rapidjson/include` to headers search path. -4. Include all files under `./src` in your project, add `sio_client.cpp`,`sio_socket.cpp`,`internal/sio_client_impl.cpp`, `internal/sio_packet.cpp` to source list. -5. Add `/lib` to library search path, add `boost.lib`(Win32) or `-lboost`(Other) link option. -6. Include `sio_client.h` in your client code where you want to use it. +** [Full overview of API can be seen here](./API.md) ** -## Quick start -The APIs are similar with JS client. -Connect to a server +The APIs are similar to the JS client. + +#### Connect to a server ```C++ sio::client h; h.connect("http://127.0.0.1:3000"); ``` -Emit a event +#### Emit an event + ```C++ -//emit event name only: +// emit event name only: h.socket->emit("login"); -//emit text + +// emit text h.socket()->emit("add user", username); -//emit binary + +// emit binary char buf[100]; h.socket()->emit("add user", std::make_shared(buf,100)); -//emit message object with lambda ack handler -h.socket()->emit("add user", string_message::create(username), [&](message::list const& msg) -{ + +// emit message object with lambda ack handler +h.socket()->emit("add user", string_message::create(username), [&](message::list const& msg) { }); -//emit with `message::list` -message::list li("arg1"); -li.push(string_message::create("arg2")); -socket->emit("new va",li);// support io.on("new va",function(arg1,arg2){}); style in server side. + +// emit multiple arguments +message::list li("sports"); +li.push(string_message::create("economics")); +socket->emit("categories", li); ``` -* Items in `message::list` will be expanded in server side event callback function as function arguments. +Items in `message::list` will be expanded in server side event callback function as function arguments. + +#### Bind an event -Bind a event +##### Bind with function pointer ```C++ -/**************** bind with function pointer ***************/ void OnMessage(sio::event &) { - + } h.socket()->on("new message", &OnMessage); +``` -/********************* bind with lambda ********************/ +##### Bind with lambda +```C++ h.socket()->on("login", [&](sio::event& ev) { //handle login message //post to UI thread if any UI updating. }); +``` -/**************** bind with member function *****************/ +##### Bind with member function +```C++ class MessageHandler { public: @@ -96,248 +92,13 @@ public: MessageHandler mh; h.socket()->on("new message",std::bind( &MessageHandler::OnMessage,&mh,std::placeholders::_1)); ``` -Send to other namespace -```C++ -h.socket("/chat")->emit("add user", username); -``` - -## API -### *Overview* -There're just 3 roles in this library - `socket`,`client` and `message`. - -`client` is for physical connection while `socket` is for "namespace"(which is like a logical channel), which means one `socket` paired with one namespace, and one `client` paired with one physical connection. - -Since a physical connection can have multiple namespaces (which is called multiplex), a `client` object may have multiple `socket` objects, each is bind to a distinct `namespace`. - -Use `client` to setup the connection to the server, manange the connection status, also session id for the connection. - -Use `socket` to send messages under namespace and receives messages in the namespace, also handle special types of message. - -The `message` is just about the content you want to send, with text,binary or structured combinations. - -### *Socket* -#### Constructors -Sockets are all managed by `client`, no public constructors. - -You can get it's pointer by `client.socket(namespace)`. - -#### Event Emitter -`void emit(std::string const& name, message::list const& msglist, std::function const& ack)` - -Universal event emition interface, by applying implicit conversion magic, it is backward compatible with all previous `emit` interfaces. - -#### Event Bindings -`void on(std::string const& event_name,event_listener const& func)` - -`void on(std::string const& event_name,event_listener_aux const& func)` - -Bind a callback to specified event name. Same as `socket.on()` function in JS, `event_listener` is for full content event object,`event_listener_aux` is for convinience. - -`void off(std::string const& event_name)` - -Unbind the event callback with specified name. - -`void off_all()` - -Clear all event bindings (not including the error listener). - -`void on_error(error_listener const& l)` - -Bind the error handler for socket.io error messages. - -`void off_error()` - -Unbind the error handler. - -```C++ -//event object: -class event -{ -public: - const std::string& get_nsp() const; - - const std::string& get_name() const; - - const message::ptr& get_message() const; - - bool need_ack() const; - - void put_ack_message(message::ptr const& ack_message); - - message::ptr const& get_ack_message() const; - ... -}; -//event listener declare: -typedef std::function event_listener_aux; - -typedef std::function event_listener; - -typedef std::function error_listener; - -``` - -#### Connect and close socket -`connect` will happen for existing `socket`s automatically when `client` have opened up the physical connection. - -`socket` opened with connected `client` will connect to its namespace immediately. - -`void close()` - -Positively disconnect from namespace. - -#### Get name of namespace -`std::string const& get_namespace() const` - -Get current namespace name which the client is inside. - -### *Client* -#### Constructors -`client()` default constructor. - -#### Connection Listeners -`void set_open_listener(con_listener const& l)` - -Call when websocket is open, especially means good connectivity. - -`void set_fail_listener(con_listener const& l)` - -Call when failed in connecting. - -`void set_close_listener(close_listener const& l)` - -Call when closed or drop. See `client::close_reason` - -```C++ -//connection listener declare: -enum close_reason -{ - close_reason_normal, - close_reason_drop -}; -typedef std::function con_listener; - -typedef std::function close_listener; -``` -#### Socket listeners -`void set_socket_open_listener(socket_listener const& l)` - -Set listener for socket connect event, called when any sockets being ready to send message. - -`void set_socket_close_listener(socket_listener const& l)` - -Set listener for socket close event, called when any sockets being closed, afterward, corresponding `socket` object will be cleared from client. +#### Using namespace ```C++ - //socket_listener declare: - typedef std::function socket_listener; -``` - -#### Connect and Close -`void connect(const std::string& uri)` - -Connect to socket.io server, eg. `client.connect("ws://localhost:3000");` - -`void close()` - -Close the client, return immediately. - -`void sync_close()` - -Close the client, return until it is really closed. - -`bool opened() const` - -Check if client's connection is opened. - -#### Transparent reconnecting -`void set_reconnect_attempts(int attempts)` - -Set max reconnect attempts, set to 0 to disable transparent reconnecting. - -`void set_reconnect_delay(unsigned millis)` - -Set minimum delay for reconnecting, this is the delay for 1st reconnecting attempt, -then the delay duration grows by attempts made. - -`void set_reconnect_delay_max(unsigned millis)` - -Set maximum delay for reconnecting. - -`void set_reconnecting_listener(con_listener const& l)` - -Set listener for reconnecting is in process. - -`void set_reconnect_listener(reconnect_listener const& l)` - -Set listener for reconnecting event, called once a delayed connecting is scheduled. - -#### Namespace -`socket::ptr socket(std::string const& nsp)` - -Get a pointer to a socket which is paired with the specified namespace. - -#### Session ID -`std::string const& get_sessionid() const` - -Get socket.io session id. - -### *Message* -`message` Base class of all message object. - -`int_message` message contains a 64-bit integer. - -`double_message` message contains a double. - -`string_message` message contains a string. - -`array_message` message contains a `vector`. - -`object_message` message contains a `map`. - -`message::ptr` pointer to `message` object, it will be one of its derived classes, judge by `message.get_flag()`. - -All designated constructor of `message` objects is hidden, you need to create message and get the `message::ptr` by `[derived]_message:create()`. - -## Boost setup -* Download boost from [boost.org](http://www.boost.org/). - -* Unpack boost to some place. - -* Run either .\bootstrap.bat (on Windows), or ./bootstrap.sh (on other operating systems) under boost folder. - -## Boost build (Build the necessary subset only) - -#### Windows (or other mainstream desktop platforms shall work too): -Run with following script will build the necessary subset: - -```bash -bjam install --prefix="" --with-system --with-date_time --with-random link=static runtime-link=shared threading=multi -``` -Optionally You can merge all output .lib files into a fat one,especially if you're not using cmake. - -In output folder, run: - -```bash -lib.exe /OUT:boost.lib * -``` - -### iOS - -##### Option 1: Cocoapods - -``` -pod 'SocketIO-Client-CPP' +h.socket("/chat")->emit("add user", username); ``` +** [Full overview of API can be seen here](./API.md) ** -##### Option 2: Static library - -Grab the latest library built for all architectures from https://github.com/hfossli/SocketIO-Client-CPP-iOS-Builds - -##### Option 3: Manually - -Use this [shell](https://gist.github.com/melode11/a90114a2abf009ca22ea) to download and build boost completely automattically. It installs boost to `/prefix`. - -See the [iOS example project](examples/iOS) for how to integrate the rest. +## License -##License MIT