From 5028352541a5f1b3be9fd567ce84824d13084891 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Wed, 25 May 2016 21:25:33 +0200 Subject: [PATCH] [DEV] better interfacing --- jus/AbstractFunction.cpp | 36 ++- jus/Client.cpp | 5 +- jus/Client.h | 7 +- jus/GateWay.cpp | 2 +- jus/GateWayClient.cpp | 206 +++++++++++++----- jus/GateWayClient.h | 9 + jus/GateWayService.cpp | 10 +- jus/GateWayService.h | 2 +- jus/ParamType.cpp | 13 ++ jus/Service.cpp | 60 ++--- jus/Service.h | 64 +++++- jus/ServiceRemote.cpp | 10 +- jus/ServiceRemote.h | 2 + jus/TcpString.cpp | 2 + jus/TcpString.h | 9 + lutinParseSubFolders.txt | 2 +- test/client/appl/main.cpp | 23 +- test1#atria-soft.com.json | 8 + tools/system-service/appl/main.cpp | 137 ------------ .../appl/debug.cpp | 0 .../appl/debug.h | 0 tools/system-user/appl/main.cpp | 199 +++++++++++++++++ .../lutin_jus-system-user.py} | 1 + 23 files changed, 566 insertions(+), 241 deletions(-) create mode 100644 test1#atria-soft.com.json delete mode 100644 tools/system-service/appl/main.cpp rename tools/{system-service => system-user}/appl/debug.cpp (100%) rename tools/{system-service => system-user}/appl/debug.h (100%) create mode 100644 tools/system-user/appl/main.cpp rename tools/{system-service/lutin_jus-system-service.py => system-user/lutin_jus-system-user.py} (88%) diff --git a/jus/AbstractFunction.cpp b/jus/AbstractFunction.cpp index 724769c..06a6004 100644 --- a/jus/AbstractFunction.cpp +++ b/jus/AbstractFunction.cpp @@ -9,6 +9,13 @@ namespace jus { template<> bool convertJsonTo(const ejson::Value& _value) { return _value.toBoolean().get(); } + template<> std::vector convertJsonTo>(const ejson::Value& _value) { + std::vector out; + for (const auto it : _value.toArray()) { + out.push_back(convertJsonTo(it)); + } + return out; + } template<> float convertJsonTo(const ejson::Value& _value) { return _value.toNumber().get(); } @@ -19,7 +26,6 @@ namespace jus { return int64_t(_value.toNumber().get()); } template<> int32_t convertJsonTo(const ejson::Value& _value) { - //_value.display(); return int32_t(_value.toNumber().get()); } template<> int16_t convertJsonTo(const ejson::Value& _value) { @@ -41,13 +47,26 @@ namespace jus { return uint8_t(_value.toNumber().get()); } template<> std::string convertJsonTo(const ejson::Value& _value) { - //_value.display(); return _value.toString().get(); } + template<> std::vector convertJsonTo>(const ejson::Value& _value) { + std::vector out; + for (const auto it : _value.toArray()) { + out.push_back(convertJsonTo(it)); + } + return out; + } template<> ejson::Value convertToJson(const bool& _value) { return ejson::Boolean(_value); } + template<> ejson::Value convertToJson>(const std::vector& _value) { + ejson::Array out; + for (const auto &it : _value) { + out.add(ejson::Boolean(it)); + } + return out; + } template<> ejson::Value convertToJson(const float& _value) { return ejson::Number(_value); } @@ -81,6 +100,13 @@ namespace jus { template<> ejson::Value convertToJson(const std::string& _value) { return ejson::String(_value); } + template<> ejson::Value convertToJson>(const std::vector& _value) { + ejson::Array out; + for (auto &it : _value) { + out.add(ejson::String(it)); + } + return out; + } template<> bool convertStringTo(const std::string& _value) { return etk::string_to_bool(_value); @@ -118,6 +144,12 @@ namespace jus { template<> std::string convertStringTo(const std::string& _value) { return _value; } + template<> std::vector convertStringTo>(const std::string& _value) { + std::vector out; + JUS_TODO("Convert string to vs"); + return out; + } + } const std::string& jus::AbstractFunction::getName() const { diff --git a/jus/Client.cpp b/jus/Client.cpp index 7eac316..1c192de 100644 --- a/jus/Client.cpp +++ b/jus/Client.cpp @@ -13,7 +13,7 @@ jus::Client::Client() : propertyIp(this, "ip", "127.0.0.1", "Ip to connect server", &jus::Client::onPropertyChangeIp), propertyPort(this, "port", 1983, "Port to connect server", &jus::Client::onPropertyChangePort), - m_id(0) { + m_id(1) { m_interfaceClient.connect(this, &jus::Client::onClientData); } @@ -29,12 +29,13 @@ jus::ServiceRemote jus::Client::getService(const std::string& _name) { return jus::ServiceRemote(this, _name); } -void jus::Client::link(const std::string& _serviceName) { +bool jus::Client::link(const std::string& _serviceName) { // TODO : Check the number of connection of this service ... bool ret = call_b("link", _serviceName); if (ret == false) { JUS_ERROR("Can not link with the service named: '" << _serviceName << "'"); } + return ret; } void jus::Client::unlink(const std::string& _serviceName) { diff --git a/jus/Client.h b/jus/Client.h index d652811..1336c30 100644 --- a/jus/Client.h +++ b/jus/Client.h @@ -28,8 +28,13 @@ namespace jus { void disconnect(); public: jus::ServiceRemote getService(const std::string& _serviceName); - void link(const std::string& _serviceName); + bool link(const std::string& _serviceName); void unlink(const std::string& _serviceName); + + // Connect that is not us + //bool identify("clientTest1#atria-soft.com", "QSDQSDGQSF54HSXWVCSQDJ654URTDJ654NBXCDFDGAEZ51968"); + // Connect to ourself: + //client1.authentificate("coucou"); private: void onClientData(std::string _value); std::string asyncRead(); diff --git a/jus/GateWay.cpp b/jus/GateWay.cpp index ad928f6..ce0dd09 100644 --- a/jus/GateWay.cpp +++ b/jus/GateWay.cpp @@ -122,7 +122,7 @@ void jus::GateWay::answer(uint64_t _userSessionId, ejson::Object _data) { if (it == nullptr) { continue; } - if (it->getId() != _userSessionId) { + if (it->getId() != std::abs(_userSessionId)) { continue; } it->returnMessage(_data); diff --git a/jus/GateWayClient.cpp b/jus/GateWayClient.cpp index 4b52821..252eb38 100644 --- a/jus/GateWayClient.cpp +++ b/jus/GateWayClient.cpp @@ -12,7 +12,8 @@ jus::GateWayClient::GateWayClient(enet::Tcp _connection, jus::GateWay* _gatewayInterface) : m_gatewayInterface(_gatewayInterface), - m_interfaceClient(std::move(_connection)) { + m_interfaceClient(std::move(_connection)), + m_transactionLocalId(-1) { JUS_INFO("----------------"); JUS_INFO("-- NEW Client --"); JUS_INFO("----------------"); @@ -38,7 +39,15 @@ void jus::GateWayClient::stop() { if (it == nullptr) { continue; } - it->SendData(m_uid, ejson::Object(), "delete"); + ejson::Object linkService; + linkService.add("event", ejson::String("delete")); + it->SendData(m_uid, linkService); + } + if (m_userService != nullptr) { + ejson::Object linkService; + linkService.add("event", ejson::String("delete")); + m_userService->SendData(-m_uid, linkService); + m_userService = nullptr; } m_listConnectedService.clear(); m_interfaceClient.disconnect(); @@ -51,10 +60,18 @@ bool jus::GateWayClient::isAlive() { void jus::GateWayClient::onClientData(std::string _value) { JUS_DEBUG("On data: " << _value); ejson::Object data(_value); + int32_t transactionId = data["id"].toNumber().get(); if (m_userConnectionName == "") { if (data.valueExist("connect-to-user") == true) { m_userConnectionName = data["connect-to-user"].toString().get(); JUS_WARNING("[" << m_uid << "] Set client connect to user : '" << m_userConnectionName << "'"); + + m_userService = m_gatewayInterface->get("system-user"); + ejson::Object linkService; + linkService.add("event", ejson::String("new")); + linkService.add("user", ejson::String(m_userConnectionName)); + m_userService->SendData(-m_uid, linkService); + // TODO : Return something ... return; } @@ -62,30 +79,74 @@ void jus::GateWayClient::onClientData(std::string _value) { // TODO : Return something ... return; } - - if (data.valueExist("service") == false) { - // add default service - data.add("service", ejson::String("ServiceManager")); - JUS_WARNING("missing service name ==> set it by default at ServiceManager"); - } std::string service = data["service"].toString().get(); // Thsi is 2 default service for the cient interface that manage the authorisation of view: - if (service == "ServiceManager") { + if (service == "") { std::string call = data["call"].toString().get(); ejson::Object answer; - answer.add("from-service", ejson::String("ServiceManager")); + //answer.add("from-service", ejson::String("")); answer.add("id", data["id"]); if (call == "getServiceCount") { // TODO : Do it better: answer.add("return", ejson::Number(2)); - } else if (call == "getServiceList") { + JUS_DEBUG("answer: " << answer.generateHumanString()); + m_interfaceClient.write(answer.generateMachineString()); + return; + } + if (call == "getServiceList") { ejson::Array listService; listService.add(ejson::String("ServiceManager/v0.1.0")); listService.add(ejson::String("getServiceInformation/v0.1.0")); answer.add("return", listService); - } else if (call == "getServiceInformation") { - - } else if (call == "link") { + JUS_DEBUG("answer: " << answer.generateHumanString()); + m_interfaceClient.write(answer.generateMachineString()); + return; + } + if (call == "identify") { + // Identify Client has an extern user ... + std::string clientName = data["param"].toArray()[0].toString().get(); + std::string clientTocken = data["param"].toArray()[1].toString().get(); + ejson::Object gwCall; + int32_t tmpID = m_transactionLocalId--; + gwCall.add("id", ejson::Number(tmpID)); + gwCall.add("call", ejson::String("checkTocken")); + ejson::Array gwParam; + gwParam.add(ejson::String(clientName)); + gwParam.add(ejson::String(clientTocken)); + gwCall.add("param", gwParam); + { + std::unique_lock lock(m_mutex); + m_actions.push_back(std::make_pair(tmpID, + [=](ejson::Object& _data) { + ejson::Object tmpAnswer; + tmpAnswer.add("id", ejson::Number(transactionId)); + JUS_ERROR(" ==> Tocken ckeck return ..."); + if (_data["return"].toBoolean().get() == true) { + m_clientName = clientName; + m_clientgroups.clear(); + // TODO : Update all service name and group ... + tmpAnswer.add("return", ejson::Boolean(true)); + } else { + tmpAnswer.add("return", ejson::Boolean(false)); + } + JUS_DEBUG("answer: " << tmpAnswer.generateHumanString()); + m_interfaceClient.write(tmpAnswer.generateMachineString()); + })); + } + if (m_userService != nullptr) { + m_userService->SendData(-m_uid, gwCall); + } else { + // TODO ... + } + return; + } + if (call == "authentify") { + // Identify Client has an local user ... (connection to is the same ...) + std::string password = data["param"].toArray()[0].toString().get(); + // TODO: ... + return; + } + if (call == "link") { // first param: std::string serviceName = data["param"].toArray()[0].toString().get(); // Check if service already link: @@ -106,8 +167,9 @@ 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)); - srv->SendData(m_uid, linkService, "new"); + srv->SendData(m_uid, linkService); m_listConnectedService.push_back(srv); answer.add("return", ejson::Boolean(true)); } else { @@ -117,7 +179,11 @@ void jus::GateWayClient::onClientData(std::string _value) { // TODO : Service already connected; answer.add("return", ejson::Boolean(false)); } - } else if (call == "unlink") { + JUS_DEBUG("answer: " << answer.generateHumanString()); + m_interfaceClient.write(answer.generateMachineString()); + return; + } + if (call == "unlink") { // first param: std::string serviceName = data["param"].toArray()[0].toString().get(); // Check if service already link: @@ -136,50 +202,88 @@ void jus::GateWayClient::onClientData(std::string _value) { if (it == m_listConnectedService.end()) { answer.add("return", ejson::Boolean(false)); } else { - (*it)->SendData(m_uid, ejson::Object(), "delete"); + ejson::Object linkService; + linkService.add("event", ejson::String("delete")); + (*it)->SendData(m_uid, linkService); m_listConnectedService.erase(it); answer.add("return", ejson::Boolean(true)); } - } else { - JUS_ERROR("Function does not exist ... '" << call << "'"); - answer.add("error", ejson::String("CALL-UNEXISTING")); - } - JUS_DEBUG("answer: " << answer.generateHumanString()); - m_interfaceClient.write(answer.generateMachineString()); - } else if (service == "Authentification") { - std::string call = data["call"].toString().get(); - - } else { - auto it = m_listConnectedService.begin(); - while (it != m_listConnectedService.end()) { - if (*it == nullptr) { - ++it; - continue; - } - if ((*it)->getName() != service) { - ++it; - continue; - } - break; - } - if (it == m_listConnectedService.end()) { - // TODO : Generate an ERROR... - ejson::Object answer; - answer.add("from-service", ejson::String("ServiceManager")); - answer.add("id", data["id"]); - JUS_ERROR("Service not linked ... " << service); - answer.add("error", ejson::String("SERVICE-NOT-LINK")); JUS_DEBUG("answer: " << answer.generateHumanString()); m_interfaceClient.write(answer.generateMachineString()); - } else { - JUS_ERROR("Add in link the name of the user in parameter ..."); - data.remove("service"); - (*it)->SendData(m_uid, data); + return; } + JUS_ERROR("Function does not exist ... '" << call << "'"); + answer.add("error", ejson::String("CALL-UNEXISTING")); + JUS_DEBUG("answer: " << answer.generateHumanString()); + m_interfaceClient.write(answer.generateMachineString()); + return; + } + auto it = m_listConnectedService.begin(); + while (it != m_listConnectedService.end()) { + if (*it == nullptr) { + ++it; + continue; + } + if ((*it)->getName() != service) { + ++it; + continue; + } + break; + } + if (it == m_listConnectedService.end()) { + // TODO : Generate an ERROR... + ejson::Object answer; + answer.add("from-service", ejson::String("ServiceManager")); + answer.add("id", data["id"]); + JUS_ERROR("Service not linked ... " << service); + answer.add("error", ejson::String("SERVICE-NOT-LINK")); + JUS_DEBUG("answer: " << answer.generateHumanString()); + m_interfaceClient.write(answer.generateMachineString()); + } else { + JUS_ERROR("Add in link the name of the user in parameter ..."); + data.remove("service"); + { + std::unique_lock lock(m_mutex); + m_actions.push_back(std::make_pair(transactionId, + [=](ejson::Object& _data) { + JUS_DEBUG(" ==> transmit"); + m_interfaceClient.write(_data.generateMachineString()); + })); + } + (*it)->SendData(m_uid, data); } } void jus::GateWayClient::returnMessage(ejson::Object _data) { JUS_DEBUG("answer: " << _data.generateHumanString()); - m_interfaceClient.write(_data.generateMachineString()); + int32_t id = _data["id"].toNumber().get(); + if (id == 0) { + JUS_ERROR("gateway reject transaction ... ==> No 'id' or 'id' == 0"); + return; + } + jus::GateWayClient::Observer obs; + ejson::Object localData; + { + std::unique_lock lock(m_mutex); + auto it = m_actions.begin(); + while (it != m_actions.end()) { + if (it->first != id) { + ++it; + continue; + } + obs = (*it).second; + m_actions.erase(it); + break; + } + if (obs == nullptr) { + JUS_ERROR("gateway reject transaction ... (not find answer)" << _data.generateHumanString()); + return; + } + } + obs(_data); + if (id >= 0) { + m_interfaceClient.write(_data.generateMachineString()); + } else { + JUS_WARNING("Action to do ..."); + } } \ No newline at end of file diff --git a/jus/GateWayClient.h b/jus/GateWayClient.h index 1730c69..9964681 100644 --- a/jus/GateWayClient.h +++ b/jus/GateWayClient.h @@ -10,17 +10,26 @@ #include #include + + namespace jus { class GateWay; class GateWayClient { + using Observer = std::function; private: jus::GateWay* m_gatewayInterface; jus::TcpString m_interfaceClient; public: esignal::Signal signalIsConnected; + ememory::SharedPtr m_userService; std::vector> m_listConnectedService; size_t m_uid; std::string m_userConnectionName; + std::string m_clientName; + std::vector m_clientgroups; + std::mutex m_mutex; + std::vector> m_actions; + int32_t m_transactionLocalId; public: GateWayClient(enet::Tcp _connection, jus::GateWay* _gatewayInterface); virtual ~GateWayClient(); diff --git a/jus/GateWayService.cpp b/jus/GateWayService.cpp index f0f4abb..f60167c 100644 --- a/jus/GateWayService.cpp +++ b/jus/GateWayService.cpp @@ -38,9 +38,8 @@ void jus::GateWayService::stop() { m_interfaceClient.disconnect(); } -void jus::GateWayService::SendData(size_t _userSessionId, ejson::Object _data, const std::string& _action) { +void jus::GateWayService::SendData(int32_t _userSessionId, ejson::Object _data) { _data.add("client-id", ejson::String(etk::to_string(_userSessionId))); - _data.add("action", ejson::String(_action)); JUS_DEBUG("Send Service: " << _data.generateHumanString()); m_interfaceClient.write(_data.generateMachineString()); } @@ -48,9 +47,14 @@ void jus::GateWayService::SendData(size_t _userSessionId, ejson::Object _data, c void jus::GateWayService::onServiceData(std::string _value) { JUS_DEBUG("On service data: " << _value); ejson::Object data(_value); + data.add("from-service", ejson::String(m_name)); if (data.valueExist("event") == true) { + // No need to have a user ID ... if (data["event"].toString().get() == "IS-ALIVE") { - JUS_INFO("Service Alive ..."); + JUS_VERBOSE("Service Alive ..."); + if (std::chrono::steady_clock::now() - m_interfaceClient.getLastTimeSend() >= std::chrono::seconds(20)) { + m_interfaceClient.write("{\"event\":\"IS-ALIVE\"}"); + } } else { JUS_INFO("Unknow service event: '" << data["event"].toString().get() << "'"); } diff --git a/jus/GateWayService.h b/jus/GateWayService.h index 098791b..f3fa829 100644 --- a/jus/GateWayService.h +++ b/jus/GateWayService.h @@ -26,7 +26,7 @@ namespace jus { void stop(); void onServiceData(std::string _value); public: - void SendData(size_t _userSessionId, ejson::Object _data, const std::string& _action="call"); + void SendData(int32_t _userSessionId, ejson::Object _data); const std::string& getName() { return m_name; } diff --git a/jus/ParamType.cpp b/jus/ParamType.cpp index d0eec93..6489912 100644 --- a/jus/ParamType.cpp +++ b/jus/ParamType.cpp @@ -43,3 +43,16 @@ generate_basic_type(uint16_t, "uint16"); generate_basic_type(uint8_t, "uint8"); generate_basic_type(std::string, "string"); + +generate_basic_type(std::vector, "vector:bool"); +generate_basic_type(std::vector, "vector:float"); +generate_basic_type(std::vector, "vector:double"); +generate_basic_type(std::vector, "vector:int64"); +generate_basic_type(std::vector, "vector:int32"); +generate_basic_type(std::vector, "vector:int16"); +generate_basic_type(std::vector, "vector:int8"); +generate_basic_type(std::vector, "vector:uint64"); +generate_basic_type(std::vector, "vector:uint32"); +generate_basic_type(std::vector, "vector:uint16"); +generate_basic_type(std::vector, "vector:uint8"); +generate_basic_type(std::vector, "vector:string"); \ No newline at end of file diff --git a/jus/Service.cpp b/jus/Service.cpp index 6f77322..6d5f803 100644 --- a/jus/Service.cpp +++ b/jus/Service.cpp @@ -26,10 +26,13 @@ jus::Service::~Service() { void jus::Service::onClientData(std::string _value) { ejson::Object request(_value); + ejson::Value tmpID = request["id"]; + request.remove("id"); JUS_INFO("Request: " << _value); ejson::Value answer = callJson(request); // check if an answer is needed if (answer.isNull() == false) { + answer.toObject().add("id", tmpID); JUS_INFO("Answer: " << answer.generateHumanString()); m_interfaceClient.write(answer.generateMachineString()); } @@ -44,10 +47,14 @@ void jus::Service::onPropertyChangePort(){ } -void jus::Service::connect(const std::string& _serviceName){ +void jus::Service::connect(const std::string& _serviceName, uint32_t _numberRetry){ disconnect(); JUS_DEBUG("connect [START]"); - enet::Tcp connection = std::move(enet::connectTcpClient(*propertyIp, *propertyPort)); + enet::Tcp connection = std::move(enet::connectTcpClient(*propertyIp, *propertyPort, _numberRetry)); + if (connection.getConnectionStatus() != enet::Tcp::status::link) { + JUS_DEBUG("connect [STOP] ==> can not connect"); + return; + } m_interfaceClient.setInterface(std::move(connection)); m_interfaceClient.connect(); m_interfaceClient.write(std::string("{\"connect-service\":\"") + _serviceName + "\"}"); @@ -60,39 +67,36 @@ void jus::Service::disconnect(){ JUS_DEBUG("disconnect [STOP]"); } +bool jus::Service::GateWayAlive() { + return m_interfaceClient.isActive(); +} void jus::Service::pingIsAlive() { - m_interfaceClient.write("{\"event\":\"IS-ALIVE\"}"); + if (std::chrono::steady_clock::now() - m_interfaceClient.getLastTimeSend() >= std::chrono::seconds(30)) { + m_interfaceClient.write("{\"event\":\"IS-ALIVE\"}"); + } } ejson::Value jus::Service::callJson(const ejson::Object& _obj) { - std::string action = _obj["action"].toString().get(); - if (action == "new") { - uint64_t clientId = etk::string_to_uint64_t(_obj["client-id"].toString().get()); - std::string userName = _obj["user"].toString().get(); - clientConnect(clientId, userName); - /* - ejson::Object tmpp; - tmpp.add("client-id", ejson::String(etk::to_string(clientId))); - tmpp.add("return", ejson::String("OK")); - return tmpp - */ + if (_obj.valueExist("event") == true) { + std::string event = _obj["event"].toString().get(); + if (event == "IS-ALIVE") { + // Gateway just aswer a keep alive information ... + // Nothing to do ... + } else if (event == "new") { + int64_t clientId = etk::string_to_int64_t(_obj["client-id"].toString().get()); + std::string userName = _obj["user"].toString().get(); + clientConnect(clientId, userName); + } else if (event == "delete") { + int64_t clientId = etk::string_to_int64_t(_obj["client-id"].toString().get()); + clientDisconnect(clientId); + } else { + JUS_ERROR("Unknow event: '" << event << "'"); + } return ejson::Null(); } - if (action == "delete") { - uint64_t clientId = etk::string_to_uint64_t(_obj["client-id"].toString().get()); - clientDisconnect(clientId); - /* - ejson::Object tmpp; - tmpp.add("client-id", ejson::String(etk::to_string(clientId))); - tmpp.add("return", ejson::String("OK")); - return tmpp; - */ - return ejson::Null(); - } - if ( action == "call" - || action == "") { - uint64_t clientId = etk::string_to_uint64_t(_obj["client-id"].toString().get()); + if (_obj.valueExist("call") == true) { + int64_t clientId = etk::string_to_int64_t(_obj["client-id"].toString().get()); ejson::Object tmpp = callJson2(clientId, _obj); tmpp.add("client-id", ejson::String(etk::to_string(clientId))); return tmpp; diff --git a/jus/Service.h b/jus/Service.h index 9e81b45..d8aa282 100644 --- a/jus/Service.h +++ b/jus/Service.h @@ -13,8 +13,34 @@ #include #include +namespace jus { + class ClientProperty { + public: + ClientProperty() {} + private: + std::string m_name; + public: + void setName(const std::string& _name) { + m_name = _name; + } + const std::string& getName() { + return m_name; + } + private: + std::vector m_groups; + public: + void setGroups(std::vector _groups) { + m_groups = _groups; + } + const std::vector& getGroups() { + return m_groups; + } + }; +} namespace jus { class Service : public eproperty::Interface, public jus::RemoteProcessCall { + protected: + std::mutex m_mutex; public: eproperty::Value propertyIp; eproperty::Value propertyPort; @@ -25,13 +51,14 @@ namespace jus { public: Service(); virtual ~Service(); - void connect(const std::string& _serviceName); + void connect(const std::string& _serviceName, uint32_t _numberRetry = 1); void disconnect(); private: void onClientData(std::string _value); std::string asyncRead(); public: void pingIsAlive(); + bool GateWayAlive(); private: void onPropertyChangeIp(); void onPropertyChangePort(); @@ -52,7 +79,7 @@ namespace jus { private: JUS_USER_ACCESS& m_getUserInterface; // no need of shared_ptr or unique_ptr (if service die all is lost and is client die, the gateway notify us...) - std::map m_interface; + std::map, ememory::SharedPtr>> m_interface; public: template lock(m_mutex); + JUS_DEBUG("connect : " << _clientSessionID << " to '" << _userName << "'"); + ememory::SharedPtr tmpProperty = std::make_shared(); + ememory::SharedPtr tmpSrv = std::make_shared(m_getUserInterface.getUser(_userName), tmpProperty); + m_interface.insert(std::make_pair(_clientSessionID, std::make_pair(tmpProperty, tmpSrv))); } void clientDisconnect(size_t _clientSessionID) { + std::unique_lock lock(m_mutex); + JUS_DEBUG("disconnect: " << _clientSessionID); auto it = m_interface.find(_clientSessionID); - if (it != m_interface.end()) { + if (it == m_interface.end()) { + JUS_WARNING("disconnect ==> Not find Client ID " << _clientSessionID); // noting to do ==> user never conected. return; } - // TODO : Set a mutex ... m_interface.erase(it); } + void clientSetName(size_t _clientSessionID, const std::string& _clientName) { + std::unique_lock lock(m_mutex); + auto it = m_interface.find(_clientSessionID); + if (it == m_interface.end()) { + JUS_ERROR("Change the client property but client was not created ..."); + return; + } + it->second.first->setName(_clientName); + } + void clientSetGroup(size_t _clientSessionID, const std::vector& _clientGroups) { + std::unique_lock lock(m_mutex); + auto it = m_interface.find(_clientSessionID); + if (it == m_interface.end()) { + JUS_ERROR("Change the client property but client was not created ..."); + return; + } + it->second.first->setGroups(_clientGroups); + } ejson::Object callJson2(size_t _clientSessionID, const ejson::Object& _obj) { ejson::Object out; auto it = m_interface.find(_clientSessionID); @@ -106,7 +156,7 @@ namespace jus { if (it2->getName() != call) { continue; } - JUS_TYPE_SERVICE* elem = it->second; + JUS_TYPE_SERVICE* elem = it->second.second.get(); return it2->executeJson(param, (void*)elem).toObject(); } out.add("error", ejson::String("FUNCTION-UNKNOW")); diff --git a/jus/ServiceRemote.cpp b/jus/ServiceRemote.cpp index 71249d5..b7f6b16 100644 --- a/jus/ServiceRemote.cpp +++ b/jus/ServiceRemote.cpp @@ -10,13 +10,19 @@ jus::ServiceRemote::ServiceRemote(jus::Client* _clientInterface, const std::string& _name): m_clientInterface(_clientInterface), m_name(_name) { - m_clientInterface->link(_name); + m_isLinked = m_clientInterface->link(_name); } jus::ServiceRemote::~ServiceRemote() { - m_clientInterface->unlink(m_name); + if (m_isLinked == true) { + m_clientInterface->unlink(m_name); + m_isLinked = false; + } } +bool jus::ServiceRemote::exist() { + return m_isLinked; +} ejson::Object jus::ServiceRemote::createBaseCall(const std::string& _functionName) { return m_clientInterface->createBaseCall(_functionName, m_name); diff --git a/jus/ServiceRemote.h b/jus/ServiceRemote.h index 2d74c8c..07ede89 100644 --- a/jus/ServiceRemote.h +++ b/jus/ServiceRemote.h @@ -17,9 +17,11 @@ namespace jus { private: jus::Client* m_clientInterface; std::string m_name; + bool m_isLinked; public: ServiceRemote(jus::Client* _clientInterface, const std::string& _name); ~ServiceRemote(); + bool exist(); private: ejson::Object callJson(const ejson::Object& _obj); ejson::Object createBaseCall(const std::string& _functionName); diff --git a/jus/TcpString.cpp b/jus/TcpString.cpp index 3d72340..c328235 100644 --- a/jus/TcpString.cpp +++ b/jus/TcpString.cpp @@ -43,6 +43,7 @@ void jus::TcpString::threadCallback() { std::string data = std::move(read()); JUS_VERBOSE("Receive data: '" << data << "'"); if (data.size() != 0) { + m_lastReceive = std::chrono::steady_clock::now(); if (m_obsercerElement != nullptr) { m_obsercerElement(std::move(data)); } @@ -106,6 +107,7 @@ int32_t jus::TcpString::write(const std::string& _data) { return 0; } uint32_t size = _data.size(); + m_lastSend = std::chrono::steady_clock::now(); m_connection.write(&size, 4); return m_connection.write(_data.c_str(), _data.size()); } diff --git a/jus/TcpString.h b/jus/TcpString.h index 1bfa29d..ded3887 100644 --- a/jus/TcpString.h +++ b/jus/TcpString.h @@ -16,6 +16,8 @@ namespace jus { enet::Tcp m_connection; std::thread* m_thread; bool m_threadRunning; + std::chrono::steady_clock::time_point m_lastReceive; + std::chrono::steady_clock::time_point m_lastSend; public: using Observer = std::function; //!< Define an Observer: function pointer Observer m_obsercerElement; @@ -46,6 +48,13 @@ namespace jus { std::string read(); private: void threadCallback(); + public: + const std::chrono::steady_clock::time_point& getLastTimeReceive() { + return m_lastReceive; + } + const std::chrono::steady_clock::time_point& getLastTimeSend() { + return m_lastSend; + } }; } diff --git a/lutinParseSubFolders.txt b/lutinParseSubFolders.txt index 72928ee..bf3047a 100644 --- a/lutinParseSubFolders.txt +++ b/lutinParseSubFolders.txt @@ -1,4 +1,4 @@ tools/system-gateway -tools/system-service +tools/system-user test/client test/service1 \ No newline at end of file diff --git a/test/client/appl/main.cpp b/test/client/appl/main.cpp index 3800ad2..b1cc417 100644 --- a/test/client/appl/main.cpp +++ b/test/client/appl/main.cpp @@ -33,11 +33,17 @@ int main(int _argc, const char *_argv[]) { APPL_INFO("=================================="); APPL_INFO("== JUS test client start =="); APPL_INFO("=================================="); - client1.connect("userName"); + client1.connect("test1#atria-soft.com"); + // Connect that is not us + //client1.identify("clientTest1#atria-soft.com", "QSDQSDGQSF54HSXWVCSQDJ654URTDJ654NBXCDFDGAEZ51968"); + bool retIdentify = client1.call_b("identify", "clientTest1#atria-soft.com", "QSDQSDGQSF54HSXWVCSQDJ654URTDJ654NBXCDFDGAEZ51968"); + // Connect to ourself: + //client1.authentificate("coucou"); + //bool retAuthentify = client1.call_b("authentify", "coucou"); APPL_INFO(" ----------------------------------"); APPL_INFO(" -- Get service count --"); APPL_INFO(" ----------------------------------"); - + /* std::vector tmp; tmp.push_back(1); tmp.push_back(22); @@ -51,10 +57,17 @@ int main(int _argc, const char *_argv[]) { APPL_INFO(" - " << it); } jus::ServiceRemote localService = client1.getService("serviceTest1"); + if (localService.exist() == true) { + double retCall = localService.call_d("mul", 13.1, 2.0); + APPL_INFO("serviceTest1.mul = " << retCall); + } + */ - double retCall = localService.call_d("mul", 13.1, 2.0); - APPL_INFO("serviceTest1.mul = " << retCall); - + jus::ServiceRemote remoteServiceUser = client1.getService("system-user"); + if (remoteServiceUser.exist() == true) { + std::vector retCall = remoteServiceUser.call_vs("getClientGroups"); + APPL_INFO("system-user.getClientGroups() = " << retCall); + } int32_t iii=0; while (iii < 3) { usleep(500000); diff --git a/test1#atria-soft.com.json b/test1#atria-soft.com.json new file mode 100644 index 0000000..f4abd31 --- /dev/null +++ b/test1#atria-soft.com.json @@ -0,0 +1,8 @@ +{ + "password":"coucou", + "client":{ + "clientTest1#atria-soft.com":{ + "tocken":"QSDQSDGQSF54HSXWVCSQDJ654URTDJ654NBXCDFDGAEZ51968" + } + } +} \ No newline at end of file diff --git a/tools/system-service/appl/main.cpp b/tools/system-service/appl/main.cpp deleted file mode 100644 index 70a75c7..0000000 --- a/tools/system-service/appl/main.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/** @file - * @author Edouard DUPIN - * @copyright 2014, Edouard DUPIN, all right reserved - * @license APACHE v2.0 (see license file) - */ - -#include -#include -#include -#include - -#include -namespace appl { - class User { - public: - User() { - APPL_WARNING("new USER"); - } - ~User() { - APPL_WARNING("delete USER"); - } - - }; - - class UserManager { - private: - std::map> m_listLoaded; - public: - UserManager() { - - } - ememory::SharedPtr getUser(const std::string& _userName) { - // TODO : Lock ... - auto it = m_listLoaded.find(_userName); - if (it != m_listLoaded.end()) { - // User already loaded: - return it->second; - } - // load New User: - ememory::SharedPtr tmp(new appl::User); - m_listLoaded.insert(std::make_pair(_userName, tmp)); - return tmp; - } - }; - class ClientProperty { - public: - ClientProperty() {} - private: - std::string m_name; - public: - void setName(const std::string& _name) { - m_name = _name - } - const std::string& getName() { - return m_name; - } - private: - std::vector m_groups; - public: - void setGroups(std::vector _groups) { - m_groups = _groups - } - const std::vector& getGroups() { - return m_groups; - } - } - class SystemService { - private: - - public: - SystemService() { - APPL_WARNING("New SystemService ..."); - } - ~SystemService() { - APPL_WARNING("delete SystemService ..."); - } - private: - ememory::SharedPtr m_user; - public: - int32_t getServiceCount() { - return 0; - } - std::vector getServiceList() { - return std::vector(); - } - public: - SystemService(ememory::SharedPtr _user) : - m_user(_user) { - - } - }; -} - - -int main(int _argc, const char *_argv[]) { - etk::init(_argc, _argv); - appl::UserManager userMng; - jus::ServiceType serviceInterface(userMng); - serviceInterface.setDescription("SystemService interface"); - serviceInterface.setVersion("0.1.1"); - serviceInterface.addAuthor("Heero Yui", "yui.heero@gmail.com"); - serviceInterface.advertise("mul", &appl::SystemService::mul); - serviceInterface.setLastFuncDesc("simple multiplication to test double IO"); - serviceInterface.addLastFuncParam("val1", "First Parameter To multiply"); - serviceInterface.addLastFuncParam("val2", "Second Parameter To multiply"); - for (int32_t iii=0; iii<_argc ; ++iii) { - std::string data = _argv[iii]; - if (etk::start_with(data, "--ip=") == true) { - serviceInterface.propertyIp.set(std::string(&data[5])); - } else if (etk::start_with(data, "--port=") == true) { - serviceInterface.propertyPort.set(etk::string_to_uint16_t(std::string(&data[7]))); - } else if ( data == "-h" - || data == "--help") { - APPL_PRINT(etk::getApplicationName() << " - help : "); - APPL_PRINT(" " << _argv[0] << " [options]"); - APPL_PRINT(" --ip=XXX Server connection IP (default: 1.7.0.0.1)"); - APPL_PRINT(" --port=XXX Server connection PORT (default: 1983)"); - return -1; - } - } - APPL_INFO("=================================="); - APPL_INFO("== JUS test service1 start =="); - APPL_INFO("=================================="); - serviceInterface.connect("serviceTest1"); - int32_t iii=0; - while (true) { - usleep(1000000); - serviceInterface.pingIsAlive(); - APPL_INFO("service in waiting ... " << iii << "/inf"); - iii++; - } - serviceInterface.disconnect(); - APPL_INFO("=================================="); - APPL_INFO("== JUS test service1 stop =="); - APPL_INFO("=================================="); - return 0; -} diff --git a/tools/system-service/appl/debug.cpp b/tools/system-user/appl/debug.cpp similarity index 100% rename from tools/system-service/appl/debug.cpp rename to tools/system-user/appl/debug.cpp diff --git a/tools/system-service/appl/debug.h b/tools/system-user/appl/debug.h similarity index 100% rename from tools/system-service/appl/debug.h rename to tools/system-user/appl/debug.h diff --git a/tools/system-user/appl/main.cpp b/tools/system-user/appl/main.cpp new file mode 100644 index 0000000..7ab1210 --- /dev/null +++ b/tools/system-user/appl/main.cpp @@ -0,0 +1,199 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include + +#include +namespace appl { + class User { + private: + std::mutex m_mutex; + std::string m_userName; + ejson::Document m_database; + public: + User(const std::string& _userName) : + m_userName(_userName) { + std::unique_lock lock(m_mutex); + APPL_WARNING("new USER: " << m_userName); + bool ret = m_database.load(std::string("USERDATA:") + m_userName + ".json"); + if (ret == false) { + APPL_WARNING(" ==> LOAD error"); + } + } + ~User() { + std::unique_lock lock(m_mutex); + APPL_WARNING("delete USER [START]"); + APPL_DEBUG("Store User Info:"); + bool ret = m_database.storeSafe(std::string("USERDATA:") + m_userName + ".json"); + if (ret == false) { + APPL_WARNING(" ==> Store error"); + } + APPL_WARNING("delete USER [STOP]"); + } + std::vector getGroups(const std::string& _clientName) { + std::unique_lock lock(m_mutex); + std::vector out; + ejson::Object clients = m_database["client"].toObject(); + if (clients.exist() == false) { + // Section never created + return out; + } + ejson::Object client = clients[_clientName].toObject(); + if (clients.exist() == false) { + // No specificity for this client (in case it have no special right) + return out; + } + // TODO: check banishing ... + ejson::Array groups = client["group"].toArray(); + for (auto it : groups) { + out.push_back(it.toString().get()); + } + return out; + } + bool checkTocken(const std::string& _clientName, const std::string& _tocken) { + std::unique_lock lock(m_mutex); + ejson::Object clients = m_database["client"].toObject(); + if (clients.exist() == false) { + // Section never created + return false; + } + ejson::Object client = clients[_clientName].toObject(); + if (clients.exist() == false) { + // No specificity for this client (in case it have no special right) + return false; + } + // TODO: check banishing ... + // TODO: Do it better ... + std::string registerTocken = client["tocken"].toString().get(); + if (registerTocken == _tocken) { + return true; + } + return false; + } + }; + + class UserManager { + private: + std::mutex m_mutex; + std::map> m_listLoaded; + public: + UserManager() { + + } + ememory::SharedPtr getUser(const std::string& _userName) { + std::unique_lock lock(m_mutex); + auto it = m_listLoaded.find(_userName); + if (it != m_listLoaded.end()) { + // User already loaded: + return it->second; + } + // load New User: + ememory::SharedPtr tmp(new appl::User(_userName)); + m_listLoaded.insert(std::make_pair(_userName, tmp)); + return tmp; + } + }; + class SystemService { + private: + ememory::SharedPtr m_user; + private: + ememory::SharedPtr m_client; + public: + SystemService() { + APPL_WARNING("New SystemService ..."); + } + SystemService(ememory::SharedPtr _user, ememory::SharedPtr _client) : + m_user(_user), + m_client(_client) { + APPL_WARNING("New SystemService ... for user: "); + } + ~SystemService() { + APPL_WARNING("delete SystemService ..."); + } + public: + std::vector getClientGroups() { + std::vector out; + if (m_client == nullptr) { + return out; + } + // TODO: check if basished ... + if (m_client->getName() != "") { + out = m_user->getGroups(m_client->getName()); + } + // TODO: Check default visibility ... (if user want to have default visibility at Noone ==> then public must be removed... + if (true) { + out.push_back("public"); + } + return out; + } + std::vector getClientServices() { + return std::vector(); + } + bool checkTocken(std::string _clientName, std::string _tocken) { + return m_user->checkTocken(_clientName, _tocken); + } + }; +} + + +int main(int _argc, const char *_argv[]) { + etk::init(_argc, _argv); + appl::UserManager userMng; + jus::ServiceType serviceInterface(userMng); + serviceInterface.setDescription("user interface management"); + serviceInterface.setVersion("0.1.0"); + serviceInterface.addAuthor("Heero Yui", "yui.heero@gmail.com"); + serviceInterface.advertise("getClientGroups", &appl::SystemService::getClientGroups); + serviceInterface.setLastFuncDesc("Get list of group availlable for a client name"); + serviceInterface.addLastFuncParam("clientName", "Name of the client"); + serviceInterface.advertise("checkTocken", &appl::SystemService::checkTocken); + for (int32_t iii=0; iii<_argc ; ++iii) { + std::string data = _argv[iii]; + if (etk::start_with(data, "--ip=") == true) { + serviceInterface.propertyIp.set(std::string(&data[5])); + } else if (etk::start_with(data, "--port=") == true) { + serviceInterface.propertyPort.set(etk::string_to_uint16_t(std::string(&data[7]))); + } else if ( data == "-h" + || data == "--help") { + APPL_PRINT(etk::getApplicationName() << " - help : "); + APPL_PRINT(" " << _argv[0] << " [options]"); + APPL_PRINT(" --ip=XXX Server connection IP (default: 1.7.0.0.1)"); + APPL_PRINT(" --port=XXX Server connection PORT (default: 1983)"); + return -1; + } + } + while (true) { + APPL_INFO("==========================================================="); + APPL_INFO("== JUS service: " << SERVICE_NAME << " [START]"); + APPL_INFO("==========================================================="); + serviceInterface.connect(SERVICE_NAME); + if (serviceInterface.GateWayAlive() == false) { + APPL_INFO("==========================================================="); + APPL_INFO("== JUS service: " << SERVICE_NAME << " [STOP] Can not connect to the GateWay"); + APPL_INFO("==========================================================="); + APPL_INFO("wait 5 second ..."); + usleep(5000000); + continue; + } + int32_t iii=0; + while (serviceInterface.GateWayAlive() == true) { + usleep(1000000); + serviceInterface.pingIsAlive(); + APPL_INFO("service in waiting ... " << iii << "/inf"); + iii++; + } + serviceInterface.disconnect(); + APPL_INFO("==========================================================="); + APPL_INFO("== JUS service: " << SERVICE_NAME << " [STOP] GateWay Stop"); + APPL_INFO("==========================================================="); + } + return 0; +} diff --git a/tools/system-service/lutin_jus-system-service.py b/tools/system-user/lutin_jus-system-user.py similarity index 88% rename from tools/system-service/lutin_jus-system-service.py rename to tools/system-user/lutin_jus-system-user.py index cca942b..dba434c 100644 --- a/tools/system-service/lutin_jus-system-service.py +++ b/tools/system-user/lutin_jus-system-user.py @@ -32,6 +32,7 @@ def create(target, module_name): 'appl/debug.cpp', 'appl/main.cpp' ]) + my_module.add_export_flag('c++', "-DSERVICE_NAME=\"\\\"" + module_name[4:] + "\\\"\"") return my_module