initial commit
This commit is contained in:
commit
4b60ece582
327 changed files with 28286 additions and 0 deletions
27
lib/wSocket/CMakeLists.txt
Normal file
27
lib/wSocket/CMakeLists.txt
Normal file
|
@ -0,0 +1,27 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(wSocket)
|
||||
|
||||
find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Network REQUIRED)
|
||||
find_package(Qt5WebSockets REQUIRED)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
set(HEADERS
|
||||
socket.h
|
||||
server.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
socket.cpp
|
||||
server.cpp
|
||||
)
|
||||
|
||||
add_library(wSocket ${HEADERS} ${SOURCES})
|
||||
|
||||
target_link_libraries(wSocket Qt5::Core)
|
||||
target_link_libraries(wSocket Qt5::Network)
|
||||
target_link_libraries(wSocket Qt5::WebSockets)
|
||||
|
||||
target_link_libraries(wSocket wType)
|
158
lib/wSocket/server.cpp
Normal file
158
lib/wSocket/server.cpp
Normal file
|
@ -0,0 +1,158 @@
|
|||
#include "server.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
W::Server::Server(const W::String& name, QObject* parent):
|
||||
QObject(parent),
|
||||
lastId(0),
|
||||
pool(),
|
||||
connections(),
|
||||
server(0),
|
||||
name(name)
|
||||
{
|
||||
server = new QWebSocketServer(name.toString().c_str(), QWebSocketServer::NonSecureMode, this);
|
||||
connect(server, SIGNAL(newConnection()), SLOT(onNewConnection()));
|
||||
connect(server, SIGNAL(serverError(QWebSocketProtocol::CloseCode)), SLOT(onServerError(QWebSocketProtocol::CloseCode)));
|
||||
}
|
||||
|
||||
W::Server::~Server()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void W::Server::listen(uint16_t port)
|
||||
{
|
||||
if (server->listen(QHostAddress::Any, port)){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void W::Server::stop()
|
||||
{
|
||||
server->close();
|
||||
lastId = 0;
|
||||
pool.clear();
|
||||
std::map<uint64_t, Socket*>::const_iterator it;
|
||||
std::map<uint64_t, Socket*>::const_iterator end = connections.end();
|
||||
|
||||
for (it = connections.begin(); it != end; ++it) {
|
||||
it->second->close();
|
||||
}
|
||||
}
|
||||
|
||||
const W::Socket& W::Server::getConnection(uint64_t p_id) const
|
||||
{
|
||||
std::map<uint64_t, Socket*>::const_iterator itr = connections.find(p_id);
|
||||
if (itr == connections.end()) {
|
||||
throw new SocketAccessError();
|
||||
}
|
||||
|
||||
return *(itr->second);
|
||||
}
|
||||
|
||||
uint64_t W::Server::getConnectionsCount() const
|
||||
{
|
||||
return connections.size();
|
||||
}
|
||||
|
||||
void W::Server::onNewConnection()
|
||||
{
|
||||
QWebSocket *webSocket = server->nextPendingConnection();
|
||||
Socket* wSocket = createSocket(webSocket);
|
||||
wSocket->setRemoteId();
|
||||
}
|
||||
|
||||
void W::Server::onSocketConnected() {
|
||||
Socket* socket = static_cast<Socket*>(sender());
|
||||
emit newConnection(*socket);
|
||||
emit connectionCountChange(getConnectionsCount());
|
||||
}
|
||||
|
||||
void W::Server::onSocketDisconnected() {
|
||||
Socket* socket = static_cast<Socket*>(sender());
|
||||
uint64_t socketId = socket->getId();
|
||||
std::map<uint64_t, Socket*>::const_iterator it = connections.find(socketId);
|
||||
connections.erase(it);
|
||||
pool.insert(socketId);
|
||||
emit closedConnection(*socket);
|
||||
emit connectionCountChange(getConnectionsCount());
|
||||
socket->deleteLater();
|
||||
}
|
||||
|
||||
void W::Server::onServerError(QWebSocketProtocol::CloseCode code)
|
||||
{
|
||||
cout << "Server error: " << code << endl;
|
||||
}
|
||||
|
||||
void W::Server::closeConnection(uint64_t p_id)
|
||||
{
|
||||
std::map<uint64_t, Socket*>::const_iterator itr = connections.find(p_id);
|
||||
if (itr == connections.end()) {
|
||||
throw new SocketAccessError();
|
||||
}
|
||||
|
||||
itr->second->close();
|
||||
}
|
||||
|
||||
W::Socket * W::Server::createSocket(QWebSocket* socket)
|
||||
{
|
||||
uint64_t connectionId;
|
||||
if (pool.empty()) {
|
||||
connectionId = ++lastId;
|
||||
} else {
|
||||
std::set<uint64_t>::const_iterator itr = pool.begin();
|
||||
connectionId = *itr;
|
||||
pool.erase(itr);
|
||||
}
|
||||
Socket *wSocket = new Socket(name, socket, connectionId, this);
|
||||
|
||||
connections[connectionId] = wSocket;
|
||||
connect(wSocket, SIGNAL(connected()), SLOT(onSocketConnected()));
|
||||
connect(wSocket, SIGNAL(disconnected()), SLOT(onSocketDisconnected()));
|
||||
connect(wSocket, SIGNAL(negotiationId(uint64_t)), SLOT(onSocketNegotiationId(uint64_t)));
|
||||
|
||||
return wSocket;
|
||||
}
|
||||
|
||||
|
||||
void W::Server::openConnection(const W::String& addr, const W::Uint64& port)
|
||||
{
|
||||
QWebSocket *webSocket = new QWebSocket();
|
||||
Socket* wSocket = createSocket(webSocket);
|
||||
wSocket->open(addr, port);
|
||||
|
||||
}
|
||||
|
||||
void W::Server::onSocketNegotiationId(uint64_t p_id)
|
||||
{
|
||||
Socket* socket = static_cast<Socket*>(sender());
|
||||
|
||||
if (p_id == socket->id) {
|
||||
socket->setRemoteName();
|
||||
} else {
|
||||
std::set<uint64_t>::const_iterator pItr = pool.lower_bound(p_id);
|
||||
uint64_t newId;
|
||||
if (pItr == pool.end()) {
|
||||
newId = ++lastId;
|
||||
} else {
|
||||
newId = *pItr;
|
||||
pool.erase(pItr);
|
||||
}
|
||||
std::map<uint64_t, Socket*>::const_iterator itr = connections.find(socket->id);
|
||||
connections.erase(itr);
|
||||
pool.insert(socket->id);
|
||||
socket->id = Uint64(newId);
|
||||
connections[newId] = socket;
|
||||
socket->setRemoteId();
|
||||
}
|
||||
}
|
||||
|
||||
W::String W::Server::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
79
lib/wSocket/server.h
Normal file
79
lib/wSocket/server.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
#include <QtCore/QObject>
|
||||
#include <QtWebSockets/QWebSocketServer>
|
||||
#include <QtNetwork/QHostAddress>
|
||||
|
||||
#include <wType/string.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
#include <utils/exception.h>
|
||||
|
||||
namespace W
|
||||
{
|
||||
class Server:
|
||||
public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Server(const String& name, QObject *parent = 0);
|
||||
~Server();
|
||||
|
||||
void listen(uint16_t port);
|
||||
void stop();
|
||||
|
||||
const Socket& getConnection(uint64_t p_id) const;
|
||||
uint64_t getConnectionsCount() const;
|
||||
void closeConnection(uint64_t p_id);
|
||||
void openConnection(const String& addr, const Uint64& port);
|
||||
String getName() const;
|
||||
|
||||
private:
|
||||
uint64_t lastId;
|
||||
std::set<uint64_t> pool;
|
||||
std::map<uint64_t, Socket*> connections;
|
||||
QWebSocketServer* server;
|
||||
String name;
|
||||
|
||||
Socket* createSocket(QWebSocket* socket);
|
||||
|
||||
signals:
|
||||
void newConnection(const W::Socket&);
|
||||
void closedConnection(const W::Socket&);
|
||||
void connectionCountChange(uint64_t count);
|
||||
|
||||
private slots:
|
||||
void onNewConnection();
|
||||
void onServerError(QWebSocketProtocol::CloseCode code);
|
||||
|
||||
void onSocketConnected();
|
||||
void onSocketDisconnected();
|
||||
void onSocketNegotiationId(uint64_t p_id);
|
||||
|
||||
private:
|
||||
class HandshakeNameError:
|
||||
public Utils::Exception
|
||||
{
|
||||
public:
|
||||
HandshakeNameError():Exception(){}
|
||||
|
||||
std::string getMessage() const{return "Name of connected socket haven't been found, but registering returned an error";}
|
||||
};
|
||||
|
||||
class SocketAccessError:
|
||||
public Utils::Exception
|
||||
{
|
||||
public:
|
||||
SocketAccessError():Exception(){}
|
||||
|
||||
std::string getMessage() const{return "An attempt to access non existing socket";}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SERVER_H
|
256
lib/wSocket/socket.cpp
Normal file
256
lib/wSocket/socket.cpp
Normal file
|
@ -0,0 +1,256 @@
|
|||
#include "socket.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
W::Socket::Socket(const W::String& p_name, QObject* parent):
|
||||
QObject(parent),
|
||||
serverCreated(false),
|
||||
state(disconnected_s),
|
||||
dState(dSize),
|
||||
socket(new QWebSocket()),
|
||||
id(0),
|
||||
name(p_name),
|
||||
remoteName(),
|
||||
helperBuffer(new W::ByteArray(4))
|
||||
{
|
||||
socket->setParent(this);
|
||||
setHandlers();
|
||||
}
|
||||
|
||||
W::Socket::Socket(const W::String& p_name, QWebSocket* p_socket, uint64_t p_id, QObject* parent):
|
||||
QObject(parent),
|
||||
serverCreated(true),
|
||||
state(disconnected_s),
|
||||
dState(dSize),
|
||||
socket(p_socket),
|
||||
id(p_id),
|
||||
name(p_name),
|
||||
remoteName(),
|
||||
helperBuffer(new W::ByteArray(4))
|
||||
{
|
||||
socket->setParent(this);
|
||||
setHandlers();
|
||||
}
|
||||
|
||||
W::Socket::~Socket()
|
||||
{
|
||||
close();
|
||||
|
||||
delete helperBuffer;
|
||||
}
|
||||
|
||||
void W::Socket::open(const W::String& addr, const W::Uint64& port)
|
||||
{
|
||||
if (state == disconnected_s) {
|
||||
String::StdStr url_str("ws://" + addr.toString() + ":" + port.toString());
|
||||
QUrl url(url_str.c_str());
|
||||
remoteName = String();
|
||||
state = connecting_s;
|
||||
socket->open(url);
|
||||
}
|
||||
}
|
||||
|
||||
void W::Socket::close()
|
||||
{
|
||||
if (state != disconnected_s && state != disconnecting_s) {
|
||||
state = disconnecting_s;
|
||||
socket->close();
|
||||
}
|
||||
}
|
||||
|
||||
void W::Socket::send(const W::Event& ev) const
|
||||
{
|
||||
//std::cout << "Sending event: " << ev.toString() << std::endl;
|
||||
W::Object::size_type size = ev.size();
|
||||
ByteArray *wba = new ByteArray(size + 5);
|
||||
wba->push32(size);
|
||||
wba->push8(ev.getType());
|
||||
ev.serialize(*wba);
|
||||
|
||||
QByteArray ba = QByteArray::fromRawData(wba->getData(), wba->size());
|
||||
socket->sendBinaryMessage(ba);
|
||||
delete wba;
|
||||
}
|
||||
|
||||
W::Uint64 W::Socket::getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
W::String W::Socket::getRemoteName() const
|
||||
{
|
||||
return remoteName; //TODO may be throw the exception, when socket is not connected?
|
||||
}
|
||||
|
||||
W::String W::Socket::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
void W::Socket::setHandlers() {
|
||||
connect(socket, SIGNAL(connected()), SLOT(onSocketConnected()));
|
||||
connect(socket, SIGNAL(disconnected()), SLOT(onSocketDisconnected()));
|
||||
connect(socket, SIGNAL(binaryMessageReceived(const QByteArray&)), SLOT(onBinaryMessageReceived(const QByteArray&)));
|
||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(onSocketError(QAbstractSocket::SocketError)));
|
||||
}
|
||||
|
||||
void W::Socket::onSocketConnected()
|
||||
{
|
||||
dState = dSize;
|
||||
delete helperBuffer;
|
||||
helperBuffer = new W::ByteArray(4);
|
||||
}
|
||||
|
||||
void W::Socket::onSocketDisconnected()
|
||||
{
|
||||
state = disconnected_s;
|
||||
emit disconnected();
|
||||
}
|
||||
|
||||
void W::Socket::onBinaryMessageReceived(const QByteArray& ba)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < ba.size()) {
|
||||
switch (dState) {
|
||||
case dSize:
|
||||
i = helperBuffer->fill(ba.data(), ba.size(), i);
|
||||
|
||||
if (helperBuffer->filled()) {
|
||||
int size = helperBuffer->pop32();
|
||||
delete helperBuffer;
|
||||
helperBuffer = new W::ByteArray(size + 1);
|
||||
dState = dBody;
|
||||
}
|
||||
break;
|
||||
case dBody:
|
||||
i = helperBuffer->fill(ba.data(), ba.size(), i);
|
||||
|
||||
if (helperBuffer->filled()) {
|
||||
Event* ev = static_cast<Event*>(W::Object::fromByteArray(*helperBuffer));
|
||||
onEvent(ev);
|
||||
|
||||
delete ev;
|
||||
|
||||
delete helperBuffer;
|
||||
helperBuffer = new W::ByteArray(4);
|
||||
dState = dSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void W::Socket::onEvent(W::Event* ev)
|
||||
{
|
||||
if (ev->isSystem()) {
|
||||
const Vocabulary& vc = static_cast<const Vocabulary&>(ev->getData());
|
||||
const String& command = static_cast<const String&>(vc.at(u"command"));
|
||||
|
||||
if (command == u"setId") {
|
||||
if (serverCreated) {
|
||||
if (state == connecting_s) {
|
||||
emit negotiationId(static_cast<const Uint64&>(vc.at(u"id")));
|
||||
} else {
|
||||
throw ErrorIdSetting();
|
||||
}
|
||||
} else {
|
||||
setId(static_cast<const Uint64&>(vc.at(u"id")));
|
||||
setRemoteName();
|
||||
}
|
||||
} else if (command == u"setName") {
|
||||
setName(static_cast<const String&>(vc.at(u"name")));
|
||||
if (static_cast<const String&>(vc.at(u"yourName")) != name) {
|
||||
setRemoteName();
|
||||
}
|
||||
emit connected();
|
||||
}
|
||||
} else {
|
||||
emit message(*ev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void W::Socket::setId(const W::Uint64& p_id)
|
||||
{
|
||||
if (state == connecting_s)
|
||||
{
|
||||
id = p_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ErrorIdSetting();
|
||||
}
|
||||
}
|
||||
|
||||
void W::Socket::setRemoteId()
|
||||
{
|
||||
if (state == disconnected_s) {
|
||||
state = connecting_s;
|
||||
}
|
||||
String command(u"setId");
|
||||
Vocabulary *vc = new Vocabulary();
|
||||
|
||||
vc->insert(u"command", command);
|
||||
vc->insert(u"id", id);
|
||||
|
||||
Address addr;
|
||||
Event ev(addr, vc, true);
|
||||
ev.setSenderId(id);
|
||||
send(ev);
|
||||
}
|
||||
|
||||
void W::Socket::setRemoteName()
|
||||
{
|
||||
String command(u"setName");
|
||||
Vocabulary *vc = new Vocabulary();
|
||||
|
||||
vc->insert(u"command", command);
|
||||
vc->insert(u"name", name);
|
||||
vc->insert(u"yourName", remoteName);
|
||||
|
||||
Address addr;
|
||||
Event ev(addr, vc, true);
|
||||
ev.setSenderId(id);
|
||||
send(ev);
|
||||
|
||||
}
|
||||
|
||||
void W::Socket::setName(const W::String& p_name)
|
||||
{
|
||||
if (state == connecting_s)
|
||||
{
|
||||
remoteName = p_name;
|
||||
state = connected_s;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ErrorNameSetting();
|
||||
}
|
||||
}
|
||||
|
||||
void W::Socket::cantDeliver(const W::Event& event) const
|
||||
{
|
||||
String command(u"cantDeliver");
|
||||
Vocabulary *vc = new Vocabulary();
|
||||
|
||||
vc->insert(u"command", command);
|
||||
vc->insert(u"event", event);
|
||||
|
||||
Address addr;
|
||||
Event ev(addr, vc, true);
|
||||
ev.setSenderId(id);
|
||||
send(ev);
|
||||
}
|
||||
|
||||
void W::Socket::onSocketError(QAbstractSocket::SocketError err)
|
||||
{
|
||||
if (state == connecting_s) {
|
||||
state = disconnected_s;
|
||||
}
|
||||
//socket->close();
|
||||
emit error(err, socket->errorString());
|
||||
}
|
||||
|
108
lib/wSocket/socket.h
Normal file
108
lib/wSocket/socket.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
#ifndef SOCKET_H
|
||||
#define SOCKET_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtWebSockets/QWebSocket>
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
#include <wType/string.h>
|
||||
#include <wType/uint64.h>
|
||||
#include <wType/bytearray.h>
|
||||
#include <wType/event.h>
|
||||
#include <wType/vocabulary.h>
|
||||
|
||||
#include <utils/exception.h>
|
||||
|
||||
namespace W
|
||||
{
|
||||
class Socket:
|
||||
public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class Server;
|
||||
|
||||
enum State
|
||||
{
|
||||
disconnected_s,
|
||||
disconnecting_s,
|
||||
connecting_s,
|
||||
connected_s
|
||||
};
|
||||
|
||||
enum DeserializationState {
|
||||
dSize,
|
||||
dBody
|
||||
};
|
||||
|
||||
public:
|
||||
explicit Socket(const String& p_name, QObject* parent = 0);
|
||||
~Socket();
|
||||
|
||||
void send(const Event& ev) const;
|
||||
void open(const String& addr, const Uint64& port);
|
||||
void close();
|
||||
|
||||
Uint64 getId() const;
|
||||
String getRemoteName() const;
|
||||
String getName() const;
|
||||
typedef QAbstractSocket::SocketError SocketError;
|
||||
|
||||
private:
|
||||
explicit Socket(const String& p_name, QWebSocket *p_socket, uint64_t p_id, QObject *parent = 0);
|
||||
|
||||
void setHandlers();
|
||||
void setId(const Uint64& p_id);
|
||||
void setRemoteId();
|
||||
void setRemoteName();
|
||||
void setName(const String& p_name);
|
||||
|
||||
bool serverCreated;
|
||||
State state;
|
||||
DeserializationState dState;
|
||||
QWebSocket *socket;
|
||||
Uint64 id;
|
||||
String name;
|
||||
String remoteName;
|
||||
ByteArray* helperBuffer;
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
void disconnected();
|
||||
void negotiationId(uint64_t p_id);
|
||||
void error(W::Socket::SocketError err, const QString& msg);
|
||||
void message(const W::Event&);
|
||||
void proxy(const W::Event&);
|
||||
|
||||
public slots:
|
||||
void cantDeliver(const Event& event) const;
|
||||
|
||||
private slots:
|
||||
void onSocketConnected();
|
||||
void onSocketDisconnected();
|
||||
void onSocketError(QAbstractSocket::SocketError err);
|
||||
void onBinaryMessageReceived(const QByteArray& ba);
|
||||
void onEvent(W::Event* ev);
|
||||
|
||||
private:
|
||||
class ErrorIdSetting:
|
||||
public Utils::Exception
|
||||
{
|
||||
public:
|
||||
ErrorIdSetting():Exception(){}
|
||||
|
||||
std::string getMessage() const{return "An attempt to set id to the socket not in connecting state";}
|
||||
};
|
||||
|
||||
class ErrorNameSetting:
|
||||
public Utils::Exception
|
||||
{
|
||||
public:
|
||||
ErrorNameSetting():Exception(){}
|
||||
|
||||
std::string getMessage() const{return "An attempt to set name to the socket not in connecting state";}
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SOCKET_H
|
Loading…
Add table
Add a link
Reference in a new issue