diff --git a/jus/AbstractFunction.cpp b/jus/AbstractFunction.cpp index a6cf6b9..79d66f1 100644 --- a/jus/AbstractFunction.cpp +++ b/jus/AbstractFunction.cpp @@ -261,10 +261,10 @@ ejson::Object jus::createCallJson(uint64_t _transactionId, const std::string& _f return callElem; } -ejson::Object jus::createBaseCall(uint64_t _transactionId, const std::string& _functionName, const std::string& _service) { +ejson::Object jus::createBaseCall(uint64_t _transactionId, const std::string& _functionName, const uint32_t& _serviceId) { ejson::Object obj; - if (_service.size() != 0) { - obj.add("service", ejson::String(_service)); + if (_serviceId != 0) { + obj.add("service", ejson::Number(_serviceId)); } obj.add("call", ejson::String(_functionName)); obj.add("id", ejson::Number(_transactionId)); diff --git a/jus/AbstractFunction.h b/jus/AbstractFunction.h index 42d4f3a..611a7bf 100644 --- a/jus/AbstractFunction.h +++ b/jus/AbstractFunction.h @@ -77,7 +77,7 @@ namespace jus { // ============================================================ // == JSON // ============================================================ - ejson::Object createBaseCall(uint64_t _transactionId, const std::string& _functionName, const std::string& _service=""); + ejson::Object createBaseCall(uint64_t _transactionId, const std::string& _functionName, const uint32_t& _serviceId=0); void createParam(std::vector& _asyncAction, int32_t _paramId, @@ -113,8 +113,8 @@ namespace jus { return callElem; } template - ejson::Object createCallService(std::vector& _asyncAction, uint64_t _transactionId, const std::string& _serviceName, const std::string& _functionName, _ARGS&&... _args) { - ejson::Object callElem = createBaseCall(_transactionId, _functionName, _serviceName); + ejson::Object createCallService(std::vector& _asyncAction, uint64_t _transactionId, const uint32_t& _serviceId, const std::string& _functionName, _ARGS&&... _args) { + ejson::Object callElem = createBaseCall(_transactionId, _functionName, _serviceId); createParam(_asyncAction, 0, callElem, std::forward<_ARGS>(_args)...); return callElem; } diff --git a/jus/Buffer.cpp b/jus/Buffer.cpp index 238c34b..787edab 100644 --- a/jus/Buffer.cpp +++ b/jus/Buffer.cpp @@ -7,17 +7,70 @@ #include #include +namespace etk { + template<> std::string to_string(const enum jus::Buffer::typeMessage& _value) { + switch (_value) { + case jus::Buffer::typeMessage::call: + return "call"; + case jus::Buffer::typeMessage::answer: + return "answer"; + case jus::Buffer::typeMessage::event: + return "event"; + } + return "???"; + } +} +std::ostream& jus::operator <<(std::ostream& _os, const std::vector& _value) { + _os << etk::to_string(_value); + return _os; +} + +static enum jus::Buffer::typeMessage getTypeType(uint16_t _value) { + switch (_value) { + case 1: + return jus::Buffer::typeMessage::call; + case 2: + return jus::Buffer::typeMessage::answer; + case 4: + return jus::Buffer::typeMessage::event; + } + return jus::Buffer::typeMessage::call; +} + jus::Buffer::Buffer() { clear(); } +void jus::Buffer::composeWith(const std::vector& _buffer) { + clear(); + m_header.lenght = _buffer.size(); + memcpy(&m_header + 4, &_buffer[0], sizeof(headerBin)-4); + JUS_INFO("Get binary message : "); + JUS_INFO(" lenght = " << m_header.lenght); + JUS_INFO(" versionProtocol = " << m_header.versionProtocol); + JUS_INFO(" transactionID = " << m_header.transactionID); + JUS_INFO(" clientID = " << m_header.clientID); + JUS_INFO(" partID = " << m_header.partID); + enum jus::Buffer::typeMessage ttype = getTypeType(m_header.typeMessage); + JUS_INFO(" typeMessage = " << ttype); + JUS_TODO(" ..."); +} + void jus::Buffer::clear() { m_data.clear(); m_paramOffset.clear(); m_header.clear(); } std::string jus::Buffer::generateHumanString() { - return "jus::Buffer ..."; + std::string out = "jus::Buffer Lenght=: "; + out += etk::to_string(m_header.lenght); + out += " v=" + etk::to_string(m_header.versionProtocol); + out += " id=" + etk::to_string(m_header.transactionID); + out += " cId=" + etk::to_string(m_header.clientID); + out += " pId=" + etk::to_string(m_header.partID); + enum jus::Buffer::typeMessage type = getTypeType(m_header.typeMessage); + out += " type=" + etk::to_string(type); + return out; } uint16_t jus::Buffer::getProtocalVersion() { @@ -78,6 +131,15 @@ uint16_t jus::Buffer::getNumberParameter() { } +void jus::Buffer::addParameter() { + int32_t currentOffset = m_data.size(); + m_paramOffset.push_back(currentOffset); + m_data.push_back('v'); + m_data.push_back('o'); + m_data.push_back('i'); + m_data.push_back('d'); + m_data.push_back('\0'); +} template<> void jus::Buffer::addParameter(const std::string& _value) { int32_t currentOffset = m_data.size(); @@ -223,6 +285,21 @@ void jus::Buffer::addParameter(const double& _value) { m_data.resize(m_data.size()+8); memcpy(&m_data[currentOffset], &_value, 8); } +template<> +void jus::Buffer::addParameter(const bool& _value) { + int32_t currentOffset = m_data.size(); + m_paramOffset.push_back(currentOffset); + m_data.push_back('b'); + m_data.push_back('o'); + m_data.push_back('o'); + m_data.push_back('l'); + m_data.push_back('\0'); + if (_value == true) { + m_data.push_back('T'); + } else { + m_data.push_back('F'); + } +} template<> std::string jus::Buffer::internalGetParameter(int32_t _id) { @@ -302,7 +379,11 @@ int8_t jus::Buffer::internalGetParameter(int32_t _id) { } - +void jus::Buffer::addError(const std::string& _value, const std::string& _comment) { + addParameter(); + addParameter(_value); + addParameter(_comment); +} std::string jus::Buffer::getCall() { std::string out; diff --git a/jus/Buffer.h b/jus/Buffer.h index 08ea06d..49f0aa7 100644 --- a/jus/Buffer.h +++ b/jus/Buffer.h @@ -29,6 +29,7 @@ namespace jus { ====================== == call ====================== + U16 param count U16[param count] parameters offset (first offset is the "callName" and limit size of the number of parameter CALL Name (funtion name) [param 1] @@ -38,8 +39,11 @@ namespace jus { ====================== == Answer ====================== - U16 ErrorOffset - [return value 1] + U16 param count = 3 + U16[param count] + [param 1] (return value) + [param 2] (error value) + [param 3] (error help) [error] (constituated with 2 strings (error type and comment) ====================== == event @@ -86,8 +90,28 @@ namespace jus { headerBin m_header; std::vector m_paramOffset; std::vector m_data; + public: + const uint8_t* getHeader() const { + return reinterpret_cast(&m_header); + } + uint32_t getHeaderSize() const { + return sizeof(headerBin); + } + const uint8_t* getParam() const { + return reinterpret_cast(&m_paramOffset[0]); + } + uint32_t getParamSize() const { + return m_paramOffset.size() * 2; + } + const uint8_t* getData() const { + return &m_data[0]; + } + uint32_t getDataSize() const { + return m_data.size(); + } public: Buffer(); + void composeWith(const std::vector& _buffer); std::string generateHumanString(); void clear(); uint16_t getProtocalVersion(); @@ -114,6 +138,7 @@ namespace jus { }; enum typeMessage getType(); void setType(enum typeMessage _value); + // =============================================== // == Section call // =============================================== @@ -127,6 +152,7 @@ namespace jus { template void addParameter(const JUS_TYPE_DATA& _value); + void addParameter(); template JUS_TYPE_DATA getParameter(int32_t _id) { @@ -139,7 +165,11 @@ namespace jus { // =============================================== public: template - void addAnswer(const JUS_TYPE_DATA& _value); + void addAnswer(const JUS_TYPE_DATA& _value) { + addParameter(_value); + } + void addError(const std::string& _value, const std::string& _comment); }; + std::ostream& operator <<(std::ostream& _os, const std::vector& _value); } diff --git a/jus/Client.cpp b/jus/Client.cpp index 0015a67..624d24d 100644 --- a/jus/Client.cpp +++ b/jus/Client.cpp @@ -146,6 +146,15 @@ bool jus::Client::connect(const std::string& _remoteUserToConnect){ enet::Tcp connection = std::move(enet::connectTcpClient(*propertyIp, *propertyPort)); m_interfaceClient.setInterface(std::move(connection)); m_interfaceClient.connect(); + // Force mode binary: + jus::Future retBin = call("setMode", "BIN").wait(); + if (retBin.get() == true) { + m_interfaceMode = jus::connectionMode::modeBinary; + JUS_INFO("Connection jump in BINARY ..."); + } else { + // stay in JSON + } + jus::Future ret = call("connectToUser", _remoteUserToConnect, "jus-client"); ret.wait(); if (ret.hasError() == true) { diff --git a/jus/FutureBase.cpp b/jus/FutureBase.cpp index 1cf4dcd..70f47fd 100644 --- a/jus/FutureBase.cpp +++ b/jus/FutureBase.cpp @@ -25,6 +25,7 @@ jus::FutureBase::FutureBase(uint64_t _transactionId, jus::FutureData::ObserverFi m_data->m_transactionId = _transactionId; m_data->m_isFinished = false; m_data->m_isSynchronous = false; + m_data->m_mode = false; m_data->m_callbackFinish = _callback; } @@ -44,6 +45,7 @@ jus::FutureBase::FutureBase(uint64_t _transactionId, bool _isFinished, ejson::Ob m_data->m_transactionId = _transactionId; m_data->m_isFinished = _isFinished; m_data->m_isSynchronous = false; + m_data->m_mode = false; m_data->m_returnData = _returnData; m_data->m_callbackFinish = _callback; if (m_data->m_isFinished == true) { @@ -54,6 +56,25 @@ jus::FutureBase::FutureBase(uint64_t _transactionId, bool _isFinished, ejson::Ob } } +jus::FutureBase::FutureBase(uint64_t _transactionId, bool _isFinished, jus::Buffer _returnData, jus::FutureData::ObserverFinish _callback) { + m_data = std::make_shared(); + if (m_data == nullptr) { + return; + } + m_data->m_sendTime = std::chrono::steady_clock::now(); + m_data->m_transactionId = _transactionId; + m_data->m_isFinished = _isFinished; + m_data->m_isSynchronous = false; + m_data->m_mode = true; + m_data->m_returnDataBinary = _returnData; + m_data->m_callbackFinish = _callback; + if (m_data->m_isFinished == true) { + m_data->m_receiveTime = std::chrono::steady_clock::now(); + if (m_data->m_callbackFinish != nullptr) { + m_data->m_callbackFinish(*this); + } + } +} std::chrono::nanoseconds jus::FutureBase::getTransmitionTime() { if (m_data == nullptr) { return std::chrono::nanoseconds(0); @@ -74,6 +95,7 @@ bool jus::FutureBase::setAnswer(const ejson::Object& _returnValue) { JUS_ERROR(" Not a valid future ..."); return true; } + m_data->m_mode = false; m_data->m_receiveTime = std::chrono::steady_clock::now(); if (m_data->m_isSynchronous == true) { m_data->m_returnData = _returnValue; @@ -108,6 +130,48 @@ bool jus::FutureBase::setAnswer(const ejson::Object& _returnValue) { } return true; } +bool jus::FutureBase::setAnswer(const jus::Buffer& _returnValue) { + if (m_data == nullptr) { + JUS_ERROR(" Not a valid future ..."); + return true; + } + m_data->m_mode = true; + m_data->m_receiveTime = std::chrono::steady_clock::now(); + if (m_data->m_isSynchronous == true) { + m_data->m_returnDataBinary = _returnValue; + if (m_data->m_callbackFinish != nullptr) { + return m_data->m_callbackFinish(*this); + } + return true; + } + /* TODO : ... + if (_returnValue.valueExist("part") == true) { + uint64_t idPart = _returnValue["part"].toNumber().getU64(); + if (idPart == 0) { + m_data->m_returnData = _returnValue; + } else { + m_data->m_returnDataPart.push_back(_returnValue["data"]); + } + if (_returnValue.valueExist("finish") == true) { + if (_returnValue["finish"].toBoolean().get() == true) { + m_data->m_isFinished = true; + if (m_data->m_callbackFinish != nullptr) { + return m_data->m_callbackFinish(*this); + } + return true; + } + // finish is false ==> normal case ... + } + return false; + } + m_data->m_returnData = _returnValue; + m_data->m_isFinished = true; + if (m_data->m_callbackFinish != nullptr) { + return m_data->m_callbackFinish(*this); + } + */ + return true; +} void jus::FutureBase::setSynchronous() { if (m_data == nullptr) { return; diff --git a/jus/FutureData.h b/jus/FutureData.h index f5bdbcf..f9fe61e 100644 --- a/jus/FutureData.h +++ b/jus/FutureData.h @@ -19,6 +19,7 @@ namespace jus { uint64_t m_transactionId; bool m_isSynchronous; bool m_isFinished; + bool m_mode; ejson::Object m_returnData; jus::Buffer m_returnDataBinary; std::vector m_returnDataPart; diff --git a/jus/GateWayClient.cpp b/jus/GateWayClient.cpp index 7661073..e3e6550 100644 --- a/jus/GateWayClient.cpp +++ b/jus/GateWayClient.cpp @@ -12,10 +12,14 @@ #include + +static const std::string protocolError = "PROTOCOL-ERROR"; + jus::GateWayClient::GateWayClient(enet::Tcp _connection, jus::GateWay* _gatewayInterface) : m_state(jus::GateWayClient::state::unconnect), m_gatewayInterface(_gatewayInterface), m_interfaceClient(std::move(_connection)), + m_interfaceMode(jus::connectionMode::modeJson), m_transactionLocalId(1) { JUS_INFO("----------------"); JUS_INFO("-- NEW Client --"); @@ -45,12 +49,16 @@ void jus::GateWayClient::stop() { continue; } ejson::Object linkService; - linkService.add("event", ejson::String("delete")); + linkService.add("call", ejson::String("_delete")); + linkService.add("id", ejson::Number(m_transactionLocalId++)); + linkService.add("param", ejson::Array()); it->SendData(m_uid, linkService); } if (m_userService != nullptr) { ejson::Object linkService; - linkService.add("event", ejson::String("delete")); + linkService.add("call", ejson::String("_delete")); + linkService.add("id", ejson::Number(m_transactionLocalId++)); + linkService.add("param", ejson::Array()); m_userService->SendData(m_uid2, linkService); m_userService = nullptr; } @@ -62,23 +70,42 @@ bool jus::GateWayClient::isAlive() { return m_interfaceClient.isActive(); } -void jus::GateWayClient::protocolError(const std::string& _errorHelp) { - ejson::Object answer; - answer.add("error", ejson::String("PROTOCOL-ERROR")); - answer.add("error-help", ejson::String(_errorHelp)); - JUS_DEBUG("answer: " << answer.generateHumanString()); - m_interfaceClient.write(answer.generateMachineString()); +void jus::GateWayClient::answerProtocolError(uint32_t _transactionId, const std::string& _errorHelp) { + answerError(_transactionId, protocolError, _errorHelp); m_state = jus::GateWayClient::state::disconnect; m_interfaceClient.disconnect(true); } - -void jus::GateWayClient::returnBool(int32_t _transactionId, bool _value) { +/* +void jus::GateWayClient::answerValue(int32_t _transactionId, bool _value) { ejson::Object answer; answer.add("id", ejson::Number(_transactionId)); answer.add("return", ejson::Boolean(_value)); JUS_DEBUG("answer: " << answer.generateHumanString()); m_interfaceClient.write(answer.generateMachineString()); } +*/ + +void jus::GateWayClient::answerError(uint64_t _clientTransactionId, const std::string& _errorValue, const std::string& _errorHelp) { + if (m_interfaceMode == jus::connectionMode::modeJson) { + ejson::Object answer; + answer.add("error", ejson::String(protocolError)); + answer.add("id", ejson::Number(_clientTransactionId)); + answer.add("error-help", ejson::String(_errorHelp)); + JUS_DEBUG("answer: " << answer.generateHumanString()); + m_interfaceClient.write(answer.generateMachineString()); + } else if (m_interfaceMode == jus::connectionMode::modeBinary) { + jus::Buffer answer; + answer.setType(jus::Buffer::typeMessage::answer); + answer.setTransactionId(_clientTransactionId); + answer.addError(protocolError, _errorHelp); + JUS_DEBUG("answer: " << answer.generateHumanString()); + m_interfaceClient.writeBinary(answer); + } else if (m_interfaceMode == jus::connectionMode::modeXml) { + JUS_ERROR("TODO ... "); + } else { + JUS_ERROR("wrong type of communication"); + } +} void jus::GateWayClient::onClientDataRaw(const jus::Buffer& _value) { @@ -90,7 +117,7 @@ void jus::GateWayClient::onClientData(std::string _value) { uint64_t transactionId = data["id"].toNumber().getU64(); if (transactionId == 0) { JUS_ERROR("Protocol error ==>missing id"); - protocolError("missing parameter: 'id'"); + answerProtocolError(transactionId, "missing parameter: 'id'"); return; } switch (m_state) { @@ -98,13 +125,13 @@ void jus::GateWayClient::onClientData(std::string _value) { case jus::GateWayClient::state::unconnect: { JUS_ERROR("Must never appear"); - protocolError("Gateway internal error"); + answerProtocolError(transactionId, "Gateway internal error"); return; } case jus::GateWayClient::state::connect: { if (m_userConnectionName != "") { - protocolError("Gateway internal error 2"); + answerProtocolError(transactionId, "Gateway internal error 2"); return; } std::string call = data["call"].toString().get(); @@ -112,46 +139,52 @@ void jus::GateWayClient::onClientData(std::string _value) { std::string mode = data["param"].toArray()[0].toString().get(); if (mode == "JSON") { JUS_WARNING("[" << m_uid << "] Change mode in: JSON"); + m_interfaceMode = jus::connectionMode::modeJson; m_interfaceClient.connectCleanRaw(); m_interfaceClient.connect(this, &jus::GateWayClient::onClientData); - returnBool(transactionId, true); + answerValue(transactionId, true); } else if (mode == "BIN") { JUS_WARNING("[" << m_uid << "] Change mode in: BINARY"); + m_interfaceMode = jus::connectionMode::modeBinary; m_interfaceClient.connectClean(); m_interfaceClient.connectRaw(this, &jus::GateWayClient::onClientDataRaw); - returnBool(transactionId, true); + answerValue(transactionId, true); } else if (mode == "XML") { JUS_WARNING("[" << m_uid << "] Change mode in: XML"); - returnBool(transactionId, false); + //m_interfaceMode = jus::connectionMode::modeXml; + answerValue(transactionId, false); } else { - protocolError(std::string("Call setMode with unknow argument : '") /*+ etk::to_string(int32_t(mode))*/ + "' supported [JSON/XML/BIN]"); + answerProtocolError(transactionId, std::string("Call setMode with unknow argument : '") /*+ etk::to_string(int32_t(mode))*/ + "' supported [JSON/XML/BIN]"); } return; } else if (call == "connectToUser") { m_userConnectionName = data["param"].toArray()[0].toString().get(); if (m_userConnectionName == "") { - protocolError("Call connectToUser with no parameter 'user'"); + answerProtocolError(transactionId, "Call connectToUser with no parameter 'user'"); } else { JUS_WARNING("[" << m_uid << "] Set client connect to user : '" << m_userConnectionName << "'"); m_userService = m_gatewayInterface->get("system-user"); if (m_userService == nullptr) { - protocolError("Gateway internal error 'No user interface'"); + answerProtocolError(transactionId, "Gateway internal error 'No user interface'"); } else { ejson::Object linkService; - linkService.add("event", ejson::String("new")); - linkService.add("user", ejson::String(m_userConnectionName)); - linkService.add("client", ejson::String("**Gateway**")); - linkService.add("groups", ejson::Array()); + linkService.add("call", ejson::String("_new")); + linkService.add("id", ejson::Number(m_transactionLocalId++)); + ejson::Array params; + params.add(ejson::String(m_userConnectionName)); + params.add(ejson::String("**Gateway**")); + params.add(ejson::Array()); + linkService.add("param", params); m_userService->SendData(m_uid2, linkService); m_state = jus::GateWayClient::state::userIdentify; - returnBool(transactionId, true); + answerValue(transactionId, true); } } return; } JUS_WARNING("[" << m_uid << "] Client must send conection to user name ..."); - protocolError("Missing call of connectToUser"); + answerProtocolError(transactionId, "Missing call of connectToUser"); return; } case jus::GateWayClient::state::userIdentify: @@ -164,26 +197,26 @@ void jus::GateWayClient::onClientData(std::string _value) { if ( callFunction != "identify" && callFunction != "auth" && callFunction != "anonymous") { - protocolError("Client must call: identify/auth/anonymous"); + answerProtocolError(transactionId, "Client must call: identify/auth/anonymous"); return; } if (callFunction == "identify") { std::string clientName = data["param"].toArray()[0].toString().get(); std::string clientTocken = data["param"].toArray()[1].toString().get(); if (m_userService == nullptr) { - protocolError("gateWay internal error 3"); + answerProtocolError(transactionId, "gateWay internal error 3"); return; } jus::Future fut = call(m_uid2, m_userService, "checkTocken", clientName, clientTocken); fut.wait(); // TODO: Set timeout ... if (fut.hasError() == true) { JUS_ERROR("Get error from the service ..."); - returnBool(transactionId, false); - protocolError("connection refused 1"); + answerValue(transactionId, false); + answerProtocolError(transactionId, "connection refused 1"); return; } else if (fut.get() == false) { - returnBool(transactionId, false); - protocolError("connection refused 2"); + answerValue(transactionId, false); + answerProtocolError(transactionId, "connection refused 2"); return; } m_clientName = clientName; @@ -194,12 +227,12 @@ void jus::GateWayClient::onClientData(std::string _value) { fut.wait(); // TODO: Set timeout ... if (fut.hasError() == true) { JUS_ERROR("Get error from the service ..."); - returnBool(transactionId, false); - protocolError("connection refused 1"); + answerValue(transactionId, false); + answerProtocolError(transactionId, "connection refused 1"); return; } else if (fut.get() == false) { - returnBool(transactionId, false); - protocolError("connection refused 2"); + answerValue(transactionId, false); + answerProtocolError(transactionId, "connection refused 2"); return; } m_clientName = m_userConnectionName; @@ -214,8 +247,8 @@ void jus::GateWayClient::onClientData(std::string _value) { futGroup.wait(); // TODO: Set timeout ... if (futGroup.hasError() == true) { JUS_ERROR("Get error from the service ..."); - returnBool(transactionId, false); - protocolError("grouping error"); + answerValue(transactionId, false); + answerProtocolError(transactionId, "grouping error"); return; } m_clientgroups = futGroup.get(); @@ -227,8 +260,8 @@ void jus::GateWayClient::onClientData(std::string _value) { futServices.wait(); // TODO: Set timeout ... if (futServices.hasError() == true) { JUS_ERROR("Get error from the service ..."); - returnBool(transactionId, false); - protocolError("service filtering error"); + answerValue(transactionId, false); + answerProtocolError(transactionId, "service filtering error"); return; } m_clientServices = futServices.get(); @@ -237,7 +270,7 @@ void jus::GateWayClient::onClientData(std::string _value) { JUS_WARNING(" services: " << etk::to_string(m_clientServices)); - returnBool(transactionId, true); + answerValue(transactionId, true); m_state = jus::GateWayClient::state::clientIdentify; return; } @@ -250,7 +283,6 @@ void jus::GateWayClient::onClientData(std::string _value) { // This is 2 default service for the cient interface that manage the authorisation of view: std::string callFunction = data["call"].toString().get(); ejson::Object answer; - //answer.add("from-service", ejson::String("")); answer.add("id", data["id"]); if (callFunction == "getServiceCount") { answer.add("return", ejson::Number(m_clientServices.size())); @@ -296,18 +328,21 @@ void jus::GateWayClient::onClientData(std::string _value) { ememory::SharedPtr srv = m_gatewayInterface->get(serviceName); if (srv != nullptr) { ejson::Object linkService; - linkService.add("event", ejson::String("new")); - linkService.add("user", ejson::String(m_userConnectionName)); - linkService.add("client", ejson::String(m_clientName)); + linkService.add("call", ejson::String("_new")); + linkService.add("id", ejson::Number(m_transactionLocalId++)); + ejson::Array params; + params.add(ejson::String(m_userConnectionName)); + params.add(ejson::String(m_clientName)); // TODO ==> remove events ... std::vector asyncAction; - linkService.add("groups", convertToJson(asyncAction, 0, m_clientgroups)); + params.add(convertToJson(asyncAction, 0, m_clientgroups)); + linkService.add("param", params); if (asyncAction.size() != 0) { JUS_ERROR("Missing send async messages"); } srv->SendData(m_uid, linkService); m_listConnectedService.push_back(srv); - answer.add("return", ejson::Number(m_listConnectedService.size()-1)); + answer.add("return", ejson::Number(m_listConnectedService.size())); } else { answer.add("error", ejson::String("CAN-NOT-CONNECT-SERVICE")); } @@ -321,7 +356,7 @@ void jus::GateWayClient::onClientData(std::string _value) { } if (callFunction == "unlink") { // first param: - int64_t localServiceID = data["param"].toArray()[0].toNumber().getI64(); + int64_t localServiceID = data["param"].toArray()[0].toNumber().getI64()-1; // Check if service already link: if (localServiceID >= m_listConnectedService.size()) { answer.add("error", ejson::String("NOT-CONNECTED-SERVICE")); @@ -330,8 +365,10 @@ void jus::GateWayClient::onClientData(std::string _value) { return; } ejson::Object linkService; - // TODO : Change event in call ... - linkService.add("event", ejson::String("delete")); // TODO : ************************************************** + linkService.add("call", ejson::String("_delete")); + linkService.add("id", ejson::Number(m_transactionLocalId++)); + ejson::Array params; + linkService.add("param", params); m_listConnectedService[localServiceID]->SendData(m_uid, linkService); m_listConnectedService[localServiceID] = nullptr; answer.add("return", ejson::Boolean(true)); @@ -346,8 +383,10 @@ void jus::GateWayClient::onClientData(std::string _value) { return; } - uint64_t serviceId = numService.getU64(); + uint64_t serviceId = numService.getU64()-1; if (serviceId >= m_listConnectedService.size()) { + ejson::Object answer; + answer.add("id", data["id"]); answer.add("error", ejson::String("NOT-CONNECTED-SERVICE")); JUS_DEBUG("answer: " << answer.generateHumanString()); m_interfaceClient.write(answer.generateMachineString()); diff --git a/jus/GateWayClient.h b/jus/GateWayClient.h index 032fc16..3e839ab 100644 --- a/jus/GateWayClient.h +++ b/jus/GateWayClient.h @@ -11,6 +11,7 @@ #include #include #include +#include @@ -29,8 +30,10 @@ namespace jus { private: jus::GateWay* m_gatewayInterface; jus::TcpString m_interfaceClient; - void protocolError(const std::string& _errorHelp); - void returnBool(int32_t _transactionId, bool _value); + protected: + enum jus::connectionMode m_interfaceMode; + public: + enum jus::connectionMode getMode() { return m_interfaceMode; } public: esignal::Signal signalIsConnected; ememory::SharedPtr m_userService; @@ -91,6 +94,38 @@ namespace jus { jus::FutureData::ObserverFinish _callback, int64_t _part, bool _finish); + + void answerProtocolError(uint32_t _transactionId, const std::string& _errorHelp); + + template + void answerValue(uint64_t _clientTransactionId, JUS_ARG _value) { + if (m_interfaceMode == jus::connectionMode::modeJson) { + ejson::Object answer; + answer.add("id", ejson::Number(_clientTransactionId)); + std::vector asyncAction; + answer.add("return", jus::convertToJson(asyncAction, -1, _value)); + if (asyncAction.size() != 0) { + JUS_ERROR("ASYNC datas ... TODO ///"); + } + JUS_DEBUG("answer: " << answer.generateHumanString()); + m_interfaceClient.write(answer.generateMachineString()); + } else if (m_interfaceMode == jus::connectionMode::modeBinary) { + jus::Buffer answer; + answer.setType(jus::Buffer::typeMessage::answer); + answer.setTransactionId(_clientTransactionId); + answer.addAnswer(_value); + JUS_DEBUG("answer: " << answer.generateHumanString()); + m_interfaceClient.writeBinary(answer); + } else if (m_interfaceMode == jus::connectionMode::modeXml) { + JUS_ERROR("TODO ... "); + } else { + JUS_ERROR("wrong type of communication"); + } + } + + void answerError(uint64_t _clientTransactionId, const std::string& _errorValue, const std::string& _errorComment=""); + + }; } diff --git a/jus/Service.cpp b/jus/Service.cpp index 1527556..63d35ea 100644 --- a/jus/Service.cpp +++ b/jus/Service.cpp @@ -116,7 +116,7 @@ void jus::Service::callJson(uint64_t _transactionId, const ejson::Object& _obj) uint64_t clientId = _obj["client-id"].toNumber().getU64(); if (_obj.valueExist("call") == true) { std::string call = _obj["call"].toString().get(); - ejson::Array params = _obj["param"].toArray() + ejson::Array params = _obj["param"].toArray(); if (call[0] == '_') { if (call == "_new") { std::string userName = params[0].toString().get(); @@ -126,6 +126,13 @@ void jus::Service::callJson(uint64_t _transactionId, const ejson::Object& _obj) } else if (call == "_delete") { clientDisconnect(clientId); } + // TODO : Do it better ... + answer.add("id", ejson::Number(_transactionId)); + answer.add("client-id", ejson::Number(clientId)); + answer.add("return", ejson::Boolean(true)); + JUS_INFO("Answer: " << answer.generateHumanString()); + m_interfaceClient->write(answer.generateMachineString()); + return; } else if (isFunctionAuthorized(clientId, call) == true) { callJson2(_transactionId, clientId, call, params); return; diff --git a/jus/ServiceRemote.cpp b/jus/ServiceRemote.cpp index 0057ed7..585e8ac 100644 --- a/jus/ServiceRemote.cpp +++ b/jus/ServiceRemote.cpp @@ -48,7 +48,7 @@ jus::FutureBase jus::ServiceRemote::callJson(uint64_t _transactionId, } jus::FutureBase jus::ServiceRemote::callBinary(uint64_t _transactionId, - const jus::Buffer& _obj, + jus::Buffer& _obj, const std::vector& _async, jus::FutureData::ObserverFinish _callback) { return m_clientInterface->callBinary(_transactionId, _obj, _async, _callback, m_serviceId); diff --git a/jus/ServiceRemote.h b/jus/ServiceRemote.h index 32024de..5f5fd80 100644 --- a/jus/ServiceRemote.h +++ b/jus/ServiceRemote.h @@ -28,7 +28,7 @@ namespace jus { bool exist(); private: jus::FutureBase callJson(uint64_t _transactionId, const ejson::Object& _obj, const std::vector& _async, jus::FutureData::ObserverFinish _callback=nullptr); - jus::FutureBase callBinary(uint64_t _transactionId, const jus::Buffer& _obj, const std::vector& _async, jus::FutureData::ObserverFinish _callback=nullptr); + jus::FutureBase callBinary(uint64_t _transactionId, jus::Buffer& _obj, const std::vector& _async, jus::FutureData::ObserverFinish _callback=nullptr); uint64_t getId(); enum jus::connectionMode getMode(); public: diff --git a/jus/TcpString.cpp b/jus/TcpString.cpp index 995fab5..9b84af8 100644 --- a/jus/TcpString.cpp +++ b/jus/TcpString.cpp @@ -55,9 +55,7 @@ void jus::TcpString::threadCallback() { } } else if (m_observerRawElement != nullptr) { jus::Buffer data = std::move(readRaw()); - if (data.size() != 0) { - m_observerRawElement(std::move(data)); - } + m_observerRawElement(std::move(data)); } } m_threadRunning = false; @@ -136,6 +134,28 @@ int32_t jus::TcpString::write(const std::string& _data) { m_connection.write(&size, 4); return m_connection.write(_data.c_str(), _data.size()); } +int32_t jus::TcpString::writeBinary(const jus::Buffer& _data) { + if (m_threadRunning == false) { + return -2; + } + /* + if (_data.size() == 0) { + return 0; + } + */ + //uint32_t size = _data.size(); + m_lastSend = std::chrono::steady_clock::now(); + const uint8_t* data = _data.getHeader(); + uint32_t dataSize = _data.getHeaderSize(); + m_connection.write(data, dataSize); + data = _data.getParam(); + dataSize = _data.getParamSize(); + m_connection.write(data, dataSize); + data = _data.getData(); + dataSize = _data.getDataSize(); + m_connection.write(data, dataSize); + return 1; +} std::string jus::TcpString::read() { JUS_VERBOSE("Read [START]"); @@ -177,6 +197,45 @@ std::string jus::TcpString::read() { return out; } +jus::Buffer jus::TcpString::readRaw() { + jus::Buffer out; + JUS_VERBOSE("ReadRaw [START]"); + if (m_threadRunning == false) { + JUS_DEBUG("Read [END] Disconected"); + return out; + } + JUS_VERBOSE("ReadRaw [START]"); + uint32_t size = 0; + int32_t len = m_connection.read(&size, 4); + if (len != 4) { + JUS_ERROR("Protocol error occured ..."); + } else { + if (size == -1) { + JUS_WARNING("Remote close connection"); + m_threadRunning = false; + //m_connection.unlink(); + } else { + int64_t offset = 0; + m_buffer.resize(size); + while (offset != size) { + len = m_connection.read(&m_buffer[offset], size-offset); + offset += len; + if (len == 0) { + JUS_WARNING("Read No data"); + //break; + } + /* + else if (size != offset) { + JUS_ERROR("Protocol error occured .2. ==> concat (offset=" << offset << " size=" << size); + } + */ + } + out.composeWith(m_buffer); + } + } + JUS_VERBOSE("ReadRaw [STOP]"); + return out; +} void jus::TcpString::threadAsyncCallback() { ethread::setName("Async-sender"); diff --git a/jus/TcpString.h b/jus/TcpString.h index a991489..cab4967 100644 --- a/jus/TcpString.h +++ b/jus/TcpString.h @@ -62,6 +62,8 @@ namespace jus { std::string asyncRead(); private: std::string read(); + jus::Buffer readRaw(); + std::vector m_buffer; private: void threadCallback(); public: diff --git a/test/client/appl/main.cpp b/test/client/appl/main.cpp index 16853b0..0ab5eba 100644 --- a/test/client/appl/main.cpp +++ b/test/client/appl/main.cpp @@ -86,7 +86,7 @@ int main(int _argc, const char *_argv[]) { APPL_INFO("serviceTest1.mul = " << retCall); } */ - if (false) { + if (true) { APPL_INFO(" ----------------------------------"); APPL_INFO(" -- Get service system-user"); APPL_INFO(" ----------------------------------"); @@ -182,6 +182,7 @@ int main(int _argc, const char *_argv[]) { } } */ + #if 0 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); jus::File tmp("./photo_2016_33913.bmp");//"image/jpg", {0,5,2,6,7,5,8,4,5,2,1,5,65,5,2,6,85,4,6,6,54,65,88,64,14,6,4,64,51,3,16,4}); int32_t size = tmp.getData().size(); @@ -190,6 +191,7 @@ int main(int _argc, const char *_argv[]) { APPL_WARNING(" IO*=" << int64_t((stop-start).count()/1000)/1000.0 << " ms"); double megaParSec = double(size)/(double((stop-start).count())/1000000000.0); APPL_WARNING(" speed=" << int64_t(megaParSec/1024.0)/1024.0 << " Mo/s"); + #endif } int32_t iii=0; while (iii < 3) {