initial commit

This commit is contained in:
Blue 2018-08-05 00:46:25 +03:00 committed by Юрий Губич
commit 4b60ece582
327 changed files with 28286 additions and 0 deletions

View 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
View 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
View 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
View 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
View 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