2019-02-12 13:12:11 +03:00
|
|
|
#include "clientprotocol.h"
|
2019-02-13 13:03:40 +03:00
|
|
|
|
2019-02-25 21:38:37 +03:00
|
|
|
#include <QDataStream>
|
2019-02-13 13:03:40 +03:00
|
|
|
#include <QVariantMap>
|
2019-02-25 21:38:37 +03:00
|
|
|
#include <networkobjects.h>
|
|
|
|
#include <streamers.h>
|
2019-02-13 13:03:40 +03:00
|
|
|
|
|
|
|
#define DEFAULT_GAME_PORT 7777
|
|
|
|
|
|
|
|
namespace ClientProtocol {
|
|
|
|
|
|
|
|
|
|
|
|
Header::Header() {
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Header::isValid() const {
|
|
|
|
|
2019-02-13 22:03:29 +03:00
|
|
|
if (sizeof (*this) != 2) {
|
2019-02-13 13:03:40 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (command) {
|
2019-02-15 23:36:59 +03:00
|
|
|
case Ping: {
|
2019-02-13 13:03:40 +03:00
|
|
|
|
2019-02-13 22:03:29 +03:00
|
|
|
if (type > 1 || size > 0)
|
2019-02-13 13:03:40 +03:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-15 23:36:59 +03:00
|
|
|
case Item: {
|
2019-02-13 22:03:29 +03:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case Request: return size == 36; // key sha256 (32byte) + id item 4
|
2019-02-25 21:38:37 +03:00
|
|
|
case Responke: return true;
|
2019-02-13 22:03:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-15 23:36:59 +03:00
|
|
|
case Login: {
|
2019-02-13 22:03:29 +03:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case Request: return size == 96; // key sha256 (32byte) + maxsize of name of gmail (64)
|
2019-02-25 21:38:37 +03:00
|
|
|
case Responke: return isValidSize(SnakeUtils::Player, size);
|
2019-02-13 22:03:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-15 23:36:59 +03:00
|
|
|
case PlayerData: {
|
2019-02-13 22:03:29 +03:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case Request: return size == 96; // key sha256 (32byte) + maxsize of name of gmail (64)
|
2019-02-25 21:38:37 +03:00
|
|
|
case Responke: return isValidSize(SnakeUtils::Player, size);
|
2019-02-13 22:03:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-13 13:03:40 +03:00
|
|
|
default: return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Header::reset() {
|
|
|
|
size = 0;
|
2019-02-15 23:36:59 +03:00
|
|
|
command = Undefined;
|
2019-02-13 13:03:40 +03:00
|
|
|
type = Responke;
|
|
|
|
}
|
|
|
|
|
|
|
|
Package::Package() {
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Package::isValid() const {
|
|
|
|
if (!hdr.isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hdr.size == data.size();
|
|
|
|
}
|
|
|
|
|
2019-02-15 23:36:59 +03:00
|
|
|
bool Package::parse(QVariantMap& res) const {
|
2019-02-13 13:03:40 +03:00
|
|
|
if (!isValid())
|
2019-02-15 23:36:59 +03:00
|
|
|
return false;
|
2019-02-13 13:03:40 +03:00
|
|
|
|
2019-02-14 13:58:51 +03:00
|
|
|
res["command"] = hdr.command;
|
|
|
|
res["type"] = hdr.type;
|
|
|
|
|
2019-02-13 13:03:40 +03:00
|
|
|
switch (hdr.command) {
|
2019-02-15 23:36:59 +03:00
|
|
|
case Ping: {
|
2019-02-13 13:03:40 +03:00
|
|
|
if (hdr.type == Responke) {
|
|
|
|
res["res"] = "Pong";
|
|
|
|
} else {
|
|
|
|
res["value"] = "Ping";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-02-15 23:36:59 +03:00
|
|
|
case Item: {
|
2019-02-14 13:58:51 +03:00
|
|
|
|
|
|
|
if (hdr.type == Responke) {
|
|
|
|
|
|
|
|
QDataStream stream(data);
|
2019-02-25 21:38:37 +03:00
|
|
|
if (!Streamers::read(stream, res)) {
|
|
|
|
return false;
|
2019-02-14 13:58:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
res["hash"] = data.left(32);
|
|
|
|
res["id"] = data.right(4).toInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-02-15 23:36:59 +03:00
|
|
|
case Login: {
|
2019-02-14 13:58:51 +03:00
|
|
|
|
|
|
|
if (hdr.type == Responke) {
|
|
|
|
|
|
|
|
QDataStream stream(data);
|
|
|
|
|
2019-02-25 21:38:37 +03:00
|
|
|
if (!Streamers::read(stream, res)) {
|
2019-02-15 23:36:59 +03:00
|
|
|
return false;
|
2019-02-14 13:58:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
QDataStream stream(data);
|
|
|
|
QString gmail;
|
|
|
|
QByteArray hash;
|
|
|
|
|
|
|
|
stream >> gmail;
|
|
|
|
stream >> hash;
|
|
|
|
|
|
|
|
res["gmail"] = gmail;
|
|
|
|
res["hash"] = hash;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-02-15 23:36:59 +03:00
|
|
|
case PlayerData: {
|
2019-02-13 22:03:29 +03:00
|
|
|
|
2019-02-14 13:58:51 +03:00
|
|
|
if (hdr.type == Responke) {
|
|
|
|
|
|
|
|
QDataStream stream(data);
|
2019-02-25 21:38:37 +03:00
|
|
|
if (!Streamers::read(stream, res)) {
|
2019-02-15 23:36:59 +03:00
|
|
|
return false;
|
2019-02-14 13:58:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
QDataStream stream(data);
|
|
|
|
QString gmail;
|
|
|
|
QByteArray hash;
|
|
|
|
|
|
|
|
stream >> gmail;
|
|
|
|
stream >> hash;
|
|
|
|
|
|
|
|
res["gmail"] = gmail;
|
|
|
|
res["hash"] = hash;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2019-02-13 13:03:40 +03:00
|
|
|
default:
|
2019-02-15 23:36:59 +03:00
|
|
|
return false;
|
2019-02-13 13:03:40 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-02-15 23:36:59 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Package::create(const QVariantMap &map) {
|
|
|
|
|
|
|
|
auto command = static_cast<unsigned char>(map.value("command", 0xff).toInt());
|
|
|
|
auto type = static_cast<unsigned char>(map.value("type", 0xff).toInt());
|
|
|
|
|
|
|
|
if (command == 0xff || type == 0xff) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (command) {
|
|
|
|
case Ping: {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Item: {
|
|
|
|
|
|
|
|
if (type == Responke) {
|
|
|
|
|
|
|
|
QDataStream stream(data);
|
|
|
|
|
2019-02-25 21:38:37 +03:00
|
|
|
if (!Streamers::write(stream, map)) {
|
|
|
|
return false;
|
2019-02-15 23:36:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
QDataStream stream(data);
|
|
|
|
|
|
|
|
QByteArray hash = map.value("hash", "").toByteArray();
|
2019-02-25 21:38:37 +03:00
|
|
|
int id = map.value("id", 0).toInt();
|
2019-02-15 23:36:59 +03:00
|
|
|
|
|
|
|
if (hash.size() != 32 || !id) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
data.append(hash.data());
|
|
|
|
data.append(reinterpret_cast<char*>(&id), sizeof (id));
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case Login: {
|
|
|
|
|
|
|
|
if (type == Responke) {
|
|
|
|
|
|
|
|
QDataStream stream(data);
|
|
|
|
|
2019-02-25 21:38:37 +03:00
|
|
|
if (!Streamers::write(stream, map)) {
|
2019-02-15 23:36:59 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
QDataStream stream(data);
|
|
|
|
|
|
|
|
QByteArray hash = map.value("hash", "").toByteArray();
|
2019-02-25 21:38:37 +03:00
|
|
|
QString gmail = map.value("gmail", "").toString();
|
2019-02-15 23:36:59 +03:00
|
|
|
|
|
|
|
if (hash.size() != 32 || gmail.isEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream << gmail;
|
|
|
|
stream << hash;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PlayerData: {
|
|
|
|
|
|
|
|
if (type == Responke) {
|
|
|
|
|
|
|
|
QDataStream stream(data);
|
|
|
|
|
2019-02-25 21:38:37 +03:00
|
|
|
if (!Streamers::write(stream, map)) {
|
2019-02-15 23:36:59 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
QDataStream stream(data);
|
|
|
|
|
|
|
|
QByteArray hash = map.value("hash", "").toByteArray();
|
2019-02-25 21:38:37 +03:00
|
|
|
QString gmail = map.value("gmail", "").toString();
|
2019-02-15 23:36:59 +03:00
|
|
|
|
|
|
|
if (hash.size() != 32 || gmail.isEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream << gmail;
|
|
|
|
stream << hash;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
hdr.command = command;
|
|
|
|
hdr.type = type;
|
|
|
|
|
|
|
|
return isValid();
|
2019-02-13 13:03:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray Package::toBytes() const {
|
|
|
|
QByteArray res;
|
|
|
|
res.append(reinterpret_cast<char*>(const_cast<Header*>(&hdr)),
|
|
|
|
sizeof (hdr));
|
|
|
|
|
|
|
|
res.append(data);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Package::reset() {
|
|
|
|
hdr.reset();
|
|
|
|
data.clear();
|
|
|
|
}
|
|
|
|
|
2019-02-25 21:38:37 +03:00
|
|
|
int getSize(SnakeUtils::Type type, bool isMax) {
|
|
|
|
auto size = SnakeUtils::getSizeType(type);
|
|
|
|
if (size) {
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == SnakeUtils::String) {
|
|
|
|
return 255;
|
|
|
|
} else if (type == SnakeUtils::Variant) {
|
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto listPropertyes = networkObjects.value(type);
|
|
|
|
size = 0;
|
|
|
|
for (auto &&i : listPropertyes) {
|
|
|
|
|
|
|
|
if (SnakeUtils::isArray(i)) {
|
|
|
|
SnakeUtils::Type arrayType = static_cast<SnakeUtils::Type>(type & ~SnakeUtils::Array);
|
|
|
|
|
|
|
|
auto sizeItem = SnakeUtils::getSizeType(arrayType);
|
|
|
|
|
|
|
|
if (arrayType == SnakeUtils::String) {
|
|
|
|
sizeItem = 255;
|
|
|
|
} else if (arrayType == SnakeUtils::Variant) {
|
|
|
|
sizeItem = 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
size += sizeItem * ((isMax)? MAX_SIZE: MIN_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
size += getSize(i, isMax);
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isStaticObject(SnakeUtils::Type type, int &max, int &min) {
|
|
|
|
max = getSize(type);
|
|
|
|
min = getSize(type, false);
|
|
|
|
|
|
|
|
return max == min;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isValidSize(SnakeUtils::Type type, int size) {
|
|
|
|
int max;
|
|
|
|
int min;
|
|
|
|
if (isStaticObject(type, max, min)) {
|
|
|
|
return size == max;
|
|
|
|
}
|
|
|
|
|
|
|
|
return size <= max && size >= min;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-02-13 13:03:40 +03:00
|
|
|
}
|