Add second work package for REST API implementation
[anna.git] / example / diameter / launcher / EventOperation.cpp
index be0c168..935940d 100644 (file)
 //#include <anna/diameter/codec/EngineManager.hpp>
 //#include <anna/http/Transport.hpp>
 //#include <anna/diameter/stack/Engine.hpp>
-//#include <anna/diameter/helpers/base/functions.hpp>
+#include <anna/diameter/helpers/base/functions.hpp>
 //#include <anna/time/functions.hpp>
 //#include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
 //#include <anna/testing/defines.hpp>
 #include <anna/xml/xml.hpp>
 //#include <anna/diameter.comm/OriginHost.hpp>
 //#include <anna/diameter.comm/OriginHostManager.hpp>
+#include <anna/diameter.comm/Message.hpp>
 //
 //// Process
 //#include <Launcher.hpp>
@@ -321,79 +322,255 @@ bool EventOperation::show_stats(std::string &response) {
 /////////////////////
 // Flow operations //
 /////////////////////
-bool EventOperation::sendmsg2e(std::string &response, const std::string & diameterJson) {
+bool EventOperation::sendmsg_hex_2e(std::string &response, const std::string & diameterJson_or_Hex, bool msg_or_hex) {
 
   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
+  anna::diameter::codec::Message codecMsg; // auxiliary codec message
+  bool success;
+  anna::diameter::comm::Message *msg;
 
+  if(msg_or_hex) {
+    std::string diameterXml = anna::json::functions::json2xml(diameterJson_or_Hex, success);
+    if (!success) {
+      response += "json to xml failed, unable to send message !";
+      return false;
+    }
+    codecMsg.loadXMLString(diameterXml);
+    try {
+      my_app.updateOperatedOriginHostWithMessage(codecMsg);
+      msg = my_app.getOperatedHost()->createCommMessage();
+      msg->clearBody();
+    }
+    catch(anna::RuntimeException &ex) {
+      ex.trace();
+      response += "invalid operated host";
+      return false;
+    }
+    try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); }  // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher)
+    msg->setBody(codecMsg.code());
+  } else {
+    // Get DataBlock from hex content:
+    anna::DataBlock db_aux(true);
+    std::string hexString = diameterJson_or_Hex;
+    hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end());
+    LOGDEBUG(
+        std::string msg = "Hex string (remove colons if exists): ";
+    msg += hexString;
+    anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+    );
+    anna::functions::fromHexString(hexString, db_aux); // could launch exception
+    try {
+      my_app.updateOperatedOriginHostWithMessage(db_aux);
+      msg = my_app.getOperatedHost()->createCommMessage();
+    }
+    catch(anna::RuntimeException &ex) {
+      ex.trace();
+      response += "invalid operated host";
+      return false;
+    }
+    msg->setBody(db_aux);
+    try { if(my_app.getOperatedHost()->logEnabled()) codecMsg.decode(db_aux); } catch(anna::RuntimeException &ex) { ex.trace(); }
+  }
 
+  success = my_app.getOperatedEntity()->send(msg);
+  my_app.getOperatedHost()->releaseCommMessage(msg);
 
-  return true; // OK
-}
-
-bool EventOperation::sendmsg2c(std::string &response, const std::string & diameterJson) {
-
-  Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
-
+  // Detailed log:
+  if(my_app.getOperatedHost()->logEnabled()) {
+    anna::diameter::comm::Server *usedServer = my_app.getOperatedEntity()->getLastUsedResource();
+    anna::diameter::comm::ClientSession *usedClientSession = usedServer ? usedServer->getLastUsedResource() : NULL;
+    std::string detail = usedClientSession ? usedClientSession->asString() : "<null client session>"; // shouldn't happen
+    my_app.getOperatedHost()->writeLogFile(codecMsg, (success ? "sent2e" : "send2eError"), detail);
+  }
 
 
-  return true; // OK
+  response = "Operation processed"; // could be failed
+  return success;
 }
 
-bool EventOperation::answermsg2e(std::string &response, const std::string & diameterJson) {
+bool EventOperation::sendmsg_hex_2c(std::string &response, const std::string & diameterJson_or_Hex, bool msg_or_hex) {
 
   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
+  anna::diameter::codec::Message codecMsg; // auxiliary codec message
+  bool success;
+  anna::diameter::comm::Message *msg;
 
+  if(msg_or_hex) {
+    std::string diameterXml = anna::json::functions::json2xml(diameterJson_or_Hex, success);
+    if (!success) {
+      response += "json to xml failed, unable to send message !";
+      return false;
+    }
+    codecMsg.loadXMLString(diameterXml);
+    try {
+      my_app.updateOperatedOriginHostWithMessage(codecMsg);
+      msg = my_app.getOperatedHost()->createCommMessage();
+      msg->clearBody();
+    }
+    catch(anna::RuntimeException &ex) {
+      ex.trace();
+      response += "invalid operated host";
+      return false;
+    }
+    try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); }  // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher)
+    msg->setBody(codecMsg.code());
+  } else {
+    // Get DataBlock from hex content:
+    anna::DataBlock db_aux(true);
+    std::string hexString = diameterJson_or_Hex;
+    hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end());
+    LOGDEBUG(
+        std::string msg = "Hex string (remove colons if exists): ";
+    msg += hexString;
+    anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+    );
+    anna::functions::fromHexString(hexString, db_aux); // could launch exception
+    try {
+      my_app.updateOperatedOriginHostWithMessage(db_aux);
+      msg = my_app.getOperatedHost()->createCommMessage();
+    }
+    catch(anna::RuntimeException &ex) {
+      ex.trace();
+      response += "invalid operated host";
+      return false;
+    }
+    msg->setBody(db_aux);
+    try { if(my_app.getOperatedHost()->logEnabled()) codecMsg.decode(db_aux); } catch(anna::RuntimeException &ex) { ex.trace(); }
+  }
 
+  success = my_app.getOperatedServer()->send(msg);
+  my_app.getOperatedHost()->releaseCommMessage(msg);
 
-  return true; // OK
-}
-
-bool EventOperation::answermsg2c(std::string &response, const std::string & diameterJson) {
-
-  Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
-
+  // Detailed log:
+  if(my_app.getOperatedHost()->logEnabled()) {
+    anna::diameter::comm::ServerSession *usedServerSession = my_app.getOperatedServer()->getLastUsedResource();
+    std::string detail = usedServerSession ? usedServerSession->asString() : "<null server session>"; // shouldn't happen
+    my_app.getOperatedHost()->writeLogFile(codecMsg, (success ? "sent2c" : "send2cError"), detail);
+  }
 
 
-  return true; // OK
+  response = "Operation processed"; // could be failed
+  return success;
 }
 
-bool EventOperation::answermsg2e_action(std::string &response, const std::string & action) {
+bool EventOperation::answermsg_action_2e(std::string &response, const std::string & diameterJson_or_action, bool msg_or_action) {
 
   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
+  anna::diameter::codec::Message codecMsg; // auxiliary codec message
+  anna::diameter::codec::Message *message;
+  bool success;
 
+  if (msg_or_action) {
 
+    std::string diameterXml = anna::json::functions::json2xml(diameterJson_or_action, success);
+    if (!success) {
+      response += "json to xml failed, unable to send message !";
+      return false;
+    }
+    codecMsg.loadXMLString(diameterXml);
+    try {
+      my_app.updateOperatedOriginHostWithMessage(codecMsg);
+      message = my_app.getOperatedHost()->getCodecEngine()->createMessage(diameterXml, false /* is xml string */); // loads xml again, lesser of two evils
+      LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION));
+    }
+    catch(anna::RuntimeException &ex) {
+      ex.trace();
+      response += "invalid operated host";
+      return false;
+    }
 
-  return true; // OK
-}
-
-bool EventOperation::answermsg2c_action(std::string &response, const std::string & action) {
-
-  Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
+    if(message->isRequest()) {
+      response += "cannot program diameter requests. Answer type must be provided";
+      return false;
+    }
 
+    int code = message->getId().first;
+    LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to entity' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION));
+    response = "Added 'answer to entity' to the FIFO queue corresponding to its message code";
+    my_app.getOperatedEntity()->getReactingAnswers()->addMessage(code, message);
+  }
+  else { // action
+
+    if(diameterJson_or_action == "list") { // programmed answers FIFO's to stdout
+      response = anna::functions::encodeBase64(my_app.getOperatedEntity()->getReactingAnswers()->asString("ANSWERS TO ENTITY"));
+    } else if (diameterJson_or_action == "rotate") {
+      my_app.getOperatedEntity()->getReactingAnswers()->rotate(true);
+      response = "rotate";
+    } else if (diameterJson_or_action == "exhaust") {
+      my_app.getOperatedEntity()->getReactingAnswers()->rotate(false);
+      response = "exhaust";
+    } else if (diameterJson_or_action == "clear") {
+      my_app.getOperatedEntity()->getReactingAnswers()->clear();
+      response = "clear";
+    } else if (diameterJson_or_action == "dump") {
+      my_app.getOperatedEntity()->getReactingAnswers()->dump("programmed_answer");
+      response = "dump";
+    }
+  }
 
 
   return true; // OK
 }
 
-bool EventOperation::sendhex2e(std::string &response, const std::string & diameterHex) {
+bool EventOperation::answermsg_action_2c(std::string &response, const std::string & diameterJson_or_action, bool msg_or_action) {
 
   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
+  anna::diameter::codec::Message codecMsg; // auxiliary codec message
+  anna::diameter::codec::Message *message;
+  bool success;
 
+  if (msg_or_action) {
 
+    std::string diameterXml = anna::json::functions::json2xml(diameterJson_or_action, success);
+    if (!success) {
+      response += "json to xml failed, unable to send message !";
+      return false;
+    }
+    codecMsg.loadXMLString(diameterXml);
+    try {
+      my_app.updateOperatedOriginHostWithMessage(codecMsg);
+      message = my_app.getOperatedHost()->getCodecEngine()->createMessage(diameterXml, false /* is xml string */); // loads xml again, lesser of two evils
+      LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION));
+    }
+    catch(anna::RuntimeException &ex) {
+      ex.trace();
+      response += "invalid operated host";
+      return false;
+    }
 
-  return true; // OK
-}
-
-bool EventOperation::sendhex2c(std::string &response, const std::string & diameterHex) {
-
-  Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
+    if(message->isRequest()) {
+      response += "cannot program diameter requests. Answer type must be provided";
+      return false;
+    }
 
+    int code = message->getId().first;
+    LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to client' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION));
+    my_app.getOperatedServer()->getReactingAnswers()->addMessage(code, message);
+    response = "Added 'answer to client' to the FIFO queue corresponding to its message code";
+  }
+  else { // action
+
+    if(diameterJson_or_action == "list") { // programmed answers FIFO's to stdout
+      response = anna::functions::encodeBase64(my_app.getOperatedServer()->getReactingAnswers()->asString("ANSWERS TO CLIENT"));
+    } else if (diameterJson_or_action == "rotate") {
+      my_app.getOperatedServer()->getReactingAnswers()->rotate(true);
+      response = "rotate";
+    } else if (diameterJson_or_action == "exhaust") {
+      my_app.getOperatedServer()->getReactingAnswers()->rotate(false);
+      response = "exhaust";
+    } else if (diameterJson_or_action == "clear") {
+      my_app.getOperatedServer()->getReactingAnswers()->clear();
+      response = "clear";
+    } else if (diameterJson_or_action == "dump") {
+      my_app.getOperatedServer()->getReactingAnswers()->dump("programmed_answer");
+      response = "dump";
+    }
+  }
 
 
   return true; // OK
 }
 
-
 /////////////////
 // FSM testing //
 /////////////////