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

15
lib/CMakeLists.txt Normal file
View file

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 2.8.12)
project(lib)
add_subdirectory(utils)
add_subdirectory(tools)
add_subdirectory(wSocket)
add_subdirectory(wType)
add_subdirectory(wDispatcher)
add_subdirectory(wContainer)
add_subdirectory(wSsh)
add_subdirectory(wModel)
add_subdirectory(wController)
add_subdirectory(wServerUtils)
add_subdirectory(fontParser)
add_subdirectory(wDatabase)

View file

@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 2.6)
project(fontparser)
set(SOURCES
font.cpp
)
add_subdirectory(tables)
add_library(font STATIC ${SOURCES})
target_link_libraries(font tables)
add_executable(fontparser main.cpp)
target_link_libraries(fontparser font)
install(TARGETS fontparser RUNTIME DESTINATION bin)

223
lib/fontParser/font.cpp Normal file
View file

@ -0,0 +1,223 @@
#include "font.h"
#include <arpa/inet.h>
Font::Font(const std::string& p_path):
path(p_path),
tables(),
cmap(0),
hhea(0),
hmtx(0),
head(0),
name(0)
{
std::ifstream file(path, std::ios::in | std::ios::binary);
char * buffer;
buffer = new char[4];
file.read(buffer, 4);
uint32_t sfntVersion = ntohl(*((uint32_t*) buffer));
if (sfntVersion == 0x00010000) {
version = TrueTypeOutlines;
} else if (sfntVersion == 0x4f54544f) {
version = WithCFFData;
} else {
std::cout << "unsupported sfntVersion" << std::endl;
throw 1;
}
delete[] buffer;
buffer = new char[2];
file.read(buffer, 2);
numberTables = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
searchRange = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
entrySelector = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
rangeShift = ntohs(*((uint16_t*) buffer));
for (int i = 0; i < numberTables; ++i) {
Table* t = Table::fromIfStream(file);
tables.insert(std::make_pair(t->tag, t));
}
file.close();
}
Font::~Font()
{
std::map<std::string, Table*>::const_iterator beg = tables.begin();
std::map<std::string, Table*>::const_iterator end = tables.end();
for (; beg != end; ++beg) {
delete beg->second;
}
}
bool Font::hasTable(const std::string& tag) const
{
std::map<std::string, Table*>::const_iterator itr = tables.find(tag);
return itr != tables.end();
}
std::list<std::string> Font::availableTables() const
{
std::list<std::string> res;
std::map<std::string, Table*>::const_iterator beg = tables.begin();
std::map<std::string, Table*>::const_iterator end = tables.end();
for (; beg != end; ++beg) {
res.push_back(beg->first);
}
return res;
}
std::map<uint32_t, uint32_t> Font::getCharCodeToCIDTable(uint32_t start, uint32_t end)
{
if (cmap == NULL) {
cmap = static_cast<Cmap*>(tables.at("cmap"));
cmap->read(path);
}
std::map<uint32_t, uint32_t> res;
for (uint32_t i = start; i <= end; ++i) {
res.insert(std::make_pair(i, cmap->getCID(i)));
}
return res;
}
std::map<uint32_t, Hmtx::HMetric> Font::getCharCodeMetrics(uint32_t start, uint32_t end)
{
std::map<uint32_t, uint32_t> CCtoCID = getCharCodeToCIDTable(start, end);
std::map<uint32_t, Hmtx::HMetric> res;
if (hmtx == NULL) {
hmtx = static_cast<Hmtx*>(tables.at("hmtx"));
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
hmtx->numOfLongHorMetrics = hhea->numOfLongHorMetrics;
hmtx->read(path);
}
std::map<uint32_t, uint32_t>::const_iterator itr = CCtoCID.begin();
std::map<uint32_t, uint32_t>::const_iterator mend = CCtoCID.end();
for (; itr != mend; ++itr) {
res.insert(std::make_pair(itr->first, hmtx->getMetric(itr->second)));
}
return res;
}
Table * Font::getTable(const std::string& tag)
{
std::map<std::string, Table*>::iterator itr = tables.find(tag);
return itr->second;
}
uint16_t Font::getUnitsPerEm()
{
if (head == NULL) {
head = static_cast<Head*>(tables.at("head"));
head->read(path);
}
return head->unitsPerEm;
}
int16_t Font::getAscent()
{
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
return hhea->ascent;
}
int16_t Font::getDescent()
{
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
return hhea->descent;
}
int16_t Font::getLineGap()
{
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
return hhea->lineGap;
}
std::string Font::getNameField(std::string key)
{
if (name == NULL) {
name = static_cast<Name*>(tables.at("name"));
name->read(path);
}
return name->getRecord(key);
}
int16_t Font::getCaretSlopeRise()
{
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
return hhea->caretSlopeRise;
}
int16_t Font::getCaretSlopeRun()
{
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
return hhea->caretSlopeRun;
}
int16_t Font::getXMax()
{
if (head == NULL) {
head = static_cast<Head*>(tables.at("head"));
head->read(path);
}
return head->xMax;
}
int16_t Font::getXMin()
{
if (head == NULL) {
head = static_cast<Head*>(tables.at("head"));
head->read(path);
}
return head->xMin;
}
int16_t Font::getYMax()
{
if (head == NULL) {
head = static_cast<Head*>(tables.at("head"));
head->read(path);
}
return head->yMax;
}
int16_t Font::getYMin()
{
if (head == NULL) {
head = static_cast<Head*>(tables.at("head"));
head->read(path);
}
return head->yMin;
}

62
lib/fontParser/font.h Normal file
View file

@ -0,0 +1,62 @@
#ifndef FILE_H
#define FILE_H
#include <fstream>
#include <iostream>
#include <string>
#include <stdint.h>
#include <map>
#include <list>
#include "tables/table.h"
#include "tables/cmap.h"
#include "tables/hhea.h"
#include "tables/hmtx.h"
#include "tables/head.h"
#include "tables/name.h"
class Font
{
public:
enum SfntVersion {
TrueTypeOutlines,
WithCFFData
};
Font(const std::string& p_path);
~Font();
bool hasTable(const std::string& tag) const;
Table* getTable(const std::string& tag);
std::list<std::string> availableTables() const;
std::map<uint32_t, uint32_t> getCharCodeToCIDTable(uint32_t start = 0, uint32_t end = 0xffff);
std::map<uint32_t, Hmtx::HMetric> getCharCodeMetrics(uint32_t start = 0, uint32_t end = 0xffff);
uint16_t getUnitsPerEm();
int16_t getAscent();
int16_t getDescent();
int16_t getLineGap();
int16_t getCaretSlopeRise();
int16_t getCaretSlopeRun();
int16_t getXMin();
int16_t getXMax();
int16_t getYMin();
int16_t getYMax();
std::string getNameField(std::string key);
SfntVersion version;
uint16_t numberTables;
uint16_t searchRange;
uint16_t entrySelector;
uint16_t rangeShift;
private:
const std::string path;
std::map<std::string, Table*> tables;
Cmap* cmap;
Hhea* hhea;
Hmtx* hmtx;
Head* head;
Name* name;
};
#endif // FILE_H

50
lib/fontParser/main.cpp Normal file
View file

@ -0,0 +1,50 @@
#include "font.h"
#include <iostream>
#include <list>
#include <string>
#include "tables/hmtx.h"
int main(int argc, char **argv) {
Font file(argv[1]);
std::map<uint32_t, Hmtx::HMetric> cidMap = file.getCharCodeMetrics(0, 0x4ff);
std::map<uint32_t, Hmtx::HMetric>::const_iterator itr = cidMap.begin();
std::map<uint32_t, Hmtx::HMetric>::const_iterator end = cidMap.end();
std::cout << "{\n";
std::cout << " \"ascent\": " << file.getAscent() << ",\n";
std::cout << " \"descent\": " << file.getDescent() << ",\n";
std::cout << " \"lineGap\": " << file.getLineGap() << ",\n";
std::cout << " \"caretSlopeRise\": " << file.getCaretSlopeRise() << ",\n";
std::cout << " \"caretSlopeRun\": " << file.getCaretSlopeRun() << ",\n";
std::cout << " \"unitsPerEm\": " << file.getUnitsPerEm() << ",\n";
std::cout << " \"fontFamily\": \"" << file.getNameField("fontFamily") << "\",\n";
std::cout << " \"postScriptName\": \"" << file.getNameField("postScriptName") << "\",\n";
std::cout << " \"boundingBox\": {\n";
std::cout << " \"xMin\": " << file.getXMin() << ",\n";
std::cout << " \"xMax\": " << file.getXMax() << ",\n";
std::cout << " \"yMin\": " << file.getYMin() << ",\n";
std::cout << " \"yMax\": " << file.getYMax() << "\n";
std::cout << " },\n";
std::cout << " \"advanceWidthArray\": [\n ";
int i = 0;
for (; itr != end; ++itr) {
if (i != 0) {
if (i == 16) {
std::cout << ",\n ";
i = 0;
} else {
std::cout << ", ";
}
}
std::cout << itr->second.advanceWidth;
++i;
}
std::cout << "\n ]\n";
std::cout << "}" << std::endl;
return 0;
}

View file

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 2.6)
project(tables)
set(SOURCES
table.cpp
cmap.cpp
hhea.cpp
hmtx.cpp
head.cpp
name.cpp
)
add_library(tables STATIC ${SOURCES})

View file

@ -0,0 +1,218 @@
#include "cmap.h"
#include <arpa/inet.h>
Cmap::Cmap(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
Table(p_tag, p_checkSum, p_offset, p_length),
initialized(false),
mt(0)
{
}
Cmap::~Cmap()
{
if (initialized) {
delete mt;
}
}
void Cmap::read(const std::string& path)
{
std::ifstream file(path, std::ios::in | std::ios::binary);
file.seekg(offset);
char * buffer;
buffer = new char[2];
file.read(buffer, 2);
version = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
numberOfTables = ntohs(*((uint16_t*) buffer));
delete[] buffer;
buffer = new char[8];
std::list<Enc> encodings;
for (int i = 0; i < numberOfTables; ++i) {
file.read(buffer, 8);
char pb[2] = {buffer[0], buffer[1]};
char eb[2] = {buffer[2], buffer[3]};
char ob[4] = {buffer[4], buffer[5], buffer[6], buffer[7]};
uint16_t pid = ntohs(*((uint16_t*) pb));
uint16_t eid = ntohs(*((uint16_t*) eb));
uint16_t offset = ntohl(*((uint32_t*) ob));
//std::cout << "Found encoding platformId " << pid << ", encodingId " << eid << std::endl;
if (pid == 0 || (pid == 3 && eid == 1)) {
encodings.emplace_back(pid, eid, offset);
}
}
delete[] buffer;
std::list<Enc>::const_iterator itr = encodings.begin();
std::list<Enc>::const_iterator end = encodings.end();
for (; itr != end; ++itr) {
//std::cout << "Trying platformId " << itr->platformId << ", encodingId " << itr->encodingId << std::endl;
file.seekg(offset + itr->offset);
bool success = true;
MappingTable* table;
try {
table = MappingTable::fromIfStream(file);
} catch (int e) {
success = false;
}
if (success) {
initialized = true;
mt = table;
break;
}
}
file.close();
if (!initialized) {
//std::cout << "Error reading cmap: no supported encoding format" << std::endl;
throw 3;
}
}
uint32_t Cmap::getCID(uint32_t charCode) const
{
return this->mt->getCID(charCode);
}
MappingTable * MappingTable::fromIfStream(std::ifstream& file)
{
uint64_t position = file.tellg();
char * buffer;
buffer = new char[2];
file.read(buffer, 2);
uint16_t format = ntohs(*((uint16_t*) buffer));
MappingTable* table = NULL;
if (format >= 8) {
if (format != 14) {
file.read(buffer, 2); //padded .0 in stupid formats
}
delete[] buffer;
buffer = new char[4];
file.read(buffer, 4);
uint32_t length = ntohl(*((uint32_t*) buffer));
file.seekg(position);
buffer = new char[length];
file.read(buffer, length);
} else {
file.read(buffer, 2);
uint16_t length = ntohs(*((uint16_t*) buffer));
file.seekg(position);
buffer = new char[length];
file.read(buffer, length);
if (format == 4) {
table = new Format4(buffer, length);
}
}
delete[] buffer;
if (table == NULL) {
std::cout << "Unrecognized format " << format << std::endl;
throw 3;
}
return table;
}
MappingTable::MappingTable(uint16_t p_f):
format(p_f)
{
}
MappingTable::~MappingTable()
{
}
Format4::Format4(char * data, uint16_t length):
MappingTable(4),
charCodesEndCode(),
segments(0),
glyphIndexArray(0)
{
char sc[2] = {data[6], data[7]};
uint16_t segCount = ntohs(*((uint16_t*) sc)) / 2;
segments = new std::vector<SegParams>(segCount);
int endCodeShift = 14;
int startCodeShift = endCodeShift + segCount * 2 + 2;
int deltaShift = startCodeShift + segCount * 2;
int rangeShift = deltaShift + segCount * 2;
int giaShift = rangeShift + segCount * 2;
int giaLength = (length - giaShift) / 2;
glyphIndexArray = new std::vector<uint16_t>(giaLength);
// std::cout << "Segments: " << segCount << ", ";
// std::cout << "Glyphs: " << giaLength << "\n";
// std::cout << "******************************************" << "\n";
for (int i = 0; i < segCount; ++i) {
char cc[2] = {data[2 * i + endCodeShift], data[2 * i + endCodeShift + 1]};
char sc[2] = {data[2 * i + startCodeShift], data[2 * i + startCodeShift + 1]};
char dc[2] = {data[2 * i + deltaShift], data[2 * i + deltaShift + 1]};
char rc[2] = {data[2 * i + rangeShift], data[2 * i + rangeShift + 1]};
uint16_t endCharCode = ntohs(*((uint16_t*) cc));
uint16_t startCharCode = ntohs(*((uint16_t*) sc));
int16_t delta = ntohs(*((int16_t*) dc));
uint16_t range = ntohs(*((uint16_t*) rc));
SegParams& sp = segments->at(i);
sp.endCode = endCharCode;
sp.startCode = startCharCode;
sp.idDelta = delta;
sp.idRangeOffset = range;
charCodesEndCode.insert(std::make_pair(endCharCode, i));
// std::cout << "Segment " << i << ",\t";
// std::cout << "Start " << startCharCode << ",\t";
// std::cout << "End " << endCharCode << ",\t";
// std::cout << "Delta " << delta << ",\t";
// std::cout << "Range " << range << "\n";
}
// std::cout << "******************************************" << std::endl;;
for (int i = 0; i < giaLength; ++i) {
char cc[2] = {data[2 * i + giaShift], data[2 * i + giaShift + 1]};
uint16_t glyphIndex = ntohs(*((uint16_t*) cc));
glyphIndexArray->at(i) = glyphIndex;
}
}
Format4::~Format4()
{
delete segments;
delete glyphIndexArray;
}
uint32_t Format4::getCID(uint32_t charCode) const
{
uint16_t cid;
uint16_t c = charCode & 0xffff;
std::map<uint16_t, uint16_t>::const_iterator itr = charCodesEndCode.lower_bound(c);
uint16_t i = itr->second;
SegParams& seg = segments->at(i);
if (seg.startCode > c) {
return 0;
}
if (seg.idRangeOffset == 0) {
cid = c + seg.idDelta;
} else {
cid = i + seg.idRangeOffset - segments->size() + c - seg.startCode;
}
return cid;
}

View file

@ -0,0 +1,66 @@
#ifndef CMAP_H
#define CMAP_H
#include "table.h"
#include <list>
#include <map>
#include <vector>
struct Enc {
Enc(uint16_t pid, uint16_t eid, uint32_t off): platformId(pid), encodingId(eid), offset(off) {}
uint16_t platformId;
uint16_t encodingId;
uint32_t offset;
};
class MappingTable {
protected:
MappingTable(uint16_t p_f);
uint16_t format;
public:
static MappingTable* fromIfStream(std::ifstream& file);
virtual ~MappingTable();
virtual uint32_t getCID(uint32_t charCode) const = 0;
};
class Format4 : public MappingTable {
public:
Format4(char* data, uint16_t length);
~Format4();
uint32_t getCID(uint32_t charCode) const override;
private:
struct SegParams {
uint16_t endCode;
uint16_t startCode;
int16_t idDelta;
uint16_t idRangeOffset;
};
std::map<uint16_t, uint16_t> charCodesEndCode;
std::vector<SegParams>* segments;
std::vector<uint16_t>* glyphIndexArray;
};
class Cmap : public Table
{
public:
Cmap(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
~Cmap();
void read(const std::string & path) override;
uint32_t getCID(uint32_t charCode) const;
uint16_t version;
uint16_t numberOfTables;
private:
bool initialized;
MappingTable* mt;
};
#endif // CMAP_H

View file

@ -0,0 +1,93 @@
#include "head.h"
#include <arpa/inet.h>
Head::Head(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
Table(p_tag, p_checkSum, p_offset, p_length),
fontRevisionMajor(0),
fontRevisionMinor(0),
flags(0),
unitsPerEm(0),
xMin(0),
yMin(0),
xMax(0),
yMax(0),
macStyle(0),
lowestRecPPEM(0),
fontDirectionHint(0),
indexToLocFormat(0)
{
}
Head::~Head()
{
}
void Head::read(const std::string& path)
{
char * buffer;
buffer = new char[2];
std::ifstream file(path, std::ios::in | std::ios::binary);
file.seekg(offset);
file.read(buffer, 2); //version is not interesting, it is always 16.16 fixed point number equals to "1.0";
file.read(buffer, 2); //version is not interesting, it is always 16.16 fixed point number equals to "1.0";
file.read(buffer, 2);
fontRevisionMajor = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
fontRevisionMinor = ntohs(*((uint16_t*) buffer));
delete[] buffer;
buffer = new char[4];
file.read(buffer, 4); //checkSumAdjustment - it's something fishy, no idea what to use it for;
file.read(buffer, 4); //magicNumber, always set to 0x5f0f3cf5;
delete[] buffer;
buffer = new char[2];
file.read(buffer, 2);
flags = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
unitsPerEm = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2); //creation date is a signed int64
file.read(buffer, 2);
file.read(buffer, 2);
file.read(buffer, 2);
file.read(buffer, 2); //last modification date is a signed int64
file.read(buffer, 2);
file.read(buffer, 2);
file.read(buffer, 2);
file.read(buffer, 2);
xMin = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
yMin = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
xMax = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
yMax = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
macStyle = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
lowestRecPPEM = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
fontDirectionHint = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
indexToLocFormat = ntohs(*((int16_t*) buffer));
//and there is stil uint16 glyph data format, but its always 0;
file.close();
delete[] buffer;
}

View file

@ -0,0 +1,28 @@
#ifndef HEAD_H
#define HEAD_H
#include "table.h"
class Head : public Table
{
public:
Head(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
~Head();
void read(const std::string & path) override;
uint16_t fontRevisionMajor;
uint16_t fontRevisionMinor;
uint16_t flags;
uint16_t unitsPerEm;
int16_t xMin;
int16_t yMin;
int16_t xMax;
int16_t yMax;
uint16_t macStyle;
uint16_t lowestRecPPEM;
int16_t fontDirectionHint;
int16_t indexToLocFormat;
};
#endif // HEAD_H

View file

@ -0,0 +1,76 @@
#include "hhea.h"
#include <arpa/inet.h>
Hhea::Hhea(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
Table(p_tag, p_checkSum, p_offset, p_length),
ascent(0),
descent(0),
lineGap(0),
advanceWidthMax(0),
minLeftSideBearing(0),
minRightSideBearing(0),
xMaxExtent(0),
caretSlopeRise(0),
caretSlopeRun(0),
caretOffset(0),
numOfLongHorMetrics(0)
{
}
Hhea::~Hhea()
{
}
void Hhea::read(const std::string& path)
{
char * buffer;
buffer = new char[2];
std::ifstream file(path, std::ios::in | std::ios::binary);
file.seekg(offset);
file.read(buffer, 2); //version is not interesting, it is always 16.16 fixed point number equals to "1.0";
file.read(buffer, 2); //version is not interesting, it is always 16.16 fixed point number equals to "1.0";
file.read(buffer, 2);
ascent = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
descent = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
lineGap = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
advanceWidthMax = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
minLeftSideBearing = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
minRightSideBearing = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
xMaxExtent = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
caretSlopeRise = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
caretSlopeRun = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
caretOffset = ntohs(*((int16_t*) buffer));
file.read(buffer, 2); //reserved empty field, supposed to be 0;
file.read(buffer, 2); //reserved empty field, supposed to be 0;
file.read(buffer, 2); //reserved empty field, supposed to be 0;
file.read(buffer, 2); //reserved empty field, supposed to be 0;
file.read(buffer, 2); //metricDataFormat, it's supposed to be 0;
file.read(buffer, 2);
numOfLongHorMetrics = ntohs(*((uint16_t*) buffer));
delete[] buffer;
file.close();
}

View file

@ -0,0 +1,27 @@
#ifndef HHEA_H
#define HHEA_H
#include "table.h"
class Hhea : public Table
{
public:
Hhea(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
~Hhea();
void read(const std::string & path) override;
int16_t ascent;
int16_t descent;
int16_t lineGap;
uint16_t advanceWidthMax;
int16_t minLeftSideBearing;
int16_t minRightSideBearing;
int16_t xMaxExtent;
int16_t caretSlopeRise;
int16_t caretSlopeRun;
int16_t caretOffset;
uint16_t numOfLongHorMetrics;
};
#endif // HHEA_H

View file

@ -0,0 +1,59 @@
#include "hmtx.h"
#include <arpa/inet.h>
Hmtx::Hmtx(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
Table(p_tag, p_checkSum, p_offset, p_length),
numOfLongHorMetrics(0),
longHorMetric(0)
{
}
Hmtx::~Hmtx()
{
delete longHorMetric;
}
void Hmtx::read(const std::string& path)
{
if (numOfLongHorMetrics == 0) {
throw 1;
}
std::ifstream file(path, std::ios::in | std::ios::binary);
file.seekg(offset);
char * buffer;
buffer = new char[2];
longHorMetric = new std::vector<HMetric>(numOfLongHorMetrics);
for (int i = 0; i < numOfLongHorMetrics; ++i) {
HMetric& met = longHorMetric->at(i);
file.read(buffer, 2);
uint16_t aw = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
int16_t lsb = ntohs(*((int16_t*) buffer));
met.advanceWidth = aw;
met.leftSideBearing = lsb;
}
file.close();
delete[] buffer;
}
Hmtx::HMetric::HMetric():
advanceWidth(0),
leftSideBearing(0)
{
}
Hmtx::HMetric Hmtx::getMetric(uint16_t cid) const
{
if (cid >= longHorMetric->size()) {
cid = longHorMetric->size() - 1;
}
return longHorMetric->at(cid);
}

View file

@ -0,0 +1,29 @@
#ifndef HMTX_H
#define HMTX_H
#include "table.h"
#include <vector>
class Hmtx : public Table
{
public:
Hmtx(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
~Hmtx();
uint16_t numOfLongHorMetrics;
struct HMetric {
HMetric();
uint16_t advanceWidth;
int16_t leftSideBearing;
};
void read(const std::string & path) override;
HMetric getMetric(uint16_t cid) const;
private:
std::vector<HMetric>* longHorMetric;
};
#endif // HMTX_H

View file

@ -0,0 +1,136 @@
#include "name.h"
#include <arpa/inet.h>
#include <list>
#include <set>
#include <codecvt>
#include <locale>
const std::map<std::string, uint16_t> Name::nameIds({
{ "copyright", 0 },
{ "fontFamily", 1 },
{ "fontSubfamily", 2 },
{ "uniqueSubfamilyId", 3 },
{ "fullFontName", 4 },
{ "nameTableVersion", 5 },
{ "postScriptName", 6 },
{ "trademarkNotice", 7 },
{ "manufacturerName", 8 },
{ "designerName", 9 },
{ "description", 10 },
{ "vendorURL", 11 },
{ "designerURL", 12 },
{ "licenseDescription", 13 },
{ "licenseURL", 14 },
{ "preferredFamily", 16 },
{ "preferredSubfamily", 17 },
{ "compatibleFull", 18 },
{ "sampleText", 19 },
{ "postScriptCID", 20 }
});
Name::Name(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
Table(p_tag, p_checkSum, p_offset, p_length),
names()
{
}
Name::~Name()
{
}
void Name::read(const std::string& path)
{
std::ifstream file(path, std::ios::in | std::ios::binary);
file.seekg(offset);
char * buffer;
buffer = new char[2];
file.read(buffer, 2); //format. it is always 0 or 1 for stupid microsoft langTags, but I don't cate, gonna use offset;
file.read(buffer, 2);
uint16_t count = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint32_t storageOffset = offset + ntohs(*((uint16_t*) buffer));
std::list<NameRecord> list;
std::set<uint16_t> ids;
for (int i = 0; i < count; ++i) {
file.read(buffer, 2);
uint16_t pid = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint16_t eid = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint16_t lid = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint16_t nid = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint16_t length = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint16_t nameOffset = ntohs(*((uint16_t*) buffer));
//std::cout << "Found pid " << pid << ", eid " << eid << ", nid " << nid << std::endl;
if (ids.find(nid) == ids.end()) {
if ((pid == 0 && (eid == 3 || eid == 4)) || (pid == 3 && eid == 1)) { //screw microsoft, screw apple;
list.emplace_back(pid, eid, lid, nid, length, nameOffset);
ids.insert(nid);
}
}
}
std::list<NameRecord>::const_iterator itr;
for (itr = list.begin(); itr != list.end(); ++itr) {
const NameRecord& nr = *itr;
file.seekg(storageOffset + nr.offset);
if ((nr.platformId == 0 && (nr.encodingId == 3 || nr.encodingId == 4)) || (nr.platformId == 3 && nr.encodingId == 1)) {
char16_t buf[nr.length / 2];
for (int i = 0; i < nr.length / 2; ++i) {
file.read(buffer, 2);
buf[i] = ntohs(*((char16_t*) buffer));
}
std::u16string string(buf, nr.length / 2);
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
names.insert(std::make_pair(nr.nameId, convert.to_bytes(string)));
}
}
delete[] buffer;
file.close();
}
std::string Name::getRecord(uint16_t id) const
{
std::string res("");
std::map<uint16_t, std::string>::const_iterator itr = names.find(id);
if (itr != names.end()) {
res = itr->second;
}
return res;
}
std::string Name::getRecord(const std::string& name) const
{
std::map<std::string, uint16_t>::const_iterator itr = nameIds.find(name);
if (itr == nameIds.end()) {
return "";
} else {
return getRecord(itr->second);
}
}
NameRecord::NameRecord(uint16_t pid, uint16_t eid, uint16_t lid, uint16_t nid, uint16_t p_l, uint16_t p_o):
platformId(pid),
encodingId(eid),
languageId(lid),
nameId(nid),
length(p_l),
offset(p_o)
{
}

View file

@ -0,0 +1,35 @@
#ifndef NAME_H
#define NAME_H
#include <map>
#include <string>
#include "table.h"
class Name : public Table
{
public:
Name(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
~Name();
void read(const std::string & path) override;
std::string getRecord(uint16_t id) const;
std::string getRecord(const std::string& name) const;
private:
std::map<uint16_t, std::string> names;
static const std::map<std::string, uint16_t> nameIds;
};
struct NameRecord {
NameRecord(uint16_t pid, uint16_t eid, uint16_t lid, uint16_t nid, uint16_t p_l, uint16_t p_o);
uint16_t platformId;
uint16_t encodingId;
uint16_t languageId;
uint16_t nameId;
uint16_t length;
uint16_t offset;
};
#endif // NAME_H

View file

@ -0,0 +1,56 @@
#include "table.h"
#include <arpa/inet.h>
#include "cmap.h"
#include "hhea.h"
#include "hmtx.h"
#include "head.h"
#include "name.h"
Table::Table(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
tag(p_tag),
checkSum(p_checkSum),
offset(p_offset),
length(p_length)
{
}
Table::~Table()
{
}
Table* Table::fromIfStream(std::ifstream& stream)
{
char * buffer;
buffer = new char[4];
stream.read(buffer, 4);
std::string tag(buffer, 4);
stream.read(buffer, 4);
uint32_t cs = ntohl(*((uint32_t*) buffer));
stream.read(buffer, 4);
uint32_t offset = ntohl(*((uint32_t*) buffer));
stream.read(buffer, 4);
uint32_t l = ntohl(*((uint32_t*) buffer));
if (tag == "cmap") {
return new Cmap(tag, cs, offset, l);
} else if (tag == "hhea") {
return new Hhea(tag, cs, offset, l);
} else if (tag == "hmtx") {
return new Hmtx(tag, cs, offset, l);
} else if (tag == "head") {
return new Head(tag, cs, offset, l);
} else if (tag == "name") {
return new Name(tag, cs, offset, l);
} else {
return new Table(tag, cs, offset, l);
}
}
void Table::read(const std::string& path)
{
std::cout << "table with type " << tag << " is not supported yet" << std::endl;
}

View file

@ -0,0 +1,26 @@
#ifndef TABLE_H
#define TABLE_H
#include <fstream>
#include <iostream>
#include <string>
#include <stdint.h>
class Table
{
public:
Table(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
virtual ~Table();
const std::string tag;
const uint32_t checkSum;
const uint32_t offset;
const uint32_t length;
static Table* fromIfStream(std::ifstream& stream);
virtual void read(const std::string& path);
};
#endif // TABLE_H

15
lib/tools/CMakeLists.txt Normal file
View file

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 2.8.12)
project(tools)
set(HEADERS
file.h
)
set(SOURCES
file.cpp
)
add_library(tools ${HEADERS} ${SOURCES})
target_link_libraries(tools wType)

115
lib/tools/file.cpp Normal file
View file

@ -0,0 +1,115 @@
#include "file.h"
#include <iostream>
T::File::File(const W::String& p_path):
path(p_path)
{
}
T::File::~File()
{
}
const W::String & T::File::getPath() const
{
return path;
}
W::String T::File::suffix() const
{
uint64_t dotPos = path.findLastOf(W::String(u"."));
if (dotPos > path.findLastOf(W::String(u"/"))) {
return path.substr(dotPos + 1);
} else {
return W::String(u"");
}
}
bool T::File::readDirectoryRecursive(const W::String& path, std::list<T::File>* result)
{
DIR *d;
struct dirent *dir;
d = opendir(path.toString().c_str());
bool success = false;
if (d) {
while ((dir = readdir(d)) != NULL) {
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
continue;
}
W::String d_path = path + W::String(u"/") + W::String(std::string(dir->d_name));
struct stat st;
int err = lstat(d_path.toString().c_str(), &st);
if (err == 0) {
success = true;
switch (st.st_mode & S_IFMT) {
case S_IFDIR:
success = File::readDirectoryRecursive(d_path, result);
break;
case S_IFREG:
result->emplace_back(d_path);
break;
}
} else {
std::cout << "unable read description of file " << d_path.toString() << ". ";
switch (errno) {
case EACCES:
std::cout << "Search permission is denied for one of the directories in the path prefix of path";
break;
case EFAULT:
std::cout << "Bad address";
break;
case ELOOP:
std::cout << "Too many symbolic links encountered while traversing the path";
break;
case ENAMETOOLONG:
std::cout << "path is too long";
break;
case ENOENT:
std::cout << "A component of path does not exist, or path is an empty string";
break;
case ENOMEM:
std::cout << "Out of memory";
break;
case ENOTDIR:
std::cout << "A component of the path prefix of path is not a directory";
break;
case EOVERFLOW:
std::cout << "EOVERFLOW error";
break;
default:
std::cout << "undefined error";
}
std::cout << std::endl;
}
}
closedir(d);
} else {
std::cout << "unable to open a directory " << path.toString() << std::endl;
}
return success;
}
W::String T::File::parentDirectory() const
{
uint64_t lastSlashPos = path.findLastOf(W::String(u"/"));
W::String fPath = path.substr(0, lastSlashPos);
uint64_t pSpashPos = fPath.findLastOf(W::String(u"/"));
return fPath.substr(pSpashPos + 1);
}
W::String T::File::name() const
{
uint64_t slashPos = path.findLastOf(W::String(u"/"));
return path.substr(slashPos + 1);
}
W::String T::File::nameWithoutSuffix() const
{
W::String nws = name();
uint64_t dotPos = path.findLastOf(W::String(u"."));
return nws.substr(0, dotPos);
}

33
lib/tools/file.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef TOOLS_FILE_H
#define TOOLS_FILE_H
#include <wType/string.h>
#include <list>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
namespace T {
class File
{
public:
File(const W::String& p_path);
~File();
const W::String& getPath() const;
W::String suffix() const;
W::String nameWithoutSuffix() const;
W::String name() const;
W::String parentDirectory() const;
static bool readDirectoryRecursive(const W::String& path, std::list<File>* result);
private:
W::String path;
};
}
#endif // TOOLS_FILE_H

22
lib/utils/CMakeLists.txt Normal file
View file

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 2.8.12)
project(utils)
find_package(Qt5Core REQUIRED)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(HEADERS
defines.h
exception.h
signalcatcher.h
)
set(SOURCES
exception.cpp
signalcatcher.cpp
)
add_library(utils ${HEADERS} ${SOURCES})
target_link_libraries(utils Qt5::Core)

9
lib/utils/defines.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef DEFINES_UTILS_H
#define DEFINES_UTILS_H
#define handler(HANDLER) \
void _h_##HANDLER(const W::Event& ev) {h_##HANDLER(ev);}\
virtual void h_##HANDLER(const W::Event& ev);\
#endif

14
lib/utils/exception.cpp Normal file
View file

@ -0,0 +1,14 @@
#include "exception.h"
Utils::Exception::Exception()
{
}
Utils::Exception::~Exception()
{
}
const char* Utils::Exception::what() const noexcept( true )
{
return getMessage().c_str();
}

22
lib/utils/exception.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef EXCEPTION_H
#define EXCEPTION_H
#include <stdexcept>
#include <string>
namespace Utils
{
class Exception:
public std::exception
{
public:
Exception();
virtual ~Exception();
virtual std::string getMessage() const = 0;
const char* what() const noexcept( true );
};
}
#endif // EXCEPTION_H

View file

@ -0,0 +1,59 @@
#include "signalcatcher.h"
#include <signal.h>
#include <sys/socket.h>
#include <unistd.h>
int W::SignalCatcher::sigintFd[2] = {0,0};
W::SignalCatcher::SignalCatcher(QCoreApplication *p_app, QObject *parent):
QObject(parent),
app(p_app)
{
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd))
{
qFatal("Couldn't create INT socketpair");
}
if (setup_unix_signal_handlers() != 0)
{
qFatal("Couldn't install unix handlers");
}
snInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
connect(snInt, SIGNAL(activated(int)), this, SLOT(handleSigInt()));
}
W::SignalCatcher::~SignalCatcher()
{}
void W::SignalCatcher::handleSigInt()
{
snInt->setEnabled(false);
char tmp;
::read(sigintFd[1], &tmp, sizeof(tmp));
app->quit();
snInt->setEnabled(true);
}
void W::SignalCatcher::intSignalHandler(int unused)
{
char a = 1;
::write(sigintFd[0], &a, sizeof(a));
}
int W::SignalCatcher::setup_unix_signal_handlers()
{
struct sigaction s_int;
s_int.sa_handler = SignalCatcher::intSignalHandler;
sigemptyset(&s_int.sa_mask);
s_int.sa_flags = 0;
s_int.sa_flags |= SA_RESTART;
if (sigaction(SIGINT, &s_int, 0) > 0)
return 1;
return 0;
}

33
lib/utils/signalcatcher.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef SIGNALCATCHER_H
#define SIGNALCATCHER_H
#include <QtCore/QCoreApplication>
#include <QtCore/QObject>
#include <QtCore/QSocketNotifier>
namespace W
{
class SignalCatcher: public QObject
{
Q_OBJECT
public:
SignalCatcher(QCoreApplication *p_app, QObject *parent = 0);
~SignalCatcher();
static void intSignalHandler(int unused);
public slots:
void handleSigInt();
private:
QCoreApplication *app;
static int sigintFd[2];
QSocketNotifier *snInt;
static int setup_unix_signal_handlers();
};
}
#endif // SIGNALCATCHER_H

View file

@ -0,0 +1,2 @@
cmake_minimum_required(VERSION 2.8.12)

136
lib/wContainer/order.h Normal file
View file

@ -0,0 +1,136 @@
#ifndef ORDER_H
#define ORDER_H
#include <map>
#include <list>
#include <utils/exception.h>
namespace W
{
template <typename data_type, typename comparator = std::less<data_type>>
class Order
{
class Duplicates:
public Utils::Exception
{
public:
Duplicates():Exception(){}
std::string getMessage() const{return "Inserting element duplicates existing";}
};
class NotFound:
public Utils::Exception
{
public:
NotFound():Exception(){}
std::string getMessage() const{return "Erasing element haven't been found";}
};
protected:
typedef std::list<data_type> List;
public:
typedef typename List::size_type size_type;
typedef typename List::const_iterator const_iterator;
typedef typename List::iterator iterator;
protected:
typedef std::map<data_type, const_iterator, comparator> Map;
typedef typename Map::const_iterator m_const_itr;
typedef typename Map::iterator m_itr;
public:
Order():
order(),
r_map()
{}
~Order() {};
size_type size() const {
return order.size();
}
void push_back(data_type element) {
m_const_itr m_itr = r_map.find(element);
if (m_itr != r_map.end()) {
throw Duplicates();
}
const_iterator itr = order.insert(order.end(), element);
r_map.insert(std::make_pair(element, itr));
}
void erase(data_type element) {
m_const_itr itr = r_map.find(element);
if (itr == r_map.end()) {
throw NotFound();
}
order.erase(itr->second);
r_map.erase(itr);
}
void clear() {
order.clear();
r_map.clear();
}
void insert(const_iterator pos, data_type element) {
m_const_itr m_itr = r_map.find(element);
if (m_itr != r_map.end()) {
throw Duplicates();
}
const_iterator itr = order.insert(pos, element);
r_map.insert(std::make_pair(element, itr));
}
void insert(iterator pos, data_type element) {
m_const_itr m_itr = r_map.find(element);
if (m_itr != r_map.end()) {
throw Duplicates();
}
const_iterator itr = order.insert(pos, element);
r_map.insert(std::make_pair(element, itr));
}
const_iterator find(data_type element) const {
m_const_itr itr = r_map.find(element);
if (itr == r_map.end()) {
return end();
} else {
return itr->second;
}
}
const_iterator begin() const {
return order.begin();
}
const_iterator end() const {
return order.end();
}
iterator begin() {
return order.begin();
}
iterator end() {
return order.end();
}
private:
List order;
Map r_map;
};
}
#endif // ORDER_H

View file

@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 2.8.12)
project(controller)
find_package(Qt5Core REQUIRED)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(HEADERS
controller.h
controllerstring.h
list.h
vocabulary.h
attributes.h
catalogue.h
collection.h
)
set(SOURCES
controller.cpp
controllerstring.cpp
list.cpp
vocabulary.cpp
attributes.cpp
catalogue.cpp
collection.cpp
)
add_library(wController STATIC ${HEADERS} ${SOURCES})
target_link_libraries(wController Qt5::Core)
target_link_libraries(wController wSocket)
target_link_libraries(wController wDispatcher)
target_link_libraries(wController wType)

View file

@ -0,0 +1,87 @@
#include "attributes.h"
uint64_t C::Attributes::counter = 0;
C::Attributes::Attributes(const W::Address& p_address, QObject* parent):
C::Vocabulary(p_address, W::Address({W::String(u"attributes") += counter++}), parent),
attributes(new Map()),
reversed(new RMap())
{
}
C::Attributes::~Attributes()
{
delete attributes;
delete reversed;
}
void C::Attributes::_newElement(const W::String& key, const W::Object& element)
{
const W::Vocabulary& evc = static_cast<const W::Vocabulary&>(element);
const W::Uint64& type = static_cast<const W::Uint64&>(evc.at(u"type"));
const W::Address& addr = static_cast<const W::Address&>(evc.at(u"address"));
C::Controller* child = C::Controller::createByType(type, addr);
attributes->insert(std::make_pair(key, child));
reversed->insert(std::make_pair(child, key));
addController(child);
connect(child, SIGNAL(modification(const W::Object&)), SLOT(onAttrModification(const W::Object&)));
C::Vocabulary::_newElement(key, element);
}
void C::Attributes::_removeElement(const W::String& key)
{
C::Vocabulary::_removeElement(key);
Map::iterator itr = attributes->find(key);
C::Controller* ctrl = itr->second;
ctrl->setProperty("name", QString::fromStdString(key.toString()));
RMap::iterator ritr = reversed->find(ctrl);
removeController(ctrl);
attributes->erase(itr);
reversed->erase(ritr);
delete ctrl;
}
void C::Attributes::_clear()
{
C::Vocabulary::_clear();
Map::iterator itr = attributes->begin();
Map::iterator end = attributes->end();
for (; itr != end; ++itr) {
removeController(itr->second);
delete itr->second;
}
attributes->clear();
reversed->clear();
}
void C::Attributes::onAttrModification(const W::Object& data)
{
C::Controller* ctrl = static_cast<C::Controller*>(sender());
RMap::iterator ritr = reversed->find(ctrl);
emit attributeChange(ritr->second, data);
}
void C::Attributes::unsubscribe()
{
C::Controller::unsubscribe();
_clear();
}
void C::Attributes::onSocketDisconnected()
{
C::Controller::onSocketDisconnected();
dropSubscribed();
_clear();
}

View file

@ -0,0 +1,43 @@
#ifndef ATTRIBUTES_H
#define ATTRIBUTES_H
#include "vocabulary.h"
#include <map>
#include <wType/uint64.h>
namespace C {
class Attributes : public C::Vocabulary
{
Q_OBJECT
public:
Attributes(const W::Address& p_address, QObject* parent = 0);
~Attributes();
void unsubscribe();
signals:
void attributeChange(const W::String& atteName, const W::Object& value);
protected:
void _newElement(const W::String & key, const W::Object & element) override;
void _removeElement(const W::String & key) override;
void _clear() override;
protected slots:
void onAttrModification(const W::Object& data);
void onSocketDisconnected() override;
private:
typedef std::map<W::String, C::Controller*> Map;
typedef std::map<C::Controller*, W::String> RMap;
static uint64_t counter;
Map* attributes;
RMap* reversed;
};
}
#endif // ATTRIBUTES_H

View file

@ -0,0 +1,220 @@
#include "catalogue.h"
uint64_t C::Catalogue::counter = 0;
C::Catalogue::Catalogue(const W::Address p_address, QObject* parent):
C::Controller(p_address, W::Address({W::String(u"catalogue") += counter++}), parent),
order(),
hasSorting(false),
hasFilter(false),
hasData(true),
sorting(0),
filter(0)
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &C::Catalogue::_h_get);
W::Handler* addElement = W::Handler::create(address + W::Address({u"addElement"}), this, &C::Catalogue::_h_addElement);
W::Handler* removeElement = W::Handler::create(address + W::Address({u"removeElement"}), this, &C::Catalogue::_h_removeElement);
W::Handler* moveElement = W::Handler::create(address + W::Address({u"moveElement"}), this, &C::Catalogue::_h_moveElement);
W::Handler* clear = W::Handler::create(address + W::Address({u"clear"}), this, &C::Catalogue::_h_clear);
addHandler(get);
addHandler(addElement);
addHandler(removeElement);
addHandler(moveElement);
addHandler(clear);
}
C::Catalogue::~Catalogue()
{
if (hasFilter) {
delete filter;
}
if (hasSorting) {
delete sorting;
}
}
void C::Catalogue::setSorting(const W::String& field, bool ascending)
{
if (!hasSorting) {
sorting = new W::Vocabulary();
hasSorting = true;
}
sorting->insert(u"field", field);
sorting->insert(u"ascending", W::Boolean(ascending));
if (hasData) {
clearCatalogue();
}
if (subscribed) {
getData();
}
}
void C::Catalogue::clearSorting()
{
if (hasSorting) {
delete sorting;
hasSorting = false;
if (hasData) {
clearCatalogue();
}
if (subscribed) {
getData();
}
}
}
void C::Catalogue::addElement(const W::Uint64& id, const W::Uint64& before)
{
if (before == 0) {
order.push_back(id);
} else {
W::Order<uint64_t>::const_iterator pos = order.find(before);
order.insert(pos, id);
}
emit addedElement(id, before);
}
void C::Catalogue::h_get(const W::Event& ev)
{
if (hasData) {
clearCatalogue();
}
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Vector& ord = static_cast<const W::Vector&>(vc.at(u"data"));
W::Vector::size_type size = ord.length();
for (uint64_t i = 0; i < size; ++i) {
const W::Uint64& id = static_cast<const W::Uint64&>(ord.at(i));
addElement(id);
}
hasData = true;
emit data();
}
void C::Catalogue::h_addElement(const W::Event& ev)
{
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Uint64& id = static_cast<const W::Uint64&>(vc.at(u"id"));
if (vc.has(u"before")) {
const W::Uint64& before = static_cast<const W::Uint64&>(vc.at(u"before"));
addElement(id, before);
} else {
addElement(id);
}
}
void C::Catalogue::clearCatalogue()
{
order.clear();
hasData = false;
emit clear();
}
void C::Catalogue::h_clear(const W::Event& ev)
{
clearCatalogue();
}
void C::Catalogue::h_removeElement(const W::Event& ev)
{
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Uint64& id = static_cast<const W::Uint64&>(vc.at(u"id"));
removeElement(id);
}
void C::Catalogue::removeElement(const W::Uint64& id)
{
W::Order<uint64_t>::const_iterator pos = order.find(id);
if (pos == order.end()) {
emit serviceMessage(QString("Recieved event to remove element with id ") + id.toString().c_str() + " but element under such id isn't present in catalogue, skipping");
return;
}
order.erase(id);
uint64_t pid;
emit removedElement(pid);
}
W::Vocabulary * C::Catalogue::createSubscriptionVC() const
{
W::Vocabulary* vc = C::Controller::createSubscriptionVC();
if (hasSorting) {
vc->insert(u"sorting", sorting->copy());
}
if (hasFilter) {
vc->insert(u"filter", filter->copy());
}
return vc;
}
void C::Catalogue::h_moveElement(const W::Event& ev)
{
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Uint64& id = static_cast<const W::Uint64&>(vc.at(u"id"));
W::Order<uint64_t>::const_iterator pos = order.find(id);
if (pos == order.end()) {
emit serviceMessage(QString("Recieved event to move element with id ") + id.toString().c_str() + " but element under such id isn't present in catalogue, skipping");
return;
}
order.erase(id);
if (vc.has(u"before")) {
const W::Uint64& before = static_cast<const W::Uint64&>(vc.at(u"before"));
W::Order<uint64_t>::const_iterator beforePosition = order.find(before);
if (beforePosition == order.end()) {
emit serviceMessage(QString("Recieved event to move element with id ") +
id.toString().c_str() + " before element with id " + before.toString().c_str() +
" but element under id " + before.toString().c_str() +
" isn't present in catalogue, inserting to the end");
order.push_back(id);
emit movedElement(id);
return;
}
order.insert(beforePosition, id);
emit movedElement(id, before);
} else {
order.push_back(id);
emit movedElement(id);
}
}
void C::Catalogue::getData()
{
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"params", createSubscriptionVC());
send(vc, W::Address{u"get"});
}
void C::Catalogue::addRemoteElement(const W::Vocabulary& element) const
{
send(static_cast<W::Vocabulary*>(element.copy()), W::Address{u"add"});
}
void C::Catalogue::updateRemoteElement(const W::Uint64& id, const W::Vocabulary& newValue) const
{
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"id", id);
vc->insert(u"value", newValue);
send(vc, W::Address{u"update"});
}

View file

@ -0,0 +1,63 @@
#ifndef CATALOGUE_H
#define CATALOGUE_H
/**
* @todo write docs
*/
#include "controller.h"
#include <wType/address.h>
#include <wType/string.h>
#include <wType/vocabulary.h>
#include <wType/boolean.h>
#include <wContainer/order.h>
namespace C {
class Catalogue : public Controller {
Q_OBJECT
public:
Catalogue(const W::Address p_address, QObject* parent);
~Catalogue();
void setSorting(const W::String& field, bool ascending = true);
void clearSorting();
void addRemoteElement(const W::Vocabulary& element) const;
void updateRemoteElement(const W::Uint64& id, const W::Vocabulary& newValue) const;
signals:
void addedElement(uint64_t id, uint64_t before = 0);
void movedElement(uint64_t id, uint64_t before = 0);
void removedElement(uint64_t id);
void clear();
void data();
protected:
handler(get)
handler(addElement)
handler(removeElement)
handler(moveElement)
handler(clear)
virtual void addElement(const W::Uint64& id, const W::Uint64& before = W::Uint64(0));
virtual void clearCatalogue();
virtual void removeElement(const W::Uint64& id);
virtual void getData();
W::Vocabulary* createSubscriptionVC() const override;
protected:
W::Order<uint64_t> order;
private:
bool hasSorting;
bool hasFilter;
bool hasData;
W::Vocabulary* sorting;
W::Vocabulary* filter;
static uint64_t counter;
};
}
#endif // CATALOGUE_H

View file

@ -0,0 +1,136 @@
#include "collection.h"
C::Collection::Collection(const W::Address p_address, QObject* parent):
C::Catalogue(p_address, parent),
elements(),
waitingElements(),
hasData(false)
{
}
C::Collection::~Collection()
{
}
void C::Collection::addChildVocabulary(const W::Uint64& id)
{
C::Vocabulary* ctrl = new C::Vocabulary(pairAddress + id);
elements.insert(std::make_pair(id, ctrl));
waitingElements.insert(ctrl);
addController(ctrl);
connect(ctrl, SIGNAL(data()), this, SLOT(onChildVCData()));
if (hasData) {
hasData = false;
}
}
void C::Collection::addElement(const W::Uint64& id, const W::Uint64& before)
{
C::Catalogue::addElement(id, before);
addChildVocabulary(id);
}
void C::Collection::clearCatalogue()
{
C::Catalogue::clearCatalogue();
std::set<C::Vocabulary*>::const_iterator itr = waitingElements.begin();
std::set<C::Vocabulary*>::const_iterator end = waitingElements.end();
for (; itr != end; ++itr) {
disconnect(*itr, SIGNAL(data()), this, SLOT(onChildVCData()));
}
elements.clear();
waitingElements.clear();
cleanChildren();
}
void C::Collection::removeElement(const W::Uint64& id)
{
C::Catalogue::removeElement(id);
Elements::const_iterator itr = elements.find(id);
C::Vocabulary* ctrl = itr->second;
removeController(ctrl);
elements.erase(itr);
if (!hasData) {
std::set<C::Vocabulary*>::const_iterator witr = waitingElements.find(ctrl);
if (witr != waitingElements.end()) {
disconnect(ctrl, SIGNAL(data()), this, SLOT(onChildVCData()));
waitingElements.erase(witr);
if (waitingElements.size() == 0) {
hasData = true;
emit ready();
}
}
}
delete ctrl;
}
void C::Collection::h_get(const W::Event& ev)
{
hasData = false;
C::Catalogue::h_get(ev);
if (waitingElements.size() == 0) {
hasData = true;
emit ready();
}
}
void C::Collection::h_clear(const W::Event& ev)
{
C::Catalogue::h_clear(ev);
if (!hasData) {
hasData = true;
emit ready();
}
}
void C::Collection::onChildVCData()
{
C::Vocabulary* child = static_cast<C::Vocabulary*>(sender());
std::set<C::Vocabulary*>::const_iterator itr = waitingElements.find(child);
waitingElements.erase(itr);
disconnect(child, SIGNAL(data()), this, SLOT(onChildVCData()));
if (waitingElements.size() == 0) {
hasData = true;
emit ready();
}
}
std::set<uint64_t> C::Collection::find(const W::String& field, const W::Object& value)
{
if (!hasData) {
emit serviceMessage(QString("An attempt to look for record where ") + field.toString().c_str() + " == " + value.toString().c_str() + " in " + address.toString().c_str() + " but controller has no data yet");
throw 2;
}
std::set<uint64_t> response;
Elements::const_iterator itr = elements.begin();
Elements::const_iterator end = elements.end();
for (; itr != end; ++itr) {
if (itr->second->at(field) == value) {
response.insert(itr->first);
}
}
return response;
}
const C::Vocabulary & C::Collection::get(uint64_t id) const
{
return *(elements.find(id)->second);
}

View file

@ -0,0 +1,52 @@
#ifndef COLLECTION_H
#define COLLECTION_H
#include "catalogue.h"
#include "vocabulary.h"
#include <wType/address.h>
#include <map>
#include <set>
namespace C {
/**
* @todo write docs
*/
class Collection : public C::Catalogue {
Q_OBJECT
public:
Collection(const W::Address p_address, QObject* parent = 0);
~Collection();
std::set<uint64_t> find(const W::String& field, const W::Object& value);
const C::Vocabulary& get(uint64_t id) const;
signals:
void ready(); //emits when every VC received their data;
protected:
void addElement(const W::Uint64 & id, const W::Uint64 & before) override;
void clearCatalogue() override;
void removeElement(const W::Uint64 & id) override;
void h_get(const W::Event & ev) override;
void h_clear(const W::Event & ev) override;
private:
typedef std::map<uint64_t, C::Vocabulary*> Elements;
Elements elements;
std::set<C::Vocabulary*> waitingElements;
bool hasData;
void addChildVocabulary(const W::Uint64& id);
private slots:
void onChildVCData();
};
}
#endif // COLLECTION_H

View file

@ -0,0 +1,278 @@
#include "controller.h"
#include "controllerstring.h"
#include "list.h"
#include "vocabulary.h"
#include "attributes.h"
#include "catalogue.h"
C::Controller::Controller(const W::Address& p_address, const W::Address& my_address, QObject* parent):
QObject(parent),
pairAddress(p_address),
address(my_address),
subscribed(false),
dispatcher(0),
socket(0),
registered(false),
controllers(new CList()),
handlers(new HList()),
properties(new W::Vector())
{
W::Handler* props = W::Handler::create(address + W::Address({u"properties"}), this, &C::Controller::_h_properties);
addHandler(props);
}
C::Controller::~Controller()
{
if (subscribed) {
unsubscribe();
}
if (registered) {
unregisterController();
}
CList::iterator itr = controllers->begin();
CList::iterator end = controllers->end();
for (; itr != end; ++itr) {
delete *itr;
}
HList::iterator hItr = handlers->begin();
HList::iterator hEnd = handlers->end();
for (; hItr != hEnd; ++hItr) {
delete *hItr;
}
delete controllers;
delete handlers;
delete properties;
}
void C::Controller::addController(C::Controller* ctrl)
{
controllers->push_back(ctrl);
connect(ctrl, SIGNAL(serviceMessage(const QString&)), SIGNAL(serviceMessage(const QString&)));
if (registered) {
ctrl->registerController(dispatcher, socket);
}
if (subscribed && !ctrl->subscribed) {
ctrl->subscribe();
}
}
void C::Controller::addHandler(W::Handler* handler)
{
handlers->push_back(handler);
if (registered) {
dispatcher->registerHandler(handler);
}
}
void C::Controller::removeHandler(W::Handler* handler)
{
handlers->erase(handler);
if (registered) {
dispatcher->unregisterHandler(handler);
}
}
void C::Controller::removeController(C::Controller* ctrl)
{
if (subscribed && !ctrl->subscribed) {
ctrl->unsubscribe();
}
if (registered) {
ctrl->unregisterController();
}
disconnect(ctrl, SIGNAL(serviceMessage(const QString&)), this, SIGNAL(serviceMessage(const QString&)));
controllers->erase(ctrl);
}
void C::Controller::h_properties(const W::Event& event)
{
delete properties;
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(event.getData());
properties = static_cast<W::Vector*>(vc.at(u"properties").copy());
//emit serviceMessage("successfully received properties");
}
void C::Controller::registerController(W::Dispatcher* dp, const W::Socket* sock)
{
if (registered) {
emit serviceMessage(QString("Controller ") + address.toString().c_str() + " is already registered");
throw 1;
} else {
dispatcher = dp;
socket = sock;
connect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
CList::iterator itr = controllers->begin();
CList::iterator end = controllers->end();
for (; itr != end; ++itr) {
C::Controller* ctrl = *itr;
ctrl->registerController(dispatcher, socket);
}
HList::iterator hItr = handlers->begin();
HList::iterator hEnd = handlers->end();
for (; hItr != hEnd; ++hItr) {
W::Handler* handler = *hItr;
dispatcher->registerHandler(handler);
}
registered = true;
}
}
void C::Controller::unregisterController()
{
if (!registered) {
emit serviceMessage(QString("Controller ") + address.toString().c_str() + " is already unregistered");
throw 2;
} else {
CList::iterator itr = controllers->begin();
CList::iterator end = controllers->end();
for (; itr != end; ++itr) {
Controller* ctrl = *itr;
ctrl->unregisterController();
}
HList::iterator hItr = handlers->begin();
HList::iterator hEnd = handlers->end();
for (; hItr != hEnd; ++hItr) {
W::Handler* handler = *hItr;
dispatcher->unregisterHandler(handler);
}
disconnect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
dispatcher = 0;
socket = 0;
registered = false;
}
}
void C::Controller::send(W::Vocabulary* vc, const W::Address& handlerAddress) const
{
if (!registered) {
emit serviceMessage(QString("An attempt to send event from model ") + address.toString().c_str() + " which was not registered");
throw 3;
}
vc->insert(u"source", address);
W::Event ev(pairAddress + handlerAddress, vc);
ev.setSenderId(socket->getId());
socket->send(ev);
}
void C::Controller::subscribe()
{
if (subscribed) {
emit serviceMessage(QString("An attempt to subscribe model ") + address.toString().c_str() + " which is already subscribed");
throw 3;
}
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"params", createSubscriptionVC());
send(vc, W::Address{u"subscribe"});
CList::iterator itr = controllers->begin();
CList::iterator end = controllers->end();
for (; itr != end; ++itr) {
(*itr)->subscribe();
}
subscribed = true;
}
void C::Controller::unsubscribe()
{
if (!subscribed) {
emit serviceMessage(QString("An attempt to unsubscribe model ") + address.toString().c_str() + " which not subscribed");
throw 3;
}
send(new W::Vocabulary(), W::Address{u"unsubscribe"});
CList::iterator itr = controllers->begin();
CList::iterator end = controllers->end();
for (; itr != end; ++itr) {
(*itr)->unsubscribe();
}
subscribed = false;
}
void C::Controller::onSocketDisconnected()
{
subscribed = false;
}
C::Controller * C::Controller::createByType(int type, const W::Address& address, QObject* parent)
{
C::Controller* ptr;
switch (type) {
case string:
ptr = new C::String(address, parent);
break;
case list:
ptr = new C::List(address, parent);
break;
case vocabulary:
ptr = new C::Vocabulary(address, parent);
break;
case catalogue:
ptr = new C::Catalogue(address, parent);
break;
case attributes:
ptr = new C::Attributes(address, parent);
break;
default:
throw 1;
}
return ptr;
}
void C::Controller::dropSubscribed()
{
subscribed = false;
CList::iterator itr = controllers->begin();
CList::iterator end = controllers->end();
for (; itr != end; ++itr) {
(*itr)->dropSubscribed();
}
}
W::Vocabulary * C::Controller::createSubscriptionVC() const
{
return new W::Vocabulary();
}
void C::Controller::cleanChildren()
{
CList::const_iterator beg = controllers->begin();
CList::const_iterator end = controllers->end();
while (beg != end) {
C::Controller* ctrl = *beg;
removeController(ctrl);
delete ctrl;
beg = controllers->begin();
}
}
bool C::Controller::isSubscribed()
{
return subscribed;
}

View file

@ -0,0 +1,82 @@
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <utils/defines.h>
#include <QtCore/QObject>
#include <QtCore/QString>
#include <wType/address.h>
#include <wType/event.h>
#include <wType/vector.h>
#include <wType/vocabulary.h>
#include <wType/string.h>
#include <wDispatcher/dispatcher.h>
#include <wDispatcher/handler.h>
#include <wSocket/socket.h>
#include <wContainer/order.h>
namespace C {
class Controller : public QObject
{
Q_OBJECT
public:
enum ModelType {
string,
list,
vocabulary,
catalogue,
attributes = 50
};
Controller(const W::Address& p_address, const W::Address& my_address, QObject* parent = 0);
virtual ~Controller();
void addController(C::Controller* ctrl);
void addHandler(W::Handler* handler);
void registerController(W::Dispatcher* dp, const W::Socket* sock);
void unregisterController();
void subscribe();
void unsubscribe();
bool isSubscribed();
void removeHandler(W::Handler* handler);
void removeController(C::Controller* ctrl);
static C::Controller* createByType(int type, const W::Address& address, QObject* parent = 0);
signals:
void serviceMessage(const QString& msg) const;
void modification(const W::Object& data);
protected:
W::Address pairAddress;
W::Address address;
bool subscribed;
void send(W::Vocabulary* vc, const W::Address& handlerAddress) const;
handler(properties)
void dropSubscribed();
virtual W::Vocabulary* createSubscriptionVC() const;
void cleanChildren();
private:
typedef W::Order<W::Handler*> HList;
typedef W::Order<C::Controller*> CList;
W::Dispatcher* dispatcher;
const W::Socket* socket;
bool registered;
CList* controllers;
HList* handlers;
W::Vector* properties;
protected slots:
virtual void onSocketDisconnected();
};
}
#endif // CONTROLLER_H

View file

@ -0,0 +1,25 @@
#include "controllerstring.h"
uint64_t C::String::counter = 0;
C::String::String(const W::Address p_address, QObject* parent):
C::Controller(p_address, W::Address({W::String(u"string") += counter++}), parent),
data(u"")
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &C::String::_h_get);
addHandler(get);
}
C::String::~String()
{
}
void C::String::h_get(const W::Event& ev)
{
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
data = static_cast<const W::String&>(vc.at(u"data"));
emit change(QString(data.toString().c_str()));
emit modification(data);
}

View file

@ -0,0 +1,33 @@
#ifndef CONTROLLER_STRING_H
#define CONTROLLER_STRING_H
#include "controller.h"
#include <wType/string.h>
#include <wType/vocabulary.h>
#include <wType/event.h>
#include <QtCore/QString>
namespace C {
class String : public C::Controller
{
Q_OBJECT
public:
String(const W::Address p_address, QObject* parent = 0);
~String();
signals:
void change(const QString& str);
protected:
W::String data;
handler(get)
private:
static uint64_t counter;
};
}
#endif // CONTROLLER_STRING_H

57
lib/wController/list.cpp Normal file
View file

@ -0,0 +1,57 @@
#include "list.h"
uint64_t C::List::counter = 0;
C::List::List(const W::Address p_address, QObject* parent):
C::Controller(p_address, W::Address({W::String(u"list") += counter++}), parent),
data(new W::Vector())
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &C::List::_h_get);
W::Handler* push = W::Handler::create(address + W::Address({u"push"}), this, &C::List::_h_push);
W::Handler* clear = W::Handler::create(address + W::Address({u"clear"}), this, &C::List::_h_clear);
addHandler(get);
addHandler(push);
addHandler(clear);
}
C::List::~List()
{
delete data;
}
void C::List::h_get(const W::Event& ev)
{
emit clear();
data->clear();
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Vector& edata = static_cast<const W::Vector&>(vc.at(u"data"));
int size = edata.size();
for (int i = 0; i < size; ++i) {
data->push(edata.at(i));
emit newElement(edata.at(i));
}
emit modification(*data);
}
void C::List::h_push(const W::Event& ev)
{
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Object& el = vc.at(u"data");
data->push(el);
emit newElement(el);
emit modification(*data);
}
void C::List::h_clear(const W::Event& ev)
{
emit clear();
data->clear();
emit modification(*data);
}

36
lib/wController/list.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef CONTROLLER_LIST_H
#define CONTROLLER_LIST_H
#include "controller.h"
#include <wType/address.h>
#include <wType/object.h>
#include <wType/event.h>
#include <wType/vector.h>
namespace C {
class List : public C::Controller
{
Q_OBJECT
public:
List(const W::Address p_address, QObject* parent);
~List();
signals:
void clear();
void newElement(const W::Object& element);
protected:
W::Vector* data;
handler(get)
handler(push)
handler(clear)
private:
static uint64_t counter;
};
}
#endif // CONTROLLER_LIST_H

View file

@ -0,0 +1,119 @@
#include "vocabulary.h"
uint64_t C::Vocabulary::counter = 0;
C::Vocabulary::Vocabulary(const W::Address p_address, QObject* parent):
C::Controller(p_address, W::Address({W::String(u"vocabulary") += counter++}), parent),
p_data(new W::Vocabulary())
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &C::Vocabulary::_h_get);
W::Handler* change = W::Handler::create(address + W::Address({u"change"}), this, &C::Vocabulary::_h_change);
W::Handler* clear = W::Handler::create(address + W::Address({u"clear"}), this, &C::Vocabulary::_h_clear);
addHandler(get);
addHandler(change);
addHandler(clear);
}
C::Vocabulary::~Vocabulary()
{
delete p_data;
}
C::Vocabulary::Vocabulary(const W::Address p_address, const W::Address& my_address, QObject* parent):
C::Controller(p_address, my_address, parent),
p_data(new W::Vocabulary())
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &C::Vocabulary::_h_get);
W::Handler* change = W::Handler::create(address + W::Address({u"change"}), this, &C::Vocabulary::_h_change);
W::Handler* clear = W::Handler::create(address + W::Address({u"clear"}), this, &C::Vocabulary::_h_clear);
addHandler(get);
addHandler(change);
addHandler(clear);
}
void C::Vocabulary::h_get(const W::Event& ev)
{
_clear();
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Vocabulary& e_data = static_cast<const W::Vocabulary&>(vc.at(u"data"));
W::Vector keys = e_data.keys();
int size = keys.length();
for (int i = 0; i < size; ++i) {
const W::String& key = static_cast<const W::String&>(keys.at(i));
_newElement(key, e_data.at(key));
}
emit modification(*p_data);
emit data();
}
void C::Vocabulary::h_change(const W::Event& ev)
{
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Vector& erase = static_cast<const W::Vector&>(vc.at(u"erase"));
const W::Vocabulary& insert = static_cast<const W::Vocabulary&>(vc.at(u"insert"));
int eSize = erase.length();
for (int i = 0; i < eSize; ++i) {
const W::String& key = static_cast<const W::String&>(erase.at(i));
_removeElement(key);
}
W::Vector keys = insert.keys();
int iSize = keys.length();
for (int i = 0; i < iSize; ++i) {
const W::String& key = static_cast<const W::String&>(keys.at(i));
_newElement(key, insert.at(key));
}
emit modification(*p_data);
}
void C::Vocabulary::h_clear(const W::Event& ev)
{
_clear();
emit modification(*p_data);
}
void C::Vocabulary::_newElement(const W::String& key, const W::Object& element)
{
p_data->insert(key, element);
emit newElement(key, element);
}
void C::Vocabulary::_removeElement(const W::String& key)
{
emit removeElement(key);
p_data->erase(key);
}
void C::Vocabulary::_clear()
{
emit clear();
p_data->clear();
}
const W::Object & C::Vocabulary::at(const W::String& key) const
{
return p_data->at(key);
}
const W::Object & C::Vocabulary::at(const W::String::u16string& key) const
{
return p_data->at(key);
}
bool C::Vocabulary::has(const W::String& key) const
{
return p_data->has(key);
}
bool C::Vocabulary::has(const W::String::u16string& key) const
{
return p_data->has(key);
}

View file

@ -0,0 +1,49 @@
#ifndef CONTROLLER_VOCABULARY_H
#define CONTROLLER_VOCABULARY_H
#include "controller.h"
#include <wType/address.h>
#include <wType/object.h>
#include <wType/event.h>
#include <wType/vector.h>
#include <wType/vocabulary.h>
namespace C {
class Vocabulary : public C::Controller
{
Q_OBJECT
protected:
Vocabulary(const W::Address p_address, const W::Address& my_address, QObject* parent = 0); //for inheritors
public:
Vocabulary(const W::Address p_address, QObject* parent = 0);
~Vocabulary();
const W::Object& at(const W::String& key) const;
const W::Object& at(const W::String::u16string& key) const;
bool has(const W::String& key) const;
bool has(const W::String::u16string& key) const;
signals:
void clear();
void newElement(const W::String& key, const W::Object& element);
void removeElement(const W::String& key);
void data();
protected:
W::Vocabulary* p_data;
handler(get)
handler(change)
handler(clear)
virtual void _newElement(const W::String& key, const W::Object& element);
virtual void _removeElement(const W::String& key);
virtual void _clear();
private:
static uint64_t counter;
};
}
#endif // VOCABULARY_H

View file

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 2.8.12)
project(database)
find_package(Qt5Core REQUIRED)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(HEADERS
database.h
resourcecache.h
)
set(SOURCES
database.cpp
resourcecache.cpp
)
add_library(wDatabase STATIC ${HEADERS} ${SOURCES})
target_link_libraries(wDatabase Qt5::Core)
target_link_libraries(wDatabase lmdb)
target_link_libraries(wDatabase wType)
target_link_libraries(wDatabase wModel)

230
lib/wDatabase/database.cpp Normal file
View file

@ -0,0 +1,230 @@
#include "database.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <wType/bytearray.h>
#include <algorithm>
Database::Database(const W::String& dbName, QObject* parent):
M::ICatalogue(W::Address({dbName}), parent),
name(dbName),
opened(false),
environment(lmdb::env::create()),
dbi(0),
elements()
{
}
Database::~Database()
{
}
void Database::open()
{
if (!opened) {
checkDirAndOpenEnvironment();
index();
opened = true;
}
}
void Database::addIndex(const W::String& fieldName, W::Object::objectType fieldType)
{
ICatalogue::addIndex(fieldName, fieldType);
if (opened) {
lmdb::txn rtxn = lmdb::txn::begin(environment, nullptr, MDB_RDONLY);
lmdb::cursor cursor = lmdb::cursor::open(rtxn, dbi);
lmdb::val key;
lmdb::val value;
while (cursor.get(key, value, MDB_NEXT)) {
uint64_t iKey = *((uint64_t*) key.data());
W::ByteArray ba(value.size());
ba.fill(value.data(), value.size());
W::Vocabulary* wVal = static_cast<W::Vocabulary*>(W::Object::fromByteArray(ba));
IndexMap::const_iterator itr = indexes.find(fieldName);
itr->second->add(wVal->at(itr->first), iKey);
delete wVal;
}
cursor.close();
rtxn.abort();
}
}
uint64_t Database::addElement(const W::Vocabulary& record)
{
if (!opened) {
throw 6; //TODO
}
uint64_t id = ICatalogue::addElement(record);
elements.insert(id);
int size = record.size();
W::ByteArray ba(size + 1);
ba.push8(record.getType());
record.serialize(ba);
lmdb::val key((uint8_t*) &id, 8);
lmdb::val value(ba.getData(), ba.size());
lmdb::txn wTrans = lmdb::txn::begin(environment);
dbi.put(wTrans, key, value);
wTrans.commit();
return id;
}
void Database::checkDirAndOpenEnvironment()
{
int state1 = mkdir("./db", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (state1 != 0 && errno != EEXIST) {
emit serviceMessage("Failed to create a root database folder");
throw 1;
}
W::String path("./db/");
path += name;
int state2 = mkdir(path.toString().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (state2 != 0 && errno != EEXIST) {
emit serviceMessage(QString("Failed to create ") + name.toString().c_str() + " database folder");
throw 1;
}
environment.set_mapsize(1UL * 1024UL * 1024UL * 1024UL);
environment.set_max_dbs(10);
environment.open(path.toString().c_str(), 0, 0664);
lmdb::txn wTrans = lmdb::txn::begin(environment);
dbi = lmdb::dbi::open(wTrans, "main", MDB_CREATE | MDB_INTEGERKEY);
wTrans.commit();
}
void Database::index()
{
lmdb::txn rtxn = lmdb::txn::begin(environment, nullptr, MDB_RDONLY);
lmdb::cursor cursor = lmdb::cursor::open(rtxn, dbi);
lmdb::val key;
lmdb::val value;
while (cursor.get(key, value, MDB_NEXT)) {
uint64_t iKey = *((uint64_t*) key.data());
W::ByteArray ba(value.size());
ba.fill(value.data(), value.size());
W::Vocabulary* wVal = static_cast<W::Vocabulary*>(W::Object::fromByteArray(ba));
ICatalogue::addElement(*wVal);
elements.insert(iKey);
delete wVal;
}
cursor.close();
rtxn.abort();
emit countChange(elements.size());
}
W::Vocabulary* Database::getElement(uint64_t id)
{
lmdb::txn rtxn = lmdb::txn::begin(environment, nullptr, MDB_RDONLY);
lmdb::val key((uint8_t*) &id, 8);
lmdb::val value;
if (dbi.get(rtxn, key, value)) {
W::ByteArray ba(value.size());
ba.fill(value.data(), value.size());
W::Vocabulary* wVal = static_cast<W::Vocabulary*>(W::Object::fromByteArray(ba));
rtxn.abort();
return wVal;
} else {
rtxn.abort();
throw 3;
}
}
std::set<uint64_t> Database::getAll() const
{
return elements;
}
void Database::removeElement(uint64_t id)
{
if (!opened) {
throw 6; //TODO
}
ICatalogue::removeElement(id);
lmdb::txn transaction = lmdb::txn::begin(environment);
lmdb::val key((uint8_t*) &id, 8);
dbi.del(transaction, key);
transaction.commit();
elements.erase(id);
}
void Database::clear()
{
if (!opened) {
throw 6; //TODO
}
M::ICatalogue::clear();
lmdb::txn transaction = lmdb::txn::begin(environment);
dbi.drop(transaction);
transaction.commit();
}
void Database::addModel(M::Model* model)
{
connect(model, SIGNAL(subscribersCountChange(uint64_t)), this, SLOT(onChildSubscribersCountChange(uint64_t)));
M::ICatalogue::addModel(model);
}
void Database::removeModel(M::Model* model)
{
disconnect(model, SIGNAL(subscribersCountChange(uint64_t)), this, SLOT(onChildSubscribersCountChange(uint64_t)));
M::ICatalogue::removeModel(model);
}
void Database::onChildSubscribersCountChange(uint64_t count)
{
if (count == 0) {
M::Model* model = static_cast<M::Model*>(sender());
removeModel(model);
emit serviceMessage(QString("Unregistered model ") + model->getAddress().toString().c_str() + " because there no subscribers left");
model->deleteLater();
}
}
void Database::modifyElement(uint64_t id, const W::Vocabulary& newValue)
{
if (!opened) {
throw 6; //TODO
}
int size = newValue.size();
W::ByteArray ba(size + 1);
ba.push8(newValue.getType());
newValue.serialize(ba);
lmdb::val key((uint8_t*) &id, 8);
lmdb::val value(ba.getData(), ba.size());
lmdb::txn wTrans = lmdb::txn::begin(environment);
dbi.put(wTrans, key, value);
wTrans.commit();
}
uint64_t Database::size() const
{
return elements.size();
}

56
lib/wDatabase/database.h Normal file
View file

@ -0,0 +1,56 @@
#ifndef DATABASE_H
#define DATABASE_H
#include "lmdb++.h"
#include <map>
#include <set>
#include <wModel/icatalogue.h>
#include <wType/string.h>
#include <wType/address.h>
class Database: public M::ICatalogue
{
Q_OBJECT
class AbstractIndex;
public:
Database(const W::String& dbName, QObject* parent = 0);
~Database();
void open();
uint64_t addElement(const W::Vocabulary& record) override;
W::Vocabulary* getElement(uint64_t id) override;
void removeElement(uint64_t id) override;
void clear() override;
void modifyElement(uint64_t id, const W::Vocabulary & newValue) override;
uint64_t size() const override;
void addIndex(const W::String& fieldName, W::Object::objectType fieldType) override;
void addModel(M::Model* model);
void removeModel(M::Model* model);
protected:
std::set<uint64_t> getAll() const override;
private:
void checkDirAndOpenEnvironment();
void index();
private slots:
void onChildSubscribersCountChange(uint64_t count);
public:
const W::String name;
private:
bool opened;
lmdb::env environment;
lmdb::dbi dbi;
std::set<uint64_t> elements;
};
#endif // DATABASE_H

1913
lib/wDatabase/lmdb++.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,277 @@
#include "resourcecache.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <fstream>
ResourceCache::ResourceCache(const W::String& dbName, QObject* parent):
M::Model(W::Address{dbName}, parent),
subscribeMember(W::Handler::create(W::Address({}), this, &ResourceCache::_h_subscribeMember)),
name(dbName),
opened(false),
environment(lmdb::env::create()),
dbi(0),
elements(),
lastIndex(0)
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &ResourceCache::_h_get);
addHandler(get);
}
ResourceCache::~ResourceCache()
{
delete subscribeMember;
}
void ResourceCache::open()
{
if (!opened) {
checkDirAndOpenEnvironment();
lmdb::txn rtxn = lmdb::txn::begin(environment, nullptr, MDB_RDONLY);
lmdb::cursor cursor = lmdb::cursor::open(rtxn, dbi);
lmdb::val key;
lmdb::val value;
while (cursor.get(key, value, MDB_NEXT)) {
uint64_t iKey = *((uint64_t*) key.data());
elements.insert(iKey);
if (iKey > lastIndex) {
lastIndex = iKey;
}
}
cursor.close();
rtxn.abort();
opened = true;
emit countChange(elements.size());
}
}
void ResourceCache::checkDirAndOpenEnvironment()
{
int state1 = mkdir("./dbMedia", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (state1 != 0 && errno != EEXIST) {
emit serviceMessage("Failed to create a root database folder");
throw 1;
}
W::String path("./dbMedia/");
path += name;
int state2 = mkdir(path.toString().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (state2 != 0 && errno != EEXIST) {
emit serviceMessage(QString("Failed to create ") + name.toString().c_str() + " database folder");
throw 1;
}
environment.set_mapsize(1UL * 1024UL * 1024UL * 1024UL);
environment.set_max_dbs(10);
environment.open(path.toString().c_str(), 0, 0664);
lmdb::txn wTrans = lmdb::txn::begin(environment);
dbi = lmdb::dbi::open(wTrans, "main", MDB_CREATE | MDB_INTEGERKEY);
wTrans.commit();
}
uint64_t ResourceCache::addResource(const W::String& path)
{
uint64_t id = ++lastIndex;
elements.insert(id);
W::ByteArray ba(path.size() + 1);
ba.push8(path.getType());
path.serialize(ba);
lmdb::val key((uint8_t*) &id, 8);
lmdb::val value(ba.getData(), ba.size());
lmdb::txn wTrans = lmdb::txn::begin(environment);
dbi.put(wTrans, key, value);
wTrans.commit();
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"id", new W::Uint64(id));
broadcast(vc, W::Address({u"addElement"}));
emit countChange(elements.size());
return id;
}
void ResourceCache::removeResource(uint64_t id)
{
if (!opened) {
throw ClosedDB("removeResource");
}
lmdb::txn transaction = lmdb::txn::begin(environment);
lmdb::val key((uint8_t*) &id, 8);
dbi.del(transaction, key);
transaction.commit();
elements.erase(id);
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"id", new W::Uint64(id));
broadcast(vc, W::Address({u"removeElement"}));
emit countChange(elements.size());
//TODO not sure, may be it's better to also destroy resource model?
}
void ResourceCache::clear()
{
if (!opened) {
throw new ClosedDB("clear");
}
lmdb::txn transaction = lmdb::txn::begin(environment);
dbi.drop(transaction);
transaction.commit();
elements.clear();
lastIndex = 0;
W::Vocabulary* vc = new W::Vocabulary();
broadcast(vc, W::Address({u"clear"}));
emit countChange(elements.size());
}
void ResourceCache::h_get(const W::Event& ev)
{
W::Vector* order = new W::Vector();
std::set<uint64_t>::const_iterator itr = elements.begin();
std::set<uint64_t>::const_iterator end = elements.end();
for (; itr != end; ++itr) {
order->push(W::Uint64(*itr));
}
W::Vocabulary* rvc = new W::Vocabulary;
rvc->insert(u"data", order);
response(rvc, W::Address({u"get"}), ev);
}
M::Model::ModelType ResourceCache::getType() const
{
return type;
}
void ResourceCache::set(W::Object* value)
{
set(*value);
}
void ResourceCache::set(const W::Object& value)
{
throw 14; //what do you expect here? not implemented, and not sure it ever would be
}
void ResourceCache::h_subscribe(const W::Event& ev)
{
M::Model::h_subscribe(ev);
h_get(ev);
}
W::String * ResourceCache::getElement(uint64_t id) const
{
lmdb::txn rtxn = lmdb::txn::begin(environment, nullptr, MDB_RDONLY);
lmdb::val key((uint8_t*) &id, 8);
lmdb::val value;
if (lmdb::dbi_get(rtxn, dbi.handle(), key, value)) {
W::ByteArray ba(value.size());
ba.fill(value.data(), value.size());
W::String* wVal = static_cast<W::String*>(W::Object::fromByteArray(ba));
rtxn.abort();
return wVal;
} else {
rtxn.abort();
throw 3;
}
}
void ResourceCache::h_subscribeMember(const W::Event& ev)
{
const W::Address& addr = ev.getDestination();
W::Address lastHops = addr << address.length();
if (lastHops.length() == 2 && (lastHops.ends(W::Address{u"subscribe"})
|| lastHops.ends(W::Address{u"get"})
|| lastHops.ends(W::Address{u"getAdditional"}))
) {
W::String* record;
try {
record = getElement(lastHops.front().toUint64());
M::File* modelRecord = M::File::create(readFile(*record), address + lastHops >> 1);
delete record;
addModel(modelRecord);
passToHandler(ev);
} catch (int err) {
if (err == 3) {
emit serviceMessage(QString("An attempt to create and subscribe record model in resourcecache, but it is not found. Event: ") + ev.toString().c_str());
} else if (err == 10) {
serviceMessage(QString("Can't open file ") + record->toString().c_str());
delete record;
} else {
throw err;
}
} catch (const std::invalid_argument& err) {
emit serviceMessage(QString("Strange event in custom handler of resourcecache ") + ev.toString().c_str());
}
} else {
emit serviceMessage(QString("Strange event in custom handler of resourcecache ") + ev.toString().c_str());
}
}
W::Blob * ResourceCache::readFile(const W::String& path) const
{
std::ifstream file (path.toString(), std::ios::in|std::ios::binary|std::ios::ate);
if (file.is_open()) {
char * memblock;
uint32_t size;
size = file.tellg();
file.seekg(0, std::ios::beg);
memblock = new char[size];
file.read(memblock, size);
file.close();
return new W::Blob(size, memblock);
} else {
throw 10; //TODO
}
}
std::set<uint64_t> ResourceCache::getAllIdentificators() const
{
if (!opened) {
throw new ClosedDB("getAllIdentificators");
}
return elements;
}
W::String ResourceCache::getPath(uint64_t id) const
{
return *(getElement(id));
}
bool ResourceCache::has(uint64_t id) const
{
if (!opened) {
throw new ClosedDB("has");
}
return elements.find(id) != elements.end();
}

View file

@ -0,0 +1,84 @@
#ifndef RESOURCECACHE_H
#define RESOURCECACHE_H
#include <set>
#include <map>
#include "lmdb++.h"
#include <wModel/model.h>
#include <wModel/file/file.h>
#include <wType/address.h>
#include <wType/string.h>
#include <wType/bytearray.h>
#include <wType/uint64.h>
#include <wType/blob.h>
#include <utils/exception.h>
class ResourceCache : public M::Model
{
Q_OBJECT
public:
ResourceCache(const W::String& dbName, QObject* parent = 0);
~ResourceCache();
void open();
uint64_t addResource(const W::String& path);
void removeResource(uint64_t id);
void clear();
bool has(uint64_t id) const;
W::String getPath(uint64_t id) const;
std::set<uint64_t> getAllIdentificators() const;
W::Handler* subscribeMember;
handler(subscribeMember);
M::Model::ModelType getType() const override;
static const M::Model::ModelType type = resourceCache;
void set(const W::Object & value) override;
void set(W::Object * value) override;
signals:
void countChange(uint64_t count);
protected:
void h_subscribe(const W::Event & ev) override;
handler(get);
W::String* getElement(uint64_t id) const;
public:
const W::String name;
private:
bool opened;
lmdb::env environment;
lmdb::dbi dbi;
std::set<uint64_t> elements;
uint64_t lastIndex;
void checkDirAndOpenEnvironment();
W::Blob* readFile(const W::String& path) const;
class ClosedDB:
public Utils::Exception
{
public:
ClosedDB(const std::string& p_op):Exception(), operation(p_op){}
std::string getMessage() const {
std::string str = "An attempt to perform method ResourceCache::";
str += operation;
str += " but the database is not open";
return str;
}
private:
std::string operation;
};
};
#endif // RESOURCECACHE_H

View file

@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 2.8.12)
project(wDispatcher)
find_package(Qt5Core REQUIRED)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(HEADERS
dispatcher.h
handler.h
defaulthandler.h
logger.h
parentreporter.h
)
set(SOURCES
dispatcher.cpp
handler.cpp
defaulthandler.cpp
logger.cpp
parentreporter.cpp
)
add_library(wDispatcher ${HEADERS} ${SOURCES})
target_link_libraries(wDispatcher Qt5::Core)

View file

@ -0,0 +1,11 @@
#include "defaulthandler.h"
W::DefaultHandler::DefaultHandler()
{
}
W::DefaultHandler::~DefaultHandler()
{
}

View file

@ -0,0 +1,18 @@
#ifndef DEFAULTHANDLER_H
#define DEFAULTHANDLER_H
#include <wType/event.h>
namespace W
{
class DefaultHandler
{
public:
DefaultHandler();
virtual ~DefaultHandler();
virtual bool call(const W::Event& ev) const = 0;
};
}
#endif // DEFAULTHANDLER_H

View file

@ -0,0 +1,84 @@
#include "dispatcher.h"
W::Dispatcher::Dispatcher()
{}
W::Dispatcher::~Dispatcher()
{}
void W::Dispatcher::pass(const W::Event& ev) const
{
n_map::const_iterator itr;
itr = nodes.find(ev.getDestination());
if (itr != nodes.end())
{
W::Order<W::Handler*>::const_iterator beg = itr->second.begin();
W::Order<W::Handler*>::const_iterator end = itr->second.end();
std::list<W::Handler*> list(beg, end);
std::list<W::Handler*>::const_iterator itr = list.begin();
std::list<W::Handler*>::const_iterator tEnd = list.end();
for (; itr != tEnd; ++itr) {
(*itr)->pass(ev);
}
}
else
{
d_order::const_iterator itr = defaultHandlers.begin();
d_order::const_iterator end = defaultHandlers.end();
for (; itr != end; ++itr)
{
if ((*itr)->call(ev)){
break;
}
}
}
}
void W::Dispatcher::registerHandler(W::Handler* dp)
{
n_map::iterator itr = nodes.find(dp->getAddress());
if (itr == nodes.end()) {
W::Order<W::Handler*> ord;
itr = nodes.insert(std::make_pair(dp->getAddress(), ord)).first;
}
itr->second.push_back(dp);
}
void W::Dispatcher::unregisterHandler(W::Handler* dp)
{
n_map::iterator itr = nodes.find(dp->getAddress());
if (itr != nodes.end())
{
W::Order<W::Handler*>::const_iterator o_itr = itr->second.find(dp);
if (o_itr != itr->second.end()) {
itr->second.erase(dp);
if (itr->second.size() == 0) {
nodes.erase(itr);
}
}
else
{
throw 5;//TODO exception;
}
}
else
{
throw 5;//TODO exception;
}
}
void W::Dispatcher::registerDefaultHandler(W::DefaultHandler* dh)
{
defaultHandlers.push_back(dh);
}
void W::Dispatcher::unregisterDefaultHandler(W::DefaultHandler* dh)
{
defaultHandlers.erase(dh);
}

View file

@ -0,0 +1,48 @@
#ifndef DISPATCHER_H
#define DISPATCHER_H
#include <map>
#include <list>
#include <wType/string.h>
#include <wType/address.h>
#include <wType/event.h>
#include <QtCore/QObject>
#include "handler.h"
#include "defaulthandler.h"
#include <wContainer/order.h>
namespace W
{
class Dispatcher:
public QObject
{
Q_OBJECT
public:
Dispatcher();
~Dispatcher();
void registerHandler(W::Handler* dp);
void unregisterHandler(W::Handler* dp);
void registerDefaultHandler(W::DefaultHandler* dh);
void unregisterDefaultHandler(W::DefaultHandler* dh);
public slots:
void pass(const W::Event& ev) const;
protected:
typedef std::map<W::Address, W::Order<W::Handler*>> n_map;
typedef W::Order<W::DefaultHandler*> d_order;
n_map nodes;
d_order defaultHandlers;
};
}
#endif // DISPATCHER_H

View file

@ -0,0 +1,17 @@
#include "handler.h"
W::Handler::Handler(const W::Address& p_rel_addr):
address(p_rel_addr)
{
}
W::Handler::~Handler()
{
}
const W::Address& W::Handler::getAddress() const
{
return address;
}

56
lib/wDispatcher/handler.h Normal file
View file

@ -0,0 +1,56 @@
#ifndef HANDLER_H
#define HANDLER_H
#include "wType/address.h"
#include "wType/event.h"
namespace W
{
template<typename InstanceType, typename MethodType>
class ImplHandle;
class Handler
{
public:
Handler(const Address& p_rel_addr);
virtual ~Handler();
template<typename InstanceType, typename MethodType>
static Handler* create(const Address& addr, InstanceType* inst, MethodType mth)
{
return new ImplHandle<InstanceType, MethodType>(addr, inst, mth);
}
const W::Address& getAddress() const;
virtual void pass(const W::Event& ev) const = 0;
private:
W::Address address;
};
template<typename InstanceType, typename MethodType>
class ImplHandle: public Handler
{
public:
ImplHandle(const Address& p_rel_addr, InstanceType *p_inst, MethodType p_mth):
Handler(p_rel_addr),
inst(p_inst),
mth(p_mth)
{}
~ImplHandle() {}
void pass(const W::Event& ev) const
{
( ( *inst ).*mth )(ev);
}
private:
InstanceType* inst;
MethodType mth;
};
}
#endif // HANDLER_H

View file

@ -0,0 +1,24 @@
#include "logger.h"
#include "iostream"
W::Logger::Logger():
DefaultHandler()
{
}
W::Logger::~Logger()
{
}
bool W::Logger::call(const W::Event& ev) const
{
std::cout << "Event went to default handler.\n";
std::cout << "Destination: " << ev.getDestination().toString() << "\n";
std::cout << "Data: " << ev.getData().toString();
std::cout << std::endl;
return false;
}

21
lib/wDispatcher/logger.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef LOGGER_H
#define LOGGER_H
#include "defaulthandler.h"
#include <wType/event.h>
namespace W
{
class Logger:
public DefaultHandler
{
public:
Logger();
~Logger();
bool call(const W::Event& ev) const;
};
}
#endif // LOGGER_H

View file

@ -0,0 +1,44 @@
#include "parentreporter.h"
W::ParentReporter::ParentReporter():
W::DefaultHandler(),
handlers()
{
}
W::ParentReporter::~ParentReporter()
{
}
bool W::ParentReporter::call(const W::Event& ev) const
{
const W::Address& addr = ev.getDestination();
std::map<int, W::Handler*> result;
Hmap::const_iterator itr = handlers.begin();
Hmap::const_iterator end = handlers.end();
for (; itr != end; ++itr) { //need to find the closest parent to the event destination
if (addr.begins(itr->first)) { //the closest parent has the longest address of those whose destinatiion begins with
result.insert(std::make_pair(itr->first.size(), itr->second));
}
}
if (result.size() > 0) {
std::map<int, W::Handler*>::const_iterator itr = result.end();
--itr;
itr->second->pass(ev); //need to report only to the closest parent
return true;
} else {
return false;
}
}
void W::ParentReporter::registerParent(const W::Address& address, W::Handler* handler)
{
Hmap::const_iterator itr = handlers.find(address);
if (itr != handlers.end()) {
throw 1;
} else {
handlers.insert(std::make_pair(address, handler));
}
}

View file

@ -0,0 +1,25 @@
#ifndef PARENTREPORTER_H
#define PARENTREPORTER_H
#include "defaulthandler.h"
#include "handler.h"
#include <map>
namespace W {
class ParentReporter : public DefaultHandler
{
public:
ParentReporter();
~ParentReporter();
bool call(const W::Event& ev) const;
void registerParent(const W::Address& address, W::Handler* handler);
private:
typedef std::map<W::Address, W::Handler*> Hmap;
Hmap handlers;
};
}
#endif // PARENTREPORTER_H

36
lib/wModel/CMakeLists.txt Normal file
View file

@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 2.8.12)
project(model)
find_package(Qt5Core REQUIRED)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(HEADERS
model.h
modelstring.h
list.h
vocabulary.h
attributes.h
icatalogue.h
catalogue.h
file/file.h
)
set(SOURCES
model.cpp
modelstring.cpp
list.cpp
vocabulary.cpp
attributes.cpp
icatalogue.cpp
catalogue.cpp
file/file.cpp
)
add_library(wModel STATIC ${HEADERS} ${SOURCES})
target_link_libraries(wModel Qt5::Core)
target_link_libraries(wModel wSocket)
target_link_libraries(wModel wDispatcher)
target_link_libraries(wModel wType)

60
lib/wModel/attributes.cpp Normal file
View file

@ -0,0 +1,60 @@
#include "attributes.h"
M::Attributes::Attributes(const W::Address p_address, QObject* parent):
M::Vocabulary(p_address, parent),
attributes(new Map())
{
}
M::Attributes::~Attributes()
{
delete attributes;
}
M::Model::ModelType M::Attributes::getType() const
{
return type;
}
void M::Attributes::addAttribute(const W::String& key, M::Model* model)
{
Map::const_iterator itr = attributes->find(key);
if (itr != attributes->end()) {
throw 1;
}
attributes->insert(std::make_pair(key, model));
addModel(model);
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"name", key);
vc->insert(u"address", model->getAddress());
vc->insert(u"type", W::Uint64(model->getType()));
insert(key, vc);
}
void M::Attributes::removeAttribute(const W::String& key)
{
Map::const_iterator itr = attributes->find(key);
if (itr == attributes->end()) {
throw 1;
}
M::Model* model = itr->second;
attributes->erase(itr);
erase(key);
removeModel(model);
delete model;
}
void M::Attributes::setAttribute(const W::String& key, const W::Object& value)
{
Map::const_iterator itr = attributes->find(key);
itr->second->set(value);
}
void M::Attributes::setAttribute(const W::String& key, W::Object* value)
{
Map::const_iterator itr = attributes->find(key);
itr->second->set(value);
}

32
lib/wModel/attributes.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef M_ATTRIBUTES_H
#define M_ATTRIBUTES_H
#include "vocabulary.h"
#include <wType/string.h>
#include <map>
namespace M {
class Attributes : public M::Vocabulary
{
public:
Attributes(const W::Address p_address, QObject* parent = 0);
~Attributes();
void addAttribute(const W::String& key, M::Model* model);
void removeAttribute(const W::String& key);
void setAttribute(const W::String& key, const W::Object& value);
void setAttribute(const W::String& key, W::Object* value);
M::Model::ModelType getType() const override;
static const M::Model::ModelType type = attributes;
private:
typedef std::map<W::String, M::Model*> Map;
Map* attributes;
};
}
#endif // ATTRIBUTES_H

66
lib/wModel/catalogue.cpp Normal file
View file

@ -0,0 +1,66 @@
#include "catalogue.h"
M::Catalogue::Catalogue(const W::Address p_address, QObject* parent):
ICatalogue(p_address, parent),
data()
{
}
M::Catalogue::~Catalogue()
{
}
uint64_t M::Catalogue::addElement(const W::Vocabulary& record)
{
uint64_t id = M::ICatalogue::addElement(record);
data.insert(std::make_pair(id, static_cast<W::Vocabulary*>(record.copy())));
return id;
}
void M::Catalogue::removeElement(uint64_t id)
{
M::ICatalogue::removeElement(id);
Data::const_iterator itr = data.find(id);
delete itr->second;
data.erase(itr);
}
void M::Catalogue::clear()
{
M::ICatalogue::clear();
data.clear();
}
W::Vocabulary * M::Catalogue::getElement(uint64_t id)
{
return static_cast<W::Vocabulary*>(data.at(id)->copy());
}
std::set<uint64_t> M::Catalogue::getAll() const
{
std::set<uint64_t> res;
Data::const_iterator itr = data.begin();
Data::const_iterator end = data.end();
for (; itr != end; ++itr) {
res.insert(itr->first);
}
return res;
}
void M::Catalogue::modifyElement(uint64_t id, const W::Vocabulary& newValue)
{
Data::iterator itr = data.find(id);
delete itr->second;
itr->second = static_cast<W::Vocabulary*>(newValue.copy());
}
uint64_t M::Catalogue::size() const
{
return data.size();
}

29
lib/wModel/catalogue.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef CATALOGUE_H
#define CATALOGUE_H
#include "icatalogue.h"
namespace M {
class Catalogue : public ICatalogue {
public:
Catalogue(const W::Address p_address, QObject* parent = 0);
~Catalogue();
uint64_t addElement(const W::Vocabulary & record) override;
void removeElement(uint64_t id) override;
void clear() override;
W::Vocabulary* getElement(uint64_t id) override;
void modifyElement(uint64_t id, const W::Vocabulary & newValue) override;
uint64_t size() const override;
protected:
std::set<uint64_t> getAll() const override;
private:
typedef std::map<uint64_t, W::Vocabulary*> Data;
Data data;
};
}
#endif // CATALOGUE_H

86
lib/wModel/file/file.cpp Normal file
View file

@ -0,0 +1,86 @@
#include "file.h"
#include <iostream>
QMimeDatabase M::File::mimeDB;
M::File::File(W::Blob* p_file, const W::Address& addr, QObject* parent):
M::Model(addr, parent),
additional(),
file(p_file)
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::File::_h_get);
W::Handler* getAdditional = W::Handler::create(address + W::Address({u"getAdditional"}), this, &M::File::_h_getAdditional);
addHandler(get);
addHandler(getAdditional);
}
M::File::~File()
{
delete file;
}
M::Model::ModelType M::File::getType() const
{
return type;
}
void M::File::initAdditional(const W::String& p_mime)
{
additional.clear();
additional.insert(u"size", new W::Uint64(file->size()));
additional.insert(u"mimeType", p_mime);
}
void M::File::set(const W::Object& value)
{
set(value.copy());
}
void M::File::set(W::Object* value)
{
delete file;
file = static_cast<W::Blob*>(value);
QMimeType mt = mimeDB.mimeTypeForData(file->byteArray());
initAdditional(W::String(mt.name().toStdString()));
W::Vocabulary* vc = static_cast<W::Vocabulary*>(additional.copy());
broadcast(vc, W::Address({u"getAdditional"}));
}
void M::File::h_getAdditional(const W::Event& ev)
{
W::Vocabulary* vc = static_cast<W::Vocabulary*>(additional.copy());
response(vc, W::Address({u"getAdditional"}), ev);
}
void M::File::h_subscribe(const W::Event& ev)
{
M::Model::h_subscribe(ev);
h_getAdditional(ev);
}
void M::File::h_get(const W::Event& ev)
{
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"additional", additional.copy());
vc->insert(u"data", file->copy());
response(vc, W::Address({u"get"}), ev);
}
M::File * M::File::create(W::Blob* blob, const W::Address& addr, QObject* parent)
{
M::File* out;
QMimeType mt = mimeDB.mimeTypeForData(blob->byteArray());
out = new File(blob, addr, parent);
out->initAdditional(W::String(mt.name().toStdString()));
return out;
}

44
lib/wModel/file/file.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef FILE_H
#define FILE_H
/**
* @todo write docs
*/
#include <wModel/model.h>
#include <wType/blob.h>
#include <QtCore/QMimeDatabase>
namespace M {
class File: public Model {
protected:
File(W::Blob* p_file, const W::Address& addr, QObject* parent = 0);
public:
~File();
void set(const W::Object & value) override;
void set(W::Object * value) override;
M::Model::ModelType getType() const override;
static const M::Model::ModelType type = file;
static File* create(W::Blob* blob, const W::Address& addr, QObject* parent = 0);
protected:
virtual void initAdditional(const W::String& p_mime);
void h_subscribe(const W::Event & ev) override;
handler(get);
handler(getAdditional);
protected:
W::Vocabulary additional;
W::Blob* file;
static QMimeDatabase mimeDB;
};
}
#endif // FILE_H

469
lib/wModel/icatalogue.cpp Normal file
View file

@ -0,0 +1,469 @@
#include "icatalogue.h"
const std::set<uint64_t> M::ICatalogue::empty = std::set<uint64_t>();
M::ICatalogue::ICatalogue(const W::Address p_address, QObject* parent):
M::Model(p_address, parent),
subscribeMember(W::Handler::create(W::Address({}), this, &M::ICatalogue::_h_subscribeMember)),
indexes(),
lastIndex(0),
activeChildren()
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::ICatalogue::_h_get);
W::Handler* add = W::Handler::create(address + W::Address({u"add"}), this, &M::ICatalogue::_h_add);
W::Handler* update = W::Handler::create(address + W::Address({u"update"}), this, &M::ICatalogue::_h_update);
addHandler(get);
addHandler(add);
addHandler(update);
}
M::ICatalogue::~ICatalogue()
{
delete subscribeMember;
IndexMap::const_iterator itr = indexes.begin();
IndexMap::const_iterator end = indexes.end();
for (; itr != end; ++itr) {
delete itr->second;
}
}
void M::ICatalogue::clear()
{
lastIndex = 0;
IndexMap::const_iterator itr = indexes.begin();
IndexMap::const_iterator end = indexes.end();
for (; itr != end; ++itr) {
itr->second->clear();
}
if (registered) {
broadcast(new W::Vocabulary(), W::Address{u"clear"});
}
emit countChange(0);
}
void M::ICatalogue::addIndex(const W::String& fieldName, W::Object::objectType fieldType)
{
IndexMap::const_iterator itr = indexes.find(fieldName);
if (itr != indexes.end()) {
throw 2;
}
switch (fieldType) {
case W::Object::uint64:
indexes.insert(std::make_pair(fieldName, new Index<W::Uint64>()));
break;
case W::Object::string:
indexes.insert(std::make_pair(fieldName, new Index<W::String>()));
break;
default:
throw 3;
}
}
const std::set<uint64_t> & M::ICatalogue::find(const W::String& indexName, const W::Object& value) const
{
IndexMap::const_iterator itr = indexes.find(indexName);
if (itr == indexes.end()) {
throw 4;
}
return itr->second->find(value);
}
std::set<uint64_t> M::ICatalogue::find(const W::Vocabulary& value) const
{
W::Vector keys = value.keys();
int size = keys.length();
std::set<uint64_t> result;
bool first = true;
for (int i = 0; i < size; ++i) {
const W::String& key = static_cast<const W::String&>(keys.at(i));
IndexMap::const_iterator itr = indexes.find(key);
if (itr == indexes.end()) {
throw 4;
}
if (first) {
result = itr->second->find(value.at(key));
first = false;
} else {
std::set<uint64_t> copy = result;
result.clear();
const std::set<uint64_t>& current = itr->second->find(value.at(key));
std::set_intersection(copy.begin(), copy.end(), current.begin(), current.end(), std::inserter(result, result.end()));
}
if (result.empty()) {
break;
}
}
return result;
}
M::Model::ModelType M::ICatalogue::getType() const
{
return type;
}
uint64_t M::ICatalogue::addElement(const W::Vocabulary& record)
{
IndexMap::const_iterator itr = indexes.begin();
IndexMap::const_iterator end = indexes.end();
++lastIndex;
for (; itr != end; ++itr) {
itr->second->add(record.at(itr->first), lastIndex);
}
Map::const_iterator sItr = subscribers->begin();
Map::const_iterator sEnd = subscribers->end();
for (; sItr != sEnd; ++sItr) {
SMap::const_iterator oItr = sItr->second.begin();
SMap::const_iterator oEnd = sItr->second.end();
for (; oItr != oEnd; ++oItr) {
const W::Vocabulary& params = oItr->second;
if (params.has(u"filter")) {
processAddElement(lastIndex, record, oItr, sItr->first);
} else {
uint64_t bid = getInsertingNeighbour(oItr->second, record, lastIndex, getAll());
W::Address dest = oItr->first + W::Address({u"addElement"});
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"id", new W::Uint64(lastIndex));
if (bid != 0) {
vc->insert(u"before", new W::Uint64(bid));
}
send(vc, dest, sItr->first);
}
}
}
emit countChange(size() + 1);
return lastIndex;
}
void M::ICatalogue::removeElement(uint64_t id)
{
IndexMap::const_iterator itr = indexes.begin();
IndexMap::const_iterator end = indexes.end();
W::Vocabulary* value = getElement(id);
Map::const_iterator sItr = subscribers->begin();
Map::const_iterator sEnd = subscribers->end();
for (; sItr != sEnd; ++sItr) {
SMap::const_iterator oItr = sItr->second.begin();
SMap::const_iterator oEnd = sItr->second.end();
for (; oItr != oEnd; ++oItr) {
const W::Vocabulary& params = oItr->second;
if (params.has(u"filter")) {
const W::Vocabulary& filter = static_cast<const W::Vocabulary&>(params.at(u"filter"));
std::set<uint64_t> set = find(filter);
std::set<uint64_t>::const_iterator idItr = set.find(id);
if (idItr != set.end()) {
W::Address dest = oItr->first + W::Address({u"removeElement"});
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"id", new W::Uint64(id));
send(vc, dest, sItr->first);
}
} else {
W::Address dest = oItr->first + W::Address({u"removeElement"});
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"id", new W::Uint64(id));
send(vc, dest, sItr->first);
}
}
}
for (; itr != end; ++itr) {
itr->second->remove(value->at(itr->first), id);
}
std::map<uint64_t, M::Vocabulary*>::const_iterator aItr = activeChildren.find(id);
if (aItr != activeChildren.end()) {
removeModel(aItr->second);
aItr->second->deleteLater();
activeChildren.erase(aItr);
}
emit countChange(size() - 1);
delete value;
}
void M::ICatalogue::h_get(const W::Event& ev)
{
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Vocabulary& params = static_cast<const W::Vocabulary&>(vc.at(u"params"));
std::set<uint64_t> set;
if (params.has(u"filter")) {
const W::Vocabulary& filter = static_cast<const W::Vocabulary&>(params.at(u"filter"));
set = find(filter);
} else {
set = getAll();
}
W::Vocabulary* rvc = new W::Vocabulary;
if (params.has(u"sorting")) {
const W::Vocabulary& sorting = static_cast<const W::Vocabulary&>(params.at(u"sorting"));
const W::String& field = static_cast<const W::String&>(sorting.at(u"field"));
bool ascending = static_cast<const W::Boolean&>(sorting.at(u"ascending"));
rvc->insert(u"data", indexes.at(field)->sort(set, ascending));
} else {
W::Vector* order = new W::Vector();
std::set<uint64_t>::const_iterator itr = set.begin();
std::set<uint64_t>::const_iterator end = set.end();
for (; itr != end; ++itr) {
order->push(W::Uint64(*itr));
}
rvc->insert(u"data", order);
}
response(rvc, W::Address({u"get"}), ev);
}
void M::ICatalogue::h_subscribe(const W::Event& ev)
{
M::Model::h_subscribe(ev);
h_get(ev);
}
void M::ICatalogue::set(const W::Object& value)
{
throw 14; //what do you expect here? not implemented, and not sure it ever would be
}
void M::ICatalogue::set(W::Object* value)
{
set(*value);
}
void M::ICatalogue::h_add(const W::Event& ev)
{
addElement(static_cast<const W::Vocabulary&>(ev.getData()));
}
void M::ICatalogue::h_update(const W::Event& ev)
{
const W::Vocabulary& data = static_cast<const W::Vocabulary&>(ev.getData());
const W::Uint64& id = static_cast<const W::Uint64&>(data.at(u"id"));
const W::Vocabulary& newValue = static_cast<const W::Vocabulary&>(data.at(u"value"));
W::Vector affectedKeys = newValue.keys();
W::Vocabulary* oldValue = getElement(id);
W::Vocabulary* modifiedValue = W::Vocabulary::extend(*oldValue, newValue);
modifyElement(id, *modifiedValue);
std::map<uint64_t, M::Vocabulary*>::const_iterator itr = activeChildren.find(id);
if (itr != activeChildren.end()) {
itr->second->set(modifiedValue);
}
Map::const_iterator sItr = subscribers->begin();
Map::const_iterator sEnd = subscribers->end();
for (; sItr != sEnd; ++sItr) {
SMap::const_iterator oItr = sItr->second.begin();
SMap::const_iterator oEnd = sItr->second.end();
for (; oItr != oEnd; ++oItr) {
const W::Vocabulary& params = oItr->second;
if (params.has(u"filter")) {
const W::Vocabulary& filter = static_cast<const W::Vocabulary&>(params.at(u"filter"));
bool matched = match(*oldValue, filter);
bool matching = match(*modifiedValue, filter);
if (matched && !matching) {
W::Address dest = oItr->first + W::Address({u"removeElement"});
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"id", new W::Uint64(id));
send(vc, dest, sItr->first);
} else if (!matched && matching) {
processAddElement(id, *modifiedValue, oItr, sItr->first);
} else if (matched && matching) {
std::set<uint64_t> set = find(filter);
uint64_t cbid = getInsertingNeighbour(params, *oldValue, id, set);
uint64_t bid = getInsertingNeighbour(params, *modifiedValue, id, set);
if (cbid != bid) {
W::Address dest = oItr->first + W::Address({u"moveElement"});
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"id", new W::Uint64(id));
if (id != 0) {
vc->insert(u"before", new W::Uint64(bid));
}
send(vc, dest, sItr->first);
}
}
} else {
if (params.has(u"sorting")) {
std::set<uint64_t> set = getAll();
uint64_t cbid = getInsertingNeighbour(params, *oldValue, id, set);
uint64_t bid = getInsertingNeighbour(params, *modifiedValue, id, set);
if (cbid != bid) {
W::Address dest = oItr->first + W::Address({u"moveElement"});
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"id", new W::Uint64(id));
if (id != 0) {
vc->insert(u"before", new W::Uint64(bid));
}
send(vc, dest, sItr->first);
}
}
}
}
}
}
void M::ICatalogue::h_subscribeMember(const W::Event& ev)
{
const W::Address& addr = ev.getDestination();
W::Address lastHops = addr << address.length();
if (lastHops.length() == 2 && (lastHops.ends(W::Address{u"subscribe"}) || lastHops.ends(W::Address{u"get"}))) {
W::Vocabulary* record;
try {
uint64_t id = lastHops.front().toUint64();
record = getElement(id);
if (lastHops.ends(W::Address{u"subscribe"})) {
M::Vocabulary* modelRecord = new M::Vocabulary(record, address + lastHops >> 1);
addModel(modelRecord);
activeChildren.insert(std::make_pair(id, modelRecord));
modelRecord->_h_subscribe(ev);
} else {
W::Vocabulary* vc = new W::Vocabulary;
vc->insert(u"data", record);
fakeResponse(vc, W::Address({u"get"}), addr >> 1, ev);
}
} catch(int err) {
if (err == 3) {
emit serviceMessage(QString("An attempt to create and subscribe record model in catalogue, but it is not found. Event: ") + ev.toString().c_str());
} else {
throw err;
}
} catch (const std::invalid_argument& err) {
emit serviceMessage(QString("Strange event in custom handler of catalogue ") + ev.toString().c_str());
}
} else {
emit serviceMessage(QString("Strange event in custom handler of catalogue ") + ev.toString().c_str());
}
}
bool M::ICatalogue::match(const W::Vocabulary& value, const W::Vocabulary& filter)
{
bool m = true;
W::Vector keys = filter.keys();
for (int i = 0; i < keys.length(); ++i) {
const W::String& key = static_cast<const W::String&>(keys.at(i));
if (filter.at(key) != value.at(key)) {
m = false;
break;
};
}
return m;
}
void M::ICatalogue::processAddElement(uint64_t id, const W::Vocabulary& value, SMap::const_iterator subscriberIterator, uint64_t socketId)
{
const W::Address& addr = subscriberIterator->first;
const W::Vocabulary& params = subscriberIterator->second;
const W::Vocabulary& filter = static_cast<const W::Vocabulary&>(params.at(u"filter"));
std::set<uint64_t> set = find(filter);
std::set<uint64_t>::const_iterator idItr = set.find(id);
if (idItr != set.end()) { //to make sure if subscriber cares
uint64_t bid = getInsertingNeighbour(params, value, id, set);
W::Address dest = addr + W::Address({u"addElement"});
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"id", new W::Uint64(id));
if (id != 0) {
vc->insert(u"before", new W::Uint64(bid));
}
send(vc, dest, socketId);
}
}
uint64_t M::ICatalogue::getInsertingNeighbour(const W::Vocabulary& params, const W::Vocabulary& record, uint64_t id, const std::set<uint64_t>& allowed) const
{
uint64_t bid;
if (params.has(u"sorting")) {
if (allowed.empty()) {
bid = 0;
} else {
const W::Vocabulary& sorting = static_cast<const W::Vocabulary&>(params.at(u"sorting"));
const W::String& field = static_cast<const W::String&>(sorting.at(u"field"));
bool ascending = static_cast<const W::Boolean&>(sorting.at(u"ascending"));
uint64_t foundId = id;
do {
if (ascending) {
foundId = indexes.at(field)->getNext(foundId, record.at(field));
} else {
foundId = indexes.at(field)->getPrev(foundId, record.at(field));
}
} while (allowed.find(foundId) == allowed.end() || foundId != 0); //to make sure, that id folowing the inserting also present in the
bid = foundId; //subscribers filter result
}
} else {
std::set<uint64_t>::const_iterator idItr = allowed.find(id);
if (idItr == allowed.end()) {
bid = 0;
} else {
++idItr;
if (idItr == allowed.end()) {
bid = 0;
} else {
bid = *idItr;
}
}
}
return bid;
}
M::ICatalogue::AbstractIndex::TypeError::TypeError(const std::string& name, const std::string& method, W::Object::objectType myType, W::Object::objectType valueType):
Utils::Exception(),
name(name),
method(method),
myType(myType),
valueType(valueType)
{}
std::string M::ICatalogue::AbstractIndex::TypeError::getMessage() const
{
std::string msg = "An attempt to call Catalogue Index of ";
msg += name;
msg += " method \"";
msg += method;
msg += "\" with value type of ";
msg += W::Object::getTypeName(valueType);
msg += " but this index values supposed to have type ";
msg += W::Object::getTypeName(myType);
return msg;
}

316
lib/wModel/icatalogue.h Normal file
View file

@ -0,0 +1,316 @@
#ifndef ICATALOGUE_H
#define ICATALOGUE_H
#include "model.h"
#include <set>
#include <map>
#include <wModel/vocabulary.h>
#include <utils/exception.h>
namespace M {
class ICatalogue : public M::Model
{
Q_OBJECT
protected:
class AbstractIndex;
public:
ICatalogue(const W::Address p_address, QObject* parent = 0);
~ICatalogue();
virtual uint64_t addElement(const W::Vocabulary& record);
virtual void removeElement(uint64_t id);
virtual W::Vocabulary* getElement(uint64_t id) = 0;
virtual void modifyElement(uint64_t id, const W::Vocabulary& newValue) = 0;
virtual uint64_t size() const = 0;
virtual void clear();
virtual void addIndex(const W::String& fieldName, W::Object::objectType fieldType);
const std::set<uint64_t>& find(const W::String& indexName, const W::Object& value) const;
std::set<uint64_t> find(const W::Vocabulary& value) const;
M::Model::ModelType getType() const override;
static const M::Model::ModelType type = catalogue;
void set(const W::Object & value) override;
void set(W::Object * value) override;
W::Handler* subscribeMember;
handler(subscribeMember);
static bool match(const W::Vocabulary& value, const W::Vocabulary& filter);
static const std::set<uint64_t> empty;
signals:
void countChange(uint64_t count);
protected:
virtual std::set<uint64_t> getAll() const = 0;
void h_subscribe(const W::Event & ev) override;
handler(get);
handler(add);
handler(update);
typedef std::map<W::String, AbstractIndex*> IndexMap;
IndexMap indexes;
private:
uint64_t lastIndex;
std::map<uint64_t, M::Vocabulary*> activeChildren;
void processAddElement(uint64_t id, const W::Vocabulary& value, SMap::const_iterator subscriberIterator, uint64_t socketId);
uint64_t getInsertingNeighbour(const W::Vocabulary& params, const W::Vocabulary& record, uint64_t id, const std::set<uint64_t>& allowed = empty) const;
protected:
class AbstractIndex {
public:
AbstractIndex(W::Object::objectType vt): valueType(vt) {}
virtual ~AbstractIndex() {}
virtual const std::set<uint64_t>& find(const W::Object& value) const = 0;
virtual void add(const W::Object& value, uint64_t id) = 0;
virtual void remove(const W::Object & value, uint64_t id) = 0;
virtual void clear() = 0;
virtual W::Vector sort(const std::set<uint64_t>& set, bool ascending) = 0;
virtual uint64_t getNext(uint64_t id, const W::Object& value) = 0;
virtual uint64_t getPrev(uint64_t id, const W::Object& value) = 0;
W::Object::objectType valueType;
protected:
class TypeError : public Utils::Exception {
public:
TypeError(const std::string& name, const std::string& method, W::Object::objectType myType, W::Object::objectType valueType);
std::string getMessage() const;
private:
std::string name;
std::string method;
W::Object::objectType myType;
W::Object::objectType valueType;
};
};
template <class T>
class Index : public AbstractIndex {
public:
Index();
~Index();
const std::set<uint64_t>& find(const W::Object& value) const override;
void add(const W::Object & value, uint64_t id) override;
void remove(const W::Object & value, uint64_t id) override;
void clear() override;
W::Vector sort(const std::set<uint64_t> & set, bool ascending) override;
uint64_t getNext(uint64_t id, const W::Object& value) override;
uint64_t getPrev(uint64_t id, const W::Object& value) override;
private:
typedef std::map<T, std::set<uint64_t>> Map;
Map values;
};
};
template<class T>
ICatalogue::Index<T>::Index():
ICatalogue::AbstractIndex(T::type),
values()
{
}
template<class T>
ICatalogue::Index<T>::~Index()
{
}
template<class T>
const std::set<uint64_t> & ICatalogue::Index<T>::find(const W::Object& value) const
{
if (value.getType() != valueType) {
throw new TypeError("Unknown", "find", valueType, value.getType()); //todo replace that unknown stuff, find a way to provide index name
}
const T& val = static_cast<const T&>(value);
typename std::map<T, std::set<uint64_t>>::const_iterator itr = values.find(val);
if (itr == values.end()) {
return ICatalogue::empty;
} else {
return itr->second;
}
}
template<class T>
void ICatalogue::Index<T>::add(const W::Object& value, uint64_t id)
{
if (value.getType() != valueType) {
throw new TypeError("Unknown", "add", valueType, value.getType());
}
const T& val = static_cast<const T&>(value);
typename std::map<T, std::set<uint64_t>>::iterator itr = values.find(val);
if (itr == values.end()) {
itr = values.insert(std::make_pair(val, std::set<uint64_t>())).first;
}
itr->second.insert(id);
}
template<class T>
void ICatalogue::Index<T>::remove(const W::Object& value, uint64_t id)
{
if (value.getType() != valueType) {
throw new TypeError("Unknown", "remove", valueType, value.getType());
}
const T& val = static_cast<const T&>(value);
typename std::map<T, std::set<uint64_t>>::iterator itr = values.find(val);
if (itr != values.end()) {
std::set<uint64_t>& set = itr->second;
if (set.size() == 1) {
values.erase(itr);
} else {
std::set<uint64_t>::const_iterator hint = set.find(id);
set.erase(hint);
}
}
}
template<class T>
void ICatalogue::Index<T>::clear()
{
values.clear();
}
template<class T>
W::Vector ICatalogue::Index<T>::sort(const std::set<uint64_t> & set, bool ascending) //TODO this needs an optimization
{
W::Vector res;
std::set<uint64_t>::const_iterator sEnd = set.end();
uint64_t size = set.size();
if (size == 0) {
return res;
} else if (size == 1) {
res.push(W::Uint64(*(set.begin())));
return res;
}
if (ascending) {
typename std::map<T, std::set<uint64_t>>::const_iterator itr = values.begin();
typename std::map<T, std::set<uint64_t>>::const_iterator end = values.end();
for (; itr != end; ++itr) {
if (size == res.size()) {
break;
}
const std::set<uint64_t>& chunk = itr->second;
std::set<uint64_t>::const_iterator cItr = chunk.begin();
std::set<uint64_t>::const_iterator cEnd = chunk.end();
for (; cItr != cEnd; ++cItr) {
uint64_t id = *cItr;
if (set.find(id) != sEnd) {
res.push(W::Uint64(id));
}
}
}
} else {
typename std::map<T, std::set<uint64_t>>::reverse_iterator itr = values.rbegin();
typename std::map<T, std::set<uint64_t>>::reverse_iterator end = values.rend();
for (; itr != end; ++itr) {
if (size == res.size()) {
break;
}
const std::set<uint64_t>& chunk = itr->second;
std::set<uint64_t>::const_iterator cItr = chunk.begin();
std::set<uint64_t>::const_iterator cEnd = chunk.end();
for (; cItr != cEnd; ++cItr) {
uint64_t id = *cItr;
if (set.find(id) != sEnd) {
res.push(W::Uint64(id));
}
}
}
}
return res;
}
template<class T>
uint64_t ICatalogue::Index<T>::getNext(uint64_t id, const W::Object& value)
{
if (value.getType() != valueType) {
throw new TypeError("Unknown", "getNext", valueType, value.getType());
}
const T& val = static_cast<const T&>(value);
typename std::map<T, std::set<uint64_t>>::iterator itr = values.find(val);
if (itr == values.end()) {
throw 2; //this is not suppose to happen!
}
const std::set<uint64_t>& set = itr->second;
std::set<uint64_t>::const_iterator sItr = set.find(id);
if (sItr == set.end()) {
throw 2; //not suppose to happen!
}
++sItr;
if (sItr == set.end()) {
++itr;
bool found = false;
while (itr != values.end()) {
if (itr->second.size() != 0) {
sItr = set.begin();
found = true;
break;
}
++itr;
}
if (!found) {
return 0;
}
}
return *sItr;
}
template<class T>
uint64_t ICatalogue::Index<T>::getPrev(uint64_t id, const W::Object& value)
{
if (value.getType() != valueType) {
throw new TypeError("Unknown", "getPrev", valueType, value.getType());
}
const T& val = static_cast<const T&>(value);
typename std::map<T, std::set<uint64_t>>::iterator itr = values.find(val);
if (itr == values.end()) {
throw 2; //this is not suppose to happen!
}
const std::set<uint64_t>& set = itr->second;
std::set<uint64_t>::const_iterator sItr = set.find(id);
if (sItr == set.end()) {
throw 2; //not suppose to happen!
}
if (sItr == set.begin()) {
bool found = false;
while (itr != values.begin()) {
--itr;
if (itr->second.size() != 0) {
sItr = set.end();
--sItr;
break;
}
}
if (!found) {
return 0;
}
} else {
--sItr;
}
return *sItr;
}
}
#endif // ICATALOGUE_H

100
lib/wModel/list.cpp Normal file
View file

@ -0,0 +1,100 @@
#include "list.h"
M::List::List(const W::Address p_address, QObject* parent):
M::Model(p_address, parent),
data(new W::Vector())
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::List::_h_get);
addHandler(get);
}
M::List::~List()
{
delete data;
}
void M::List::h_subscribe(const W::Event& ev)
{
M::Model::h_subscribe(ev);
h_get(ev);
}
void M::List::h_get(const W::Event& ev)
{
W::Vocabulary* vc = new W::Vocabulary;
vc->insert(u"data", data->copy());
response(vc, W::Address({u"get"}), ev);
}
void M::List::push(const W::Object& obj)
{
data->push(obj);
if (registered) {
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"data", obj);
broadcast(vc, W::Address{u"push"});
}
}
void M::List::push(W::Object* obj)
{
data->push(obj);
if (registered) {
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"data", obj->copy());
broadcast(vc, W::Address{u"push"});
}
}
void M::List::clear()
{
data->clear();
if (registered) {
broadcast(new W::Vocabulary(), W::Address{u"clear"});
}
}
M::Model::ModelType M::List::getType() const
{
return type;
}
void M::List::set(const W::Object& value)
{
delete data;
data = static_cast<W::Vector*>(value.copy());
W::Vocabulary* vc = new W::Vocabulary;
vc->insert(u"data", data->copy());
broadcast(vc, W::Address({u"get"}));
}
void M::List::set(W::Object* value)
{
delete data;
data = static_cast<W::Vector*>(value);
W::Vocabulary* vc = new W::Vocabulary;
vc->insert(u"data", data->copy());
broadcast(vc, W::Address({u"get"}));
}
uint64_t M::List::size() const
{
return data->size();
}
const W::Object & M::List::at(uint64_t index) const
{
return data->at(index);
}

41
lib/wModel/list.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef M_LIST_H
#define M_LIST_H
#include "model.h"
#include <wType/object.h>
#include <wType/address.h>
#include <wType/vector.h>
namespace M {
class List : public M::Model
{
public:
List(const W::Address p_address, QObject* parent = 0);
~List();
void push(const W::Object& obj);
void push(W::Object* obj);
void clear();
uint64_t size() const;
const W::Object& at(uint64_t index) const;
void set(const W::Object & value) override;
void set(W::Object * value) override;
M::Model::ModelType getType() const override;
static const M::Model::ModelType type = list;
protected:
void h_subscribe(const W::Event & ev) override;
handler(get);
private:
W::Vector* data;
};
}
#endif // M_LIST_H

339
lib/wModel/model.cpp Normal file
View file

@ -0,0 +1,339 @@
#include "model.h"
M::Model::Model(const W::Address p_address, QObject* parent):
QObject(parent),
address(p_address),
registered(false),
subscribers(new Map()),
dispatcher(0),
server(0),
subscribersCount(0),
handlers(new HList()),
properties(new W::Vector()),
models(new MList())
{
W::Handler* subscribe = W::Handler::create(address + W::Address({u"subscribe"}), this, &M::Model::_h_subscribe);
W::Handler* unsubscribe = W::Handler::create(address + W::Address({u"unsubscribe"}), this, &M::Model::_h_unsubscribe);
addHandler(subscribe);
addHandler(unsubscribe);
}
M::Model::~Model()
{
if (registered) {
unregisterModel();
}
MList::iterator itr = models->begin();
MList::iterator end = models->end();
for (; itr != end; ++itr) {
delete *itr;
}
HList::iterator hItr = handlers->begin();
HList::iterator hEnd = handlers->end();
for (; hItr != hEnd; ++hItr) {
delete *hItr;
}
delete subscribers;
delete properties;
delete handlers;
delete models;
}
void M::Model::addModel(M::Model* model)
{
models->push_back(model);
connect(model, SIGNAL(serviceMessage(const QString&)), SIGNAL(serviceMessage(const QString&)));
if (registered) {
model->registerModel(dispatcher, server);
}
}
void M::Model::addHandler(W::Handler* handler)
{
handlers->push_back(handler);
if (registered) {
dispatcher->registerHandler(handler);
}
}
void M::Model::addProperty(const W::String& value, const W::String& name)
{
W::Vocabulary vc;
vc.insert(u"key", name);
vc.insert(u"property", value);
properties->push(vc);
if (registered) {
W::Vocabulary* nvc = new W::Vocabulary;
nvc->insert(u"properties", *properties);
broadcast(nvc, W::Address({u"properties"}));
}
}
W::Address M::Model::getAddress() const
{
return address;
}
void M::Model::registerModel(W::Dispatcher* dp, W::Server* srv)
{
if (registered) {
emit serviceMessage(QString("Model ") + address.toString().c_str() + " is already registered");
throw 1;
} else {
dispatcher = dp;
server = srv;
MList::iterator itr = models->begin();
MList::iterator end = models->end();
for (; itr != end; ++itr) {
M::Model* model = *itr;
model->registerModel(dispatcher, server);
}
HList::iterator hItr = handlers->begin();
HList::iterator hEnd = handlers->end();
for (; hItr != hEnd; ++hItr) {
W::Handler* handler = *hItr;
dispatcher->registerHandler(handler);
}
registered = true;
}
}
void M::Model::unregisterModel()
{
if (!registered) {
emit serviceMessage(QString("Model ") + address.toString().c_str() + " is not registered");
throw 2;
} else {
MList::iterator itr = models->begin();
MList::iterator end = models->end();
for (; itr != end; ++itr) {
Model* model = *itr;
model->unregisterModel();
}
HList::iterator hItr = handlers->begin();
HList::iterator hEnd = handlers->end();
for (; hItr != hEnd; ++hItr) {
W::Handler* handler = *hItr;
dispatcher->unregisterHandler(handler);
}
Map::iterator sItr = subscribers->begin();
Map::iterator sEnd = subscribers->end();
for (; sItr != sEnd; ++sItr) {
const W::Socket& socket = server->getConnection(sItr->first);
disconnect(&socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
}
subscribers->clear();
subscribersCount = 0;
dispatcher = 0;
server = 0;
registered = false;
}
}
void M::Model::h_subscribe(const W::Event& ev)
{
uint64_t id = ev.getSenderId();
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Address& source = static_cast<const W::Address&>(vc.at(u"source"));
W::Vocabulary params;
if (vc.has(u"params")) {
params = static_cast<const W::Vocabulary&>(vc.at(u"params"));
}
Map::iterator sItr = subscribers->find(id);
if (sItr == subscribers->end()) {
std::pair<Map::iterator, bool> pair = subscribers->emplace(std::make_pair(id, SMap()));
if (!pair.second) {
emit serviceMessage(QString("Model ") + address.toString().c_str() + ": something completely wrong happened");
throw 3;
}
const W::Socket& socket = server->getConnection(id);
connect(&socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
sItr = pair.first;
}
SMap::const_iterator oItr = sItr->second.find(source);
if (oItr != sItr->second.end()) {
emit serviceMessage(QString("Socket ") + id +
" subscriber " + source.toString().c_str() +
" is already subscribed to model " + source.toString().c_str());
throw 4;
}
sItr->second.insert(std::make_pair(source, params));
++subscribersCount;
W::Vocabulary* nvc = new W::Vocabulary();
nvc->insert(u"properties", *properties);
response(nvc, W::Address({u"properties"}), ev);
emit serviceMessage(QString("Model ") + address.toString().c_str() + ": now has " + std::to_string(subscribersCount).c_str() + " subscribers");
emit subscribersCountChange(subscribersCount);
}
void M::Model::onSocketDisconnected()
{
W::Socket* socket = static_cast<W::Socket*>(sender());
disconnect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
uint64_t id = socket->getId();
Map::iterator itr = subscribers->find(id);
if (itr == subscribers->end()) {
emit serviceMessage(QString("Model ") + address.toString().c_str() +
": socket disconnected have been handled for not subscribed id");
throw 5;
}
subscribersCount -= itr->second.size();
subscribers->erase(itr);
emit serviceMessage(QString("Model ") + address.toString().c_str() + ": now has " + std::to_string(subscribersCount).c_str() + " subscribers");
emit subscribersCountChange(subscribersCount);
}
void M::Model::h_unsubscribe(const W::Event& ev)
{
uint64_t id = ev.getSenderId();
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Address& source = static_cast<const W::Address&>(vc.at(u"source"));
Map::iterator itr = subscribers->find(id);
if (itr == subscribers->end()) {
emit serviceMessage(QString("Socket ") + id +
" has no subscribed addresses to model " + source.toString().c_str());
throw 6;
}
SMap& smap = itr->second;
SMap::const_iterator sItr = smap.find(source);
if (sItr == smap.end()) {
emit serviceMessage(QString("Socket ") + id +
" subscriber " + source.toString().c_str() +
" is not subscribed to model " + source.toString().c_str());
throw 7;
}
smap.erase(sItr);
if (smap.size() == 0) {
const W::Socket& socket = server->getConnection(itr->first);
disconnect(&socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
subscribers->erase(itr);
}
--subscribersCount;
emit serviceMessage(QString("Model ") + address.toString().c_str() + ": now has " + std::to_string(subscribersCount).c_str() + " subscribers");
emit subscribersCountChange(subscribersCount);
}
void M::Model::send(W::Vocabulary* vc, const W::Address& destination, uint64_t connectionId)
{
if (!registered) {
emit serviceMessage(QString("An attempt to send event from model ") + address.toString().c_str() + " which was not registered");
throw 8;
}
W::Event ev(destination, vc);
ev.setSenderId(connectionId);
server->getConnection(connectionId).send(ev);
}
void M::Model::response(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Event& src)
{
if (!registered) {
emit serviceMessage(QString("An attempt to send event from model ") + address.toString().c_str() + " which was not registered");
throw 8;
}
const W::Vocabulary& svc = static_cast<const W::Vocabulary&>(src.getData());
const W::Address& source = static_cast<const W::Address&>(svc.at(u"source"));
uint64_t id = src.getSenderId();
vc->insert(u"source", address);
W::Event ev(source + handlerAddress, vc);
ev.setSenderId(id);
server->getConnection(id).send(ev);
}
void M::Model::fakeResponse(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Address& sourceAddress, const W::Event& src)
{
if (!registered) {
emit serviceMessage(QString("An attempt to send event from model ") + address.toString().c_str() + " which was not registered");
throw 8;
}
const W::Vocabulary& svc = static_cast<const W::Vocabulary&>(src.getData());
const W::Address& source = static_cast<const W::Address&>(svc.at(u"source"));
uint64_t id = src.getSenderId();
vc->insert(u"source", sourceAddress);
W::Event ev(source + handlerAddress, vc);
ev.setSenderId(id);
server->getConnection(id).send(ev);
}
void M::Model::broadcast(W::Vocabulary* vc, const W::Address& handlerAddress)
{
if (!registered) {
emit serviceMessage(QString("An attempt to send event from model ") + address.toString().c_str() + " which was not registered");
throw 8;
}
Map::const_iterator itr = subscribers->begin();
Map::const_iterator end = subscribers->end();
vc->insert(u"source", address);
for (;itr != end; ++itr) {
SMap::const_iterator oItr = itr->second.begin();
SMap::const_iterator oEnd = itr->second.end();
for (;oItr != oEnd; ++oItr) {
W::Event ev(oItr->first + handlerAddress, vc->copy());
ev.setSenderId(itr->first);
server->getConnection(itr->first).send(ev);
}
}
delete vc;
}
void M::Model::removeHandler(W::Handler* handler)
{
handlers->erase(handler);
if (registered) {
dispatcher->unregisterHandler(handler);
}
}
void M::Model::removeModel(M::Model* model)
{
models->erase(model);
if (registered) {
model->unregisterModel();
}
}
void M::Model::passToHandler(const W::Event& event) const
{
if (registered) {
dispatcher->pass(event);
} else {
emit serviceMessage(QString("An attempt to pass event to dispatcher from unregistered model\nModel address ") + address.toString().c_str());
}
}

92
lib/wModel/model.h Normal file
View file

@ -0,0 +1,92 @@
#ifndef W_MODEL_H
#define W_MODEL_H
#include <utils/defines.h>
#include <map>
#include <list>
#include <QtCore/QObject>
#include <QtCore/QString>
#include <wType/address.h>
#include <wType/vector.h>
#include <wType/event.h>
#include <wType/string.h>
#include <wSocket/socket.h>
#include <wSocket/server.h>
#include <wDispatcher/dispatcher.h>
#include <wDispatcher/handler.h>
#include <wContainer/order.h>
namespace M {
class Model : public QObject
{
Q_OBJECT
public:
enum ModelType {
string,
list,
vocabulary,
catalogue,
attributes = 50,
file,
resourceCache
};
Model(const W::Address p_address, QObject* parent = 0);
//i'm not sure about copy constructor, it just doesn't make sense, because the address is the parameter which is supposed to be unique
virtual ~Model();
virtual ModelType getType() const = 0;
virtual void set(W::Object* value) = 0;
virtual void set(const W::Object& value) = 0;
void addModel(M::Model* model);
void addHandler(W::Handler* handler);
void addProperty(const W::String& value, const W::String& name);
W::Address getAddress() const;
void registerModel(W::Dispatcher* dp, W::Server* srv);
void unregisterModel();
void removeHandler(W::Handler* handler);
void removeModel(M::Model* model);
void passToHandler(const W::Event& event) const;
signals:
void serviceMessage(const QString& msg) const;
void subscribersCountChange(uint64_t count) const;
protected:
typedef std::map<W::Address, W::Vocabulary> SMap;
typedef std::map<uint64_t, SMap> Map;
W::Address address;
bool registered;
Map* subscribers;
void send(W::Vocabulary* vc, const W::Address& destination, uint64_t connectionId);
void response(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Event& src);
void fakeResponse(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Address& sourceAddress, const W::Event& src);
void broadcast(W::Vocabulary* vc, const W::Address& handlerAddress);
handler(subscribe)
handler(unsubscribe)
private:
typedef W::Order<W::Handler*> HList;
typedef W::Order<M::Model*> MList;
W::Dispatcher* dispatcher;
W::Server* server;
uint64_t subscribersCount;
HList* handlers;
W::Vector* properties;
MList* models;
private slots:
void onSocketDisconnected();
};
}
#endif // W_MODEL_H

View file

@ -0,0 +1,77 @@
#include "modelstring.h"
M::String::String(const W::String& str, const W::Address& addr, QObject* parent):
M::Model(addr, parent),
data(new W::String(str))
{
addHandler(W::Handler::create(address + W::Address({u"get"}), this, &M::String::_h_get));
}
M::String::String(W::String* str, const W::Address& addr, QObject* parent):
M::Model(addr, parent),
data(str)
{
}
M::String::~String()
{
delete data;
}
void M::String::h_subscribe(const W::Event& ev)
{
M::Model::h_subscribe(ev);
h_get(ev);
}
void M::String::h_get(const W::Event& ev)
{
W::Vocabulary* vc = new W::Vocabulary;
vc->insert(u"data", *data);
response(vc, W::Address({u"get"}), ev);
}
void M::String::set(const W::String& str)
{
delete data;
data = static_cast<W::String*>(str.copy());
if (registered) {
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"data", str);
broadcast(vc, W::Address{u"get"});
}
}
void M::String::set(W::String* str)
{
delete data;
data = str;
if (registered) {
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"data", *str);
broadcast(vc, W::Address{u"get"});
}
}
void M::String::set(const W::Object& value)
{
set(static_cast<const W::String&>(value));
}
void M::String::set(W::Object* value)
{
set(static_cast<W::String*>(value));
}
M::Model::ModelType M::String::getType() const
{
return type;
}

40
lib/wModel/modelstring.h Normal file
View file

@ -0,0 +1,40 @@
#ifndef M_STRING_H
#define M_STRING_H
#include "model.h"
#include <QtCore/QObject>
#include <wType/string.h>
#include <wType/address.h>
namespace M {
class String: public Model
{
public:
String(const W::String& str, const W::Address& addr, QObject* parent = 0);
String(W::String* str, const W::Address& addr, QObject* parent = 0);
~String();
void set(const W::Object & value) override;
void set(W::Object * value) override;
void set(const W::String& str);
void set(W::String* str);
M::Model::ModelType getType() const override;
static const M::Model::ModelType type = M::Model::string;
protected:
void h_subscribe(const W::Event& ev);
handler(get)
private:
W::String* data;
};
}
#endif // M_STRING_H

136
lib/wModel/vocabulary.cpp Normal file
View file

@ -0,0 +1,136 @@
#include "vocabulary.h"
M::Vocabulary::Vocabulary(const W::Address p_address, QObject* parent):
M::Model(p_address, parent),
data(new W::Vocabulary())
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Vocabulary::_h_get);
addHandler(get);
}
M::Vocabulary::Vocabulary(W::Vocabulary* p_data, const W::Address p_address, QObject* parent):
M::Model(p_address, parent),
data(p_data)
{
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Vocabulary::_h_get);
addHandler(get);
}
M::Vocabulary::~Vocabulary()
{
delete data;
}
void M::Vocabulary::h_subscribe(const W::Event& ev)
{
M::Model::h_subscribe(ev);
h_get(ev);
}
void M::Vocabulary::h_get(const W::Event& ev)
{
W::Vocabulary* vc = new W::Vocabulary;
vc->insert(u"data", data->copy());
response(vc, W::Address({u"get"}), ev);
}
void M::Vocabulary::insert(const W::String& key, const W::Object& value)
{
if (registered) {
W::Vocabulary* vc = new W::Vocabulary();
W::Vocabulary* insert = new W::Vocabulary();
W::Vector* erase = new W::Vector();
if (data->has(key)) {
erase->push(key);
}
data->insert(key, value);
insert->insert(key, value);
vc->insert(u"insert", insert);
vc->insert(u"erase", erase);
broadcast(vc, W::Address{u"change"});
} else {
data->insert(key, value);
}
}
void M::Vocabulary::insert(const W::String& key, W::Object* value)
{
if (registered) {
W::Vocabulary* vc = new W::Vocabulary();
W::Vocabulary* insert = new W::Vocabulary();
W::Vector* erase = new W::Vector();
if (data->has(key)) {
erase->push(key);
}
data->insert(key, value);
insert->insert(key, value->copy());
vc->insert(u"insert", insert);
vc->insert(u"erase", erase);
broadcast(vc, W::Address{u"change"});
} else {
data->insert(key, value);
}
}
void M::Vocabulary::erase(const W::String& key)
{
data->erase(key);
if (registered) {
W::Vocabulary* vc = new W::Vocabulary();
W::Vocabulary* insert = new W::Vocabulary();
W::Vector* erase = new W::Vector();
erase->push(key);
vc->insert(u"insert", insert);
vc->insert(u"erase", erase);
broadcast(vc, W::Address{u"change"});
}
}
void M::Vocabulary::clear()
{
data->clear();
if (registered) {
broadcast(new W::Vocabulary(), W::Address{u"clear"});
}
}
M::Model::ModelType M::Vocabulary::getType() const
{
return type;
}
void M::Vocabulary::set(const W::Object& value)
{
delete data;
data = static_cast<W::Vocabulary*>(value.copy());
W::Vocabulary* vc = new W::Vocabulary;
vc->insert(u"data", data->copy());
broadcast(vc, W::Address({u"get"}));
}
void M::Vocabulary::set(W::Object* value)
{
delete data;
data = static_cast<W::Vocabulary*>(value);
W::Vocabulary* vc = new W::Vocabulary;
vc->insert(u"data", data->copy());
broadcast(vc, W::Address({u"get"}));
}

45
lib/wModel/vocabulary.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef M_VOCABULARY_H
#define M_VOCABULARY_H
#include "model.h"
#include <wType/object.h>
#include <wType/address.h>
#include <wType/vocabulary.h>
#include <wType/vector.h>
namespace M {
class ICatalogue;
class Vocabulary : public M::Model
{
friend class ICatalogue;
public:
Vocabulary(const W::Address p_address, QObject* parent = 0);
Vocabulary(W::Vocabulary* p_data, const W::Address p_address, QObject* parent = 0);
~Vocabulary();
void insert(const W::String& key, const W::Object& value);
void insert(const W::String& key, W::Object* value);
void erase(const W::String& key);
void clear();
void set(const W::Object & value) override;
void set(W::Object* value) override;
M::Model::ModelType getType() const override;
static const M::Model::ModelType type = vocabulary;
protected:
void h_subscribe(const W::Event & ev) override;
handler(get);
private:
W::Vocabulary* data;
};
}
#endif // M_VOCABULARY_H

View file

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 2.8.12)
project(wServerUtils)
find_package(Qt5Core REQUIRED)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(HEADERS
commands.h
connector.h
)
set(SOURCES
commands.cpp
connector.cpp
)
add_library(wServerUtils ${HEADERS} ${SOURCES})
target_link_libraries(wServerUtils Qt5::Core)
target_link_libraries(wServerUtils wType)
target_link_libraries(wServerUtils wModel)
target_link_libraries(wServerUtils wSocket)
target_link_libraries(wServerUtils wDispatcher)

View file

@ -0,0 +1,85 @@
#include "commands.h"
U::Commands::Commands(const W::Address& address, QObject* parent):
M::Vocabulary(address, parent),
commands(new Map())
{
}
U::Commands::~Commands()
{
Map::iterator beg = commands->begin();
Map::iterator end = commands->end();
for (; beg != end; ++beg) {
Command* cmd = beg->second;
if (cmd->enabled) {
removeHandler(cmd->handler);
}
delete cmd->handler;
delete cmd;
}
delete commands;
}
void U::Commands::addCommand(const W::String& key, W::Handler* handler, const W::Vocabulary& args)
{
Map::const_iterator itr = commands->find(key);
if (itr != commands->end()) {
throw 1;
}
Command* cmd = new Command{key, handler, args, false};
commands->insert(std::make_pair(cmd->name, cmd));
}
void U::Commands::enableCommand(const W::String& key, bool value)
{
Map::const_iterator itr = commands->find(key);
if (itr == commands->end()) {
throw 2;
}
Command* cmd = itr->second;
if (cmd->enabled != value) {
if (value) {
enableCommand(cmd);
} else {
disableCommand(cmd);
}
}
}
void U::Commands::enableCommand(U::Commands::Command* cmd)
{
addHandler(cmd->handler);
cmd->enabled = true;
W::Vocabulary* vc = new W::Vocabulary;
vc->insert(u"address", cmd->handler->getAddress());
vc->insert(u"arguments", cmd->arguments);
insert(cmd->name, vc);
}
void U::Commands::disableCommand(U::Commands::Command* cmd)
{
removeHandler(cmd->handler);
cmd->enabled = false;
erase(cmd->name);
}
void U::Commands::removeCommand(const W::String& key)
{
Map::const_iterator itr = commands->find(key);
if (itr == commands->end()) {
throw 2;
}
Command* cmd = itr->second;
if (cmd->enabled) {
disableCommand(cmd);
}
commands->erase(itr);
delete cmd->handler;
delete cmd;
}

View file

@ -0,0 +1,43 @@
#ifndef SERVERUTILS_COMMANDS_H
#define SERVERUTILS_COMMANDS_H
#include <map>
#include <wType/address.h>
#include <wType/vocabulary.h>
#include <wType/event.h>
#include <wType/string.h>
#include <wModel/vocabulary.h>
namespace U {
class Commands : public M::Vocabulary
{
struct Command;
typedef std::map<W::String, Command*> Map;
public:
Commands(const W::Address& address, QObject* parent = 0);
~Commands();
void addCommand(const W::String& key, W::Handler* handler, const W::Vocabulary& args);
void removeCommand(const W::String& key);
void enableCommand(const W::String& key, bool value);
private:
void enableCommand(Command* cmd);
void disableCommand(Command* cmd);
Map* commands;
struct Command {
W::String name;
W::Handler* handler;
W::Vocabulary arguments;
bool enabled;
};
};
}
#endif // SERVERUTILS_COMMANDS_H

View file

@ -0,0 +1,124 @@
#include "connector.h"
U::Connector::Connector(W::Dispatcher* dp, W::Server* srv, U::Commands* cmds, QObject* parent):
QObject(parent),
dispatcher(dp),
server(srv),
commands(cmds),
nodes(),
ignoredNodes()
{
connect(server, SIGNAL(newConnection(const W::Socket&)), SLOT(onNewConnection(const W::Socket&)));
connect(server, SIGNAL(closedConnection(const W::Socket&)), SLOT(onClosedConnection(const W::Socket&)));
W::String cn = W::String(u"connect");
W::Handler* ch = W::Handler::create(commands->getAddress() + W::Address({cn}), this, &U::Connector::_h_connect);
W::Vocabulary vc;
vc.insert(u"address", W::Uint64(W::Object::string));
vc.insert(u"port", W::Uint64(W::Object::uint64));
commands->addCommand(cn, ch, vc);
commands->enableCommand(cn, true);
}
U::Connector::~Connector()
{
commands->removeCommand(W::String(u"connect"));
Map::const_iterator itr = nodes.begin();
Map::const_iterator end = nodes.begin();
W::String dc = W::String(u"disconnect");
for (; itr != end; ++itr) {
commands->removeCommand(dc + itr->first);
}
}
void U::Connector::addIgnoredNode(const W::String& name)
{
ignoredNodes.insert(name);
}
void U::Connector::sendTo(const W::String& name, const W::Event& event)
{
Map::const_iterator itr = nodes.find(name);
if (itr != nodes.end()) {
throw new NodeAccessError(name);
} else {
server->getConnection(itr->second).send(event);
}
}
void U::Connector::onNewConnection(const W::Socket& socket)
{
W::String name = socket.getRemoteName();
std::set<W::String>::const_iterator ign = ignoredNodes.find(name);
if (ign == ignoredNodes.end()) {
Map::const_iterator itr = nodes.find(name);
if (itr == nodes.end()) {
if (server->getName() == name) {
emit serviceMessage("An attempt to connect node to itself, closing connection");
server->closeConnection(socket.getId());
} else {
W::String dc = W::String(u"disconnect");
W::String dn = dc + name;
W::Handler* dh = W::Handler::create(commands->getAddress() + W::Address({dc, name}), this, &U::Connector::_h_disconnect);
commands->addCommand(dn, dh, W::Vocabulary());
commands->enableCommand(dn, true);
nodes.insert(std::make_pair(name, socket.getId()));
emit serviceMessage(QString("New connection, id: ") + socket.getId().toString().c_str());
connect(&socket, SIGNAL(message(const W::Event&)), dispatcher, SLOT(pass(const W::Event&)));
emit nodeConnected(name);
}
} else {
emit serviceMessage(QString("Node ") + QString(name.toString().c_str()) + " tried to connect, but connection with that node is already open, closing new connection");
server->closeConnection(socket.getId());
}
} else {
emit serviceMessage(QString("New connection, id: ") + socket.getId().toString().c_str());
connect(&socket, SIGNAL(message(const W::Event&)), dispatcher, SLOT(pass(const W::Event&)));
}
}
void U::Connector::onClosedConnection(const W::Socket& socket)
{
emit serviceMessage(QString("Connection closed, id: ") + socket.getId().toString().c_str());
W::String name = socket.getRemoteName();
std::set<W::String>::const_iterator ign = ignoredNodes.find(name);
if (ign == ignoredNodes.end()) {
Map::const_iterator itr = nodes.find(name);
if (itr != nodes.end()) {
emit nodeDisconnected(name);
commands->removeCommand(W::String(u"disconnect") + name);
nodes.erase(itr);
}
}
}
void U::Connector::h_connect(const W::Event& ev)
{
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::String& addr = static_cast<const W::String&>(vc.at(u"address"));
const W::Uint64& port = static_cast<const W::Uint64&>(vc.at(u"port"));
server->openConnection(addr, port);
}
void U::Connector::h_disconnect(const W::Event& ev)
{
const W::Address& addr = static_cast<const W::Address&>(ev.getDestination());
const W::String& name = addr.back();
Map::const_iterator itr = nodes.find(name);
server->closeConnection(itr->second);
}
const W::Socket& U::Connector::getNodeSocket(const W::String& name)
{
Map::const_iterator itr = nodes.find(name);
if (itr == nodes.end()) {
throw new NodeAccessError(name);
}
return server->getConnection(itr->second);
}

View file

@ -0,0 +1,68 @@
#ifndef CONNECTOR_H
#define CONNECTOR_H
#include <QtCore/QObject>
#include <map>
#include <set>
#include <wDispatcher/dispatcher.h>
#include <wSocket/socket.h>
#include <wSocket/server.h>
#include <wType/string.h>
#include <wType/uint64.h>
#include <wType/event.h>
#include <utils/exception.h>
#include "commands.h"
namespace U {
class Connector : public QObject
{
Q_OBJECT
typedef std::map<W::String, uint64_t> Map;
public:
Connector(W::Dispatcher* dp, W::Server* srv, Commands* cmds, QObject* parent = 0);
~Connector();
void addIgnoredNode(const W::String& name);
void sendTo(const W::String& name, const W::Event& event);
const W::Socket& getNodeSocket(const W::String& name);
signals:
void serviceMessage(const QString& msg);
void nodeConnected(const W::String& name);
void nodeDisconnected(const W::String& name);
private:
W::Dispatcher* dispatcher;
W::Server* server;
U::Commands* commands;
Map nodes;
std::set<W::String> ignoredNodes;
protected:
handler(connect);
handler(disconnect);
private slots:
void onNewConnection(const W::Socket& socket);
void onClosedConnection(const W::Socket& socket);
public:
class NodeAccessError:
public Utils::Exception
{
W::String name;
public:
NodeAccessError(const W::String& p_name):Exception(), name(p_name){}
std::string getMessage() const{return std::string("An attempt to access non existing node ") + name.toString();}
};
};
}
#endif // CONNECTOR_H

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

23
lib/wSsh/CMakeLists.txt Normal file
View file

@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 2.8.12)
project(wSsh)
find_package(Qt5Core REQUIRED)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(HEADERS
sshsocket.h
qsshsocket.h
)
set(SOURCES
sshsocket.cpp
qsshsocket.cpp
)
add_library(wSsh ${HEADERS} ${SOURCES})
target_link_libraries(wSsh Qt5::Core)
target_link_libraries(wSsh ssh)
target_link_libraries(wSsh ssh_threads)

186
lib/wSsh/qsshsocket.cpp Normal file
View file

@ -0,0 +1,186 @@
#include "qsshsocket.h"
#include <libssh/callbacks.h>
bool QSshSocket::lib_ssh_inited = false;
QSshSocket::QSshSocket(QObject * parent)
:QObject(parent),
loggedIn(false),
session(0),
m_connected(false),
executing(false),
command(0)
{
if (!lib_ssh_inited) {
lib_ssh_init();
lib_ssh_inited = true;
}
qRegisterMetaType<QSshSocket::SshError>(); //not sure if it supposed to be here
}
QSshSocket::~QSshSocket()
{
}
void QSshSocket::disconnect()
{
if (m_connected) {
loggedIn = false;
m_connected = false;
if (executing) {
destroyCommand();
}
ssh_disconnect(session);
ssh_free(session);
session = 0;
emit disconnected();
}
}
void QSshSocket::connect(QString host, int port)
{
if (!m_connected) {
session = ssh_new();
int verbosity = SSH_LOG_PROTOCOL;
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(session, SSH_OPTIONS_HOST, host.toUtf8().data());
ssh_options_set(session, SSH_OPTIONS_PORT, &port);
int connectionResponse = ssh_connect(session);
if (connectionResponse == SSH_OK) {
m_connected = true;
emit connected();
} else {
ssh_disconnect(session);
ssh_free(session);
session = 0;
emit error(SessionCreationError);
}
} else {
throw 1; //TODO
}
}
void QSshSocket::login(QString user, QString password)
{
if (m_connected && !loggedIn) {
int worked = ssh_userauth_password(session, user.toUtf8().data(), password.toUtf8().data());
if (worked == SSH_OK) {
loggedIn = true;
emit loginSuccessful();
} else {
emit error(PasswordAuthenticationFailedError);
disconnect();
}
} else {
throw 2; //TODO
}
}
void QSshSocket::executeCommand(QString p_command)
{
if (executing) {
//todo
return;
}
ssh_channel channel = ssh_channel_new(session);
if (ssh_channel_open_session(channel) != SSH_OK) {
emit error(ChannelCreationError);
}
int success;
do {
success = ssh_channel_request_exec(channel, p_command.toUtf8().data());
} while (success == SSH_AGAIN);
if (success != SSH_OK) {
ssh_channel_close(channel);
ssh_channel_free(channel);
emit error(WriteError);
} else {
qintptr fd = ssh_get_fd(session);
QSocketNotifier* readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read);
QObject::connect(readNotifier, SIGNAL(activated(int)), this, SLOT(socketRead(int)));
command = new Command{fd, p_command, channel, readNotifier};
executing = true;
}
}
bool QSshSocket::isConnected()
{
return m_connected;
}
bool QSshSocket::isLoggedIn()
{
return loggedIn;
}
bool QSshSocket::isExecuting()
{
return executing;
}
void QSshSocket::socketRead(int ptr)
{
command->notifier->setEnabled(false);
char* buffer = new char[1048576];
int totalBytes = 0;
int newBytes = 0;
do {
newBytes = ssh_channel_read_nonblocking(command->channel, &buffer[totalBytes], 1048576 - totalBytes, 0);
if (newBytes > 0) {
totalBytes += newBytes;
}
} while (newBytes > 0);
if (newBytes == SSH_ERROR) {
emit error(ReadError);
destroyCommand();
} else if (ssh_channel_is_eof(command->channel) != 0) {
command->notifier->setEnabled(true);
QString response = QString::fromUtf8(buffer, totalBytes);
emit commandData(response);
emit endOfFile();
destroyCommand();
} else {
command->notifier->setEnabled(true);
QString response = QString::fromUtf8(buffer, totalBytes);
emit commandData(response);
}
delete[] buffer;
}
void QSshSocket::destroyCommand()
{
delete command->notifier;
ssh_channel_send_eof(command->channel);
ssh_channel_close(command->channel);
ssh_channel_free(command->channel);
delete command;
executing = false;
}
void QSshSocket::lib_ssh_init()
{
ssh_threads_set_callbacks(ssh_threads_get_pthread());
ssh_init();
}
void QSshSocket::interrupt()
{
if (executing) {
ssh_channel_request_send_signal(command->channel, "INT");
}
}

81
lib/wSsh/qsshsocket.h Normal file
View file

@ -0,0 +1,81 @@
#ifndef QSSHSOCKET_H
#define QSSHSOCKET_H
#include <libssh/libssh.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <QtCore/QDebug>
#include <QtCore/QObject>
#include <QtCore/QSocketNotifier>
#include <QtCore/QByteArray>
#include <QtCore/QVector>
#include <QtCore/QMap>
class QSshSocket: public QObject
{
Q_OBJECT
public:
enum SshError
{
SocketError,
SessionCreationError,
ChannelCreationError,
ReadError,
WriteError,
PasswordAuthenticationFailedError
};
explicit QSshSocket(QObject* parent = 0);
~QSshSocket();
bool isLoggedIn();
bool isConnected();
bool isExecuting();
signals:
void connected();
void disconnected();
void error(QSshSocket::SshError error);
void loginSuccessful();
void commandData(QString data);
void endOfFile();
public slots:
void connect(QString host, int port = 22);
void disconnect();
void executeCommand(QString command);
void login(QString user, QString password);
void interrupt();
private:
struct Command
{
qintptr id;
QString command;
ssh_channel channel;
QSocketNotifier* notifier;
};
bool loggedIn;
ssh_session session;
bool m_connected;
bool executing;
Command* command;
static bool lib_ssh_inited;
static void lib_ssh_init();
private:
void destroyCommand();
private slots:
void socketRead(int ptr);
};
Q_DECLARE_METATYPE(QSshSocket::SshError)
#endif // QSSHSOCKET_H

195
lib/wSsh/sshsocket.cpp Normal file
View file

@ -0,0 +1,195 @@
#include "sshsocket.h"
#include <QtCore/QDebug>
W::SshSocket::SshSocket(const QString& p_login, const QString& p_password, QObject* parent):
QObject(parent),
socket(new QSshSocket()),
thread(new QThread()),
login(p_login),
password(p_password),
state(Disconnected)
{
connect(socket, SIGNAL(connected()), this, SLOT(onSocketConnected()));
connect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
connect(socket, SIGNAL(loginSuccessful()), this, SLOT(onSocketLoggedIn()));
connect(socket, SIGNAL(error(QSshSocket::SshError)), this, SLOT(onSocketError(QSshSocket::SshError)));
connect(socket, SIGNAL(commandData(QString)), this, SLOT(onSocketCommandData(QString)));
connect(socket, SIGNAL(endOfFile()), this, SLOT(onSocketEOF()));
socket->moveToThread(thread);
}
W::SshSocket::~SshSocket()
{
if (state != Disconnected) {
if (state == Disconnecting) {
onSocketDisconnected();
} else {
qDebug("Socket wasn't closed, terminating the inner thread");
thread->terminate();
}
}
socket->deleteLater();
thread->deleteLater();
//TODO;
}
void W::SshSocket::open(const QString& address, uint16_t port)
{
if (state == Disconnected) {
state = Connecting;
thread->start();
QMetaObject::invokeMethod(socket, "connect", Qt::QueuedConnection, Q_ARG(QString, address), Q_ARG(int, port));
} else {
//TODO;
}
}
void W::SshSocket::onSocketConnected()
{
if (state == Connecting) {
state = Connected;
authorize();
} else {
//TODO;
}
}
void W::SshSocket::authorize()
{
if (state == Connected) {
state = Authorizing;
QMetaObject::invokeMethod(socket, "login", Qt::QueuedConnection, Q_ARG(QString, login), Q_ARG(QString, password));
} else {
//TODO;
}
}
void W::SshSocket::onSocketLoggedIn()
{
if (state == Authorizing) {
state = Authorized;
emit opened();
}
}
void W::SshSocket::close()
{
switch (state) {
case Disconnected:
//TODO;
break;
case Connecting:
case Connected:
case Authorizing:
case Authorized:
QMetaObject::invokeMethod(socket, "disconnect", Qt::QueuedConnection);
state = Disconnecting;
break;
case Disconnecting:
//TODO;
break;
}
}
void W::SshSocket::onSocketDisconnected()
{
if (state == Disconnecting) {
thread->quit();
thread->wait();
state = Disconnected;
emit closed();
} else {
//TODO;
}
}
void W::SshSocket::execute(const QString& command)
{
if (state == Authorized) {
QMetaObject::invokeMethod(socket, "executeCommand", Qt::QueuedConnection, Q_ARG(QString, command));
} else {
//TODO;
}
}
void W::SshSocket::onSocketCommandData(QString p_data)
{
if (state == Authorized) {
emit data(p_data);
}
}
void W::SshSocket::onSocketError(QSshSocket::SshError p_error)
{
QString msg;
Error errCode;
switch (p_error) {
case QSshSocket::SocketError:
msg = "There was a trouble creating a socket. Looks like you have problems with internet connectiion";
errCode = SocketError;
break;
case QSshSocket::SessionCreationError:
msg = "No route to the remote host";
errCode = SessionCreationError;
if (state == Connecting) {
state = Disconnected;
}
break;
case QSshSocket::ChannelCreationError:
msg = "An ssh channel could not be created";
errCode = ChannelCreationError;
break;
case QSshSocket::ReadError:
msg = "There was an error reading the socket";
errCode = ReadError;
break;
case QSshSocket::WriteError:
msg = "There was an error writing to the socket";
errCode = WriteError;
break;
case QSshSocket::PasswordAuthenticationFailedError:
msg = "The credentials of a user on the remote host could not be authenticated";
errCode = PasswordAuthenticationError;
if (state == Authorizing) {
state = Connected;
}
break;
}
emit error(errCode, msg);
}
void W::SshSocket::onSocketEOF()
{
emit finished();
}
bool W::SshSocket::isReady() const
{
return state == Authorized;
}
void W::SshSocket::interrupt()
{
if (state == Authorized) {
QMetaObject::invokeMethod(socket, "interrupt", Qt::QueuedConnection);
} else {
//TODO;
}
}
void W::SshSocket::setLogin(const QString& lng)
{
login = lng;
}
void W::SshSocket::setPassword(const QString& pass)
{
password = pass;
}

69
lib/wSsh/sshsocket.h Normal file
View file

@ -0,0 +1,69 @@
#ifndef SSHSOCKET_H
#define SSHSOCKET_H
#include "qsshsocket.h"
#include <QtCore/QObject>
#include <QtCore/QThread>
namespace W {
class SshSocket : public QObject {
Q_OBJECT
public:
SshSocket(const QString& p_login, const QString& p_password, QObject* parent = 0);
~SshSocket();
enum Error {
SocketError,
SessionCreationError,
ChannelCreationError,
ReadError,
WriteError,
PasswordAuthenticationError
};
void open(const QString& address, uint16_t port = 22);
void close();
void execute(const QString& command);
void interrupt();
bool isReady() const;
void setLogin(const QString& lng);
void setPassword(const QString& pass);
signals:
void opened();
void closed();
void error(W::SshSocket::Error code, const QString& message);
void data(const QString& data);
void finished();
private:
void authorize();
enum State {
Disconnected,
Connecting,
Connected,
Authorizing,
Authorized,
Disconnecting
};
QSshSocket* socket;
QThread* thread;
QString login;
QString password;
State state;
private slots:
void onSocketConnected();
void onSocketDisconnected();
void onSocketLoggedIn();
void onSocketError(QSshSocket::SshError p_error);
void onSocketCommandData(QString p_data);
void onSocketEOF();
};
}
#endif // SSHSOCKET_H

31
lib/wType/CMakeLists.txt Normal file
View file

@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 2.8.12)
project(type)
set(HEADERS
bytearray.h
object.h
string.h
vocabulary.h
uint64.h
address.h
boolean.h
event.h
vector.h
blob.h
)
set(SOURCES
bytearray.cpp
object.cpp
string.cpp
vocabulary.cpp
uint64.cpp
address.cpp
boolean.cpp
event.cpp
vector.cpp
blob.cpp
)
add_library(wType ${HEADERS} ${SOURCES})
target_link_libraries(wType utils)

326
lib/wType/address.cpp Normal file
View file

@ -0,0 +1,326 @@
#include "address.h"
W::Address::Address():
Object(),
data(new List())
{
}
W::Address::Address(const W::Address::InitList& list):
Object(),
data(new List())
{
InitList::const_iterator itr = list.begin();
InitList::const_iterator end = list.end();
for (; itr != end; ++itr)
{
data->emplace_back(String(*itr));
}
}
W::Address::Address(const W::Address& original):
Object(),
data(new List(*original.data))
{
}
W::Address::~Address()
{
delete data;
}
W::Address& W::Address::operator=(const W::Address& original)
{
if (&original != this)
{
data->clear();
data->insert(data->end(), original.data->begin(), original.data->end());
}
return *this;
}
W::Object::size_type W::Address::length() const
{
return data->size();
}
W::Object::objectType W::Address::getType() const
{
return type;
}
W::Object::StdStr W::Address::toString() const
{
StdStr str;
List::const_iterator itr;
List::const_iterator beg = data->begin();
List::const_iterator end = data->end();
str += '[';
for (itr = beg; itr != end; ++itr)
{
if (itr != beg)
{
str += ", ";
}
str += itr->toString();
}
str += ']';
return str;
}
W::Object* W::Address::copy() const
{
return new Address(*this);
}
void W::Address::serialize(W::ByteArray& out) const
{
out.push32(length());
List::const_iterator itr;
List::const_iterator beg = data->begin();
List::const_iterator end = data->end();
for (itr = beg; itr != end; ++itr)
{
itr->serialize(out);
}
}
void W::Address::deserialize(W::ByteArray& in)
{
data->clear();
size_type length = in.pop32();
for (size_type i = 0; i != length; ++i)
{
data->emplace_back(String());
data->back().deserialize(in);
}
}
bool W::Address::operator<(const W::Address& other) const
{
return *data < *other.data;
}
bool W::Address::operator>(const W::Address& other) const
{
return *data > *other.data;
}
bool W::Address::operator==(const W::Address& other) const
{
return *data == *other.data;
}
bool W::Address::operator!=(const W::Address& other) const
{
return *data != *other.data;
}
bool W::Address::operator<=(const W::Address& other) const
{
return *data <= *other.data;
}
bool W::Address::operator>=(const W::Address& other) const
{
return *data >= *other.data;
}
bool W::Address::begins(const W::Address& other) const
{
if (other.length() > length())
{
return false;
}
List::const_iterator itr_o = other.data->begin();
List::const_iterator end_o = other.data->end();
List::const_iterator itr_i = data->begin();
while (itr_o != end_o)
{
if (*itr_o != *itr_i) {
return false;
}
++itr_o;
++itr_i;
}
return true;
}
bool W::Address::ends(const W::Address& other) const
{
if (other.length() > length())
{
return false;
}
List::const_reverse_iterator itr_o = other.data->rbegin();
List::const_reverse_iterator end_o = other.data->rend();
List::const_reverse_iterator itr_i = data->rbegin();
while (itr_o != end_o)
{
if (*itr_o != *itr_i) {
return false;
}
++itr_o;
++itr_i;
}
return true;
}
bool W::Address::contains(const W::Address& other, int position) const
{
if (other.length() > length() - position)
{
return false;
}
bool res = true;
List::const_iterator itr_o = other.data->begin();
List::const_iterator end_o = other.data->end();
List::const_iterator itr_i = data->begin();
for (int i = 0; i < position; ++i) {
++itr_i;
}
while (res == true && itr_o != end_o)
{
res = *itr_o == *itr_i;
++itr_o;
++itr_i;
}
return res;
}
W::Address& W::Address::operator+=(const W::Address& other)
{
data->insert(data->end(), other.data->begin(), other.data->end());
return *this;
}
W::Address& W::Address::operator+=(const W::String& other)
{
data->push_back(other);
return *this;
}
W::Address& W::Address::operator+=(const W::String::u16string& other)
{
String hop(other);
return operator+=(hop);
}
W::Address W::Address::operator>>(W::Object::size_type count) const
{
W::Address res;
if (count < length())
{
List::const_iterator itr = data->end();
for (size_type i = 0; i != count; ++i)
{
itr--;
}
List::const_iterator beg = data->begin();
res.data->insert(res.data->end(), beg, itr);
}
return res;
}
W::Address W::Address::operator<<(W::Object::size_type count) const
{
W::Address res;
if (count < length())
{
List::const_iterator itr = data->begin();
for (size_type i = 0; i != count; ++i)
{
itr++;
}
List::const_iterator end = data->end();
res.data->insert(res.data->end(), itr, end);
}
return res;
}
W::Address W::Address::operator+(const W::Address& other) const
{
W::Address res;
res += *this;
res += other;
return res;
}
W::Address & W::Address::operator+=(const Uint64& other)
{
data->push_back(String(other.toString()));
return *this;
}
W::Address W::Address::operator+(const Uint64& other) const
{
W::Address res;
res += *this;
res += other;
return res;
}
const W::String& W::Address::front() const
{
return data->front();
}
const W::String& W::Address::back() const
{
return data->back();
}
bool W::Address::operator==(const W::Object& other) const
{
if (sameType(other)) {
return operator==(static_cast<const W::Address&>(other));
} else {
return false;
}
}
W::Object::size_type W::Address::size() const
{
size_type size = 4;
List::const_iterator itr = data->begin();
List::const_iterator end = data->end();
for (; itr != end; ++itr)
{
size += itr->size();
}
return size;
}

70
lib/wType/address.h Normal file
View file

@ -0,0 +1,70 @@
#ifndef ADDRESS_H
#define ADDRESS_H
#include "object.h"
#include "string.h"
#include "uint64.h"
#include <list>
#include <initializer_list>
namespace W
{
class Address:
public Object
{
typedef std::list<String> List;
typedef std::initializer_list<String::u16string> InitList;
public:
Address();
Address(const InitList& list);
Address(const Address& original);
~Address();
Address& operator=(const Address& original);
StdStr toString() const override;
Object* copy() const override;
size_type length() const override;
size_type size() const override;
objectType getType() const override;
void serialize(ByteArray& out) const override;
void deserialize(ByteArray& in) override;
bool operator==(const Object & other) const override;
bool operator<(const Address& other) const;
bool operator>(const Address& other) const;
bool operator<=(const Address& other) const;
bool operator>=(const Address& other) const;
bool operator==(const Address& other) const;
bool operator!=(const Address& other) const;
bool begins(const Address& other) const;
bool ends(const Address& other) const;
bool contains(const Address& other, int position) const;
Address& operator+=(const Address& other);
Address& operator+=(const String& other);
Address& operator+=(const Uint64& other);
Address& operator+=(const String::u16string& other);
Address operator>>(size_type count) const;
Address operator<<(size_type count) const;
Address operator+(const Address& other) const;
Address operator+(const Uint64& other) const;
static const objectType type = address;
const String& front() const;
const String& back() const;
private:
List *data;
};
}
#endif // ADDRESS_H

146
lib/wType/blob.cpp Normal file
View file

@ -0,0 +1,146 @@
#include "blob.h"
#include <arpa/inet.h>
#include <string>
W::Blob::Blob():
W::Object(),
hasData(false),
dataSize(0),
data(0),
qDataView()
{
}
W::Blob::Blob(uint32_t size, char* p_data):
W::Object(),
hasData(true),
dataSize(size),
data(p_data),
qDataView(QByteArray::fromRawData(p_data, size))
{
}
W::Blob::Blob(const W::Blob& original):
W::Object(),
hasData(original.data),
dataSize(original.dataSize),
data(0),
qDataView()
{
if (hasData) {
data = new char[dataSize];
std::copy(original.data, original.data + dataSize, data);
qDataView = QByteArray::fromRawData(data, dataSize);
}
}
W::Blob::~Blob()
{
if (hasData) {
delete [] data;
}
}
W::Blob & W::Blob::operator=(const W::Blob& original)
{
if (&original != this)
{
if (hasData) {
delete [] data;
qDataView = QByteArray();
}
hasData = original.hasData;
dataSize = original.dataSize;
if (hasData) {
data = new char[dataSize];
std::copy(original.data, original.data + dataSize, data);
qDataView = QByteArray::fromRawData(data, dataSize);
}
}
return *this;
}
W::Object * W::Blob::copy() const
{
return new W::Blob(*this);
}
W::Object::objectType W::Blob::getType() const
{
return type;
}
W::Object::size_type W::Blob::length() const
{
return dataSize;
}
void W::Blob::serialize(W::ByteArray& out) const
{
out.push32(length());
for (uint32_t i = 0; i < dataSize; ++i) {
out.push8(data[i]);
}
}
void W::Blob::deserialize(W::ByteArray& in)
{
if (hasData) {
delete [] data;
qDataView = QByteArray();
}
dataSize = in.pop32();
if (dataSize > 0) {
hasData = true;
data = new char[dataSize];
for (uint32_t i = 0; i < dataSize; ++i) {
data[i] = in.pop8();
}
qDataView = QByteArray::fromRawData(data, dataSize);
} else {
hasData = false;
}
}
W::Object::StdStr W::Blob::toString() const
{
return "Blob <" + std::to_string(dataSize) + ">";
}
bool W::Blob::operator==(const W::Blob& other) const
{
if (dataSize != other.dataSize) {
return false;
} else {
bool equals = true;
uint64_t i = 0;
while (equals && i < dataSize) {
equals = data[i] == other.data[i]; //TODO not sure about the c++ syntax if i'm comparing values or addresses this time
++i;
}
return equals;
}
}
bool W::Blob::operator==(const W::Object& other) const
{
if (sameType(other)) {
return operator==(static_cast<const W::Blob&>(other));
} else {
return false;
}
}
W::Object::size_type W::Blob::size() const
{
return dataSize + 4;
}
const QByteArray & W::Blob::byteArray() const
{
return qDataView;
}

46
lib/wType/blob.h Normal file
View file

@ -0,0 +1,46 @@
#ifndef BLOB_H
#define BLOB_H
#include "object.h"
#include <QtCore/QByteArray>
namespace W
{
class Blob: public Object
{
public:
Blob();
Blob(uint32_t size, char* p_data);
Blob(const Blob& original);
~Blob();
Blob& operator=(const Blob& original);
StdStr toString() const override;
Object* copy() const override;
size_type length() const override;
size_type size() const override;
objectType getType() const override;
bool operator==(const W::Object & other) const override;
void serialize(ByteArray& out) const override;
void deserialize(ByteArray& in) override;
bool operator==(const Blob& other) const;
static const objectType type = blob;
const QByteArray& byteArray() const;
protected:
bool hasData;
uint32_t dataSize;
char* data;
QByteArray qDataView;
};
}
#endif // BLOB_H

146
lib/wType/boolean.cpp Normal file
View file

@ -0,0 +1,146 @@
#include "boolean.h"
W::Boolean::Boolean():
Object(),
data(false)
{
}
W::Boolean::Boolean(bool value):
Object(),
data(value)
{
}
W::Boolean::Boolean(const W::Boolean& original):
Object(),
data(original.data)
{
}
W::Boolean::~Boolean()
{
}
W::Boolean& W::Boolean::operator=(const W::Boolean& original)
{
data = original.data;
return *this;
}
W::Boolean& W::Boolean::operator=(bool original)
{
data = original;
return *this;
}
W::Object::StdStr W::Boolean::toString() const
{
StdStr str;
if (data)
{
str = "true";
}
else
{
str = "false";
}
return str;
}
W::Object::objectType W::Boolean::getType() const
{
return Boolean::type;
}
W::Object::size_type W::Boolean::length() const
{
return 1;
}
W::Object* W::Boolean::copy() const
{
return new Boolean(*this);
}
bool W::Boolean::operator>(const W::Boolean& other) const
{
return data > other.data;
}
bool W::Boolean::operator<(const W::Boolean& other) const
{
return data < other.data;
}
bool W::Boolean::operator==(const W::Boolean& other) const
{
return data == other.data;
}
bool W::Boolean::operator!=(const W::Boolean& other) const
{
return data != other.data;
}
bool W::Boolean::operator<=(const W::Boolean& other) const
{
return data <= other.data;
}
bool W::Boolean::operator>=(const W::Boolean& other) const
{
return data >= other.data;
}
void W::Boolean::serialize(W::ByteArray& out) const
{
uint8_t val;
if (data)
{
val = 253;
}
else
{
val = 0;
}
out.push8(val);
}
void W::Boolean::deserialize(W::ByteArray& in)
{
uint8_t val = in.pop8();
if (val == 253)
{
data = true;
}
else
{
data = false;
}
}
W::Boolean::operator bool() const
{
return data;
}
bool W::Boolean::operator==(const W::Object& other) const
{
if (sameType(other)) {
return operator==(static_cast<const W::Boolean&>(other));
} else {
return false;
}
}
W::Object::size_type W::Boolean::size() const
{
return 1;
}

49
lib/wType/boolean.h Normal file
View file

@ -0,0 +1,49 @@
#ifndef BOOLEAN_H
#define BOOLEAN_H
#include "object.h"
namespace W
{
class Boolean:
public Object
{
public:
Boolean();
explicit Boolean(bool value);
Boolean(const Boolean& original);
~Boolean();
Boolean& operator=(const Boolean& original);
Boolean& operator=(bool original);
StdStr toString() const override;
Object* copy() const override;
size_type length() const override;
size_type size() const override;
objectType getType() const override;
bool operator==(const W::Object & other) const override;
bool operator<(const Boolean& other) const;
bool operator>(const Boolean& other) const;
bool operator<=(const Boolean& other) const;
bool operator>=(const Boolean& other) const;
bool operator==(const Boolean& other) const;
bool operator!=(const Boolean& other) const;
static const objectType type = boolean;
void serialize(ByteArray& out) const override;
void deserialize(ByteArray& in) override;
operator bool() const;
private:
bool data;
};
}
#endif // BOOLEAN_H

Some files were not shown because too many files have changed in this diff Show more