diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d75b111..b2e8590c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,10 +59,10 @@ add_executable(hpcore src/ledger/ledger_sync.cpp src/ledger/ledger_serve.cpp src/ledger/ledger.cpp + src/hpsh/hpsh.cpp src/status.cpp src/consensus.cpp src/main.cpp - src/hpsh/hpsh.cpp ) target_link_libraries(hpcore killswitch @@ -78,7 +78,7 @@ target_link_libraries(hpcore add_custom_command(TARGET hpcore POST_BUILD # COMMAND strip ./build/hpcore - COMMAND rm -f ./build/hpws ./build/hpfs ./build/hpsh && cp ./test/bin/hpws ./test/bin/hpfs ./test/bin/hpsh ./build/ + COMMAND cp ./test/bin/hpws ./test/bin/hpfs ./test/bin/hpsh ./build/ ) target_precompile_headers(hpcore PUBLIC src/pchheader.hpp) diff --git a/examples/js_client/text-client.js b/examples/js_client/text-client.js index 1c3a61d4..d402ac47 100644 --- a/examples/js_client/text-client.js +++ b/examples/js_client/text-client.js @@ -123,6 +123,9 @@ async function main() { else if (inp === "stat") { hpc.getStatus().then(stat => console.log(stat)); } + else if (inp.startsWith("hpsh ")) { + hpc.submitHpshRequest(inp.substr(5)).then(reply => console.log(reply)); + } else { if (inp.startsWith("upload ")) { diff --git a/examples/nodejs_contract/echo_contract.js b/examples/nodejs_contract/echo_contract.js index 7b152b55..8c2be74f 100644 --- a/examples/nodejs_contract/echo_contract.js +++ b/examples/nodejs_contract/echo_contract.js @@ -84,5 +84,42 @@ const echoContract = async (ctx) => { // await ctx.updateConfig(config); } +const fallback = async (ctx) => { + console.log("This is fallback mode"); + + const hpconfig = await ctx.getConfig(); + + for (const u of ctx.unl.list()) { + const gap = Math.abs(u.activeOn - ctx.timestamp); + // If last active timestamp is before the twice of roundtime, This node must be active. + if (u.activeOn && gap > (hpconfig.consensus.roundtime * 4)) { + console.log("Updating patch config", u); + hpconfig.unl = hpconfig.unl.filter(e => e !== u.publicKey); + await ctx.updateConfig(hpconfig); + } + } + + // NPL messages example. + // Start listening to incoming NPL messages before we send ours. + const promise = new Promise((resolve, reject) => { + let timeout = setTimeout(() => { + reject('NPL timeout.'); + }, 4000); + + let list = []; + ctx.unl.onMessage((node, msg) => { + console.log(`${node.publicKey} said ${msg} to me.`); + list.push(msg); + if (list.length == ctx.unl.list().length) { + clearTimeout(timeout); + resolve(); + } + }); + }); + + await ctx.unl.send("Hello"); + await promise; +} + const hpc = new HotPocket.Contract(); hpc.init(echoContract); \ No newline at end of file diff --git a/src/conf.cpp b/src/conf.cpp index 68d1dd01..227b62d8 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -194,6 +194,8 @@ namespace conf cfg.log.loggers.emplace("console"); cfg.log.loggers.emplace("file"); + cfg.hpsh.enabled = false; + // Save the default settings into the config file. if (write_config(cfg) != 0) return -1; @@ -512,6 +514,28 @@ namespace conf } } + // hpsh + { + jpath = "hpsh"; + + try + { + const jsoncons::ojson &hpsh = d["hpsh"]; + cfg.hpsh.enabled = hpsh["enabled"].as(); + + if (cfg.hpsh.run_as.from_string(hpsh["run_as"].as()) == -1) + { + std::cerr << "Invalid format for hpsh run as config (\"uid>0:gid>0\" expected).\n"; + return -1; + } + } + catch (const std::exception &e) + { + print_missing_field_error(jpath, e); + return -1; + } + } + return 0; } @@ -624,6 +648,14 @@ namespace conf d.insert_or_assign("log", log_config); } + // hpsh configs + { + jsoncons::ojson hpsh_config; + hpsh_config.insert_or_assign("enabled", cfg.hpsh.enabled); + hpsh_config.insert_or_assign("run_as", cfg.hpsh.run_as.to_string()); + d.insert_or_assign("hpsh", hpsh_config); + } + return write_json_file(ctx.config_file, d); } diff --git a/src/conf.hpp b/src/conf.hpp index a29a6294..b91764f4 100644 --- a/src/conf.hpp +++ b/src/conf.hpp @@ -208,6 +208,12 @@ namespace conf std::vector runtime_env_args; // Contract environment variables. }; + struct hpsh_config + { + bool enabled = false; // Whether or not to enable hpsh. + ugid run_as; // The user/groups id to execute the hpsh as. + }; + struct user_config { uint16_t port = 0; // Listening port for public user connections @@ -317,6 +323,7 @@ namespace conf hpfs_config hpfs; log_config log; health_config health; // For debugging only. Not included in the config file. + hpsh_config hpsh; }; // Global contract context struct exposed to the application. diff --git a/src/hpsh/hpsh.cpp b/src/hpsh/hpsh.cpp index e6994e59..50ac92e3 100644 --- a/src/hpsh/hpsh.cpp +++ b/src/hpsh/hpsh.cpp @@ -2,27 +2,27 @@ namespace hpsh { - constexpr const char *HPSH_EXEC_PATH = "./executable/hpsh"; - constexpr int MAX_BUFFER_LEN = 1024; - constexpr int POLL_TIMEOUT = 1000; + constexpr uint32_t POLL_TIMEOUT = 1000; constexpr uint32_t READ_BUFFER_SIZE = 128 * 1024; hpsh_context ctx; int init() { - std::cout << "Initializing hpsh process.." << std::endl; + // Do not initialize if disabled in config. + if (!conf::cfg.hpsh.enabled) + return 0; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ctx.control_fds) == -1) { - std::cerr << errno << "Error initializing socket pair." << std::endl; + LOG_ERROR << errno << ": Error initializing socket pair."; return -1; } ctx.hpsh_pid = fork(); if (ctx.hpsh_pid == -1) { - std::cerr << errno << "Error forking." << std::endl; + LOG_ERROR << errno << ": Error forking."; close(ctx.control_fds[0]); close(ctx.control_fds[1]); return -1; @@ -39,27 +39,41 @@ namespace hpsh close(ctx.control_fds[1]); - std::cout << "Starting hpsh process... " << std::endl; - std::string fd_str; fd_str.resize(10); snprintf(fd_str.data(), sizeof(fd_str), "%d", ctx.control_fds[0]); + char *argv[] = {(char *)conf::ctx.hpsh_exe_path.data(), fd_str.data(), NULL}; + + // Just before we execv the hpsh binary, we set user execution user/group if specified in hp config. + // (Must set gid before setting uid) + if (!conf::cfg.hpsh.run_as.empty() && (setgid(conf::cfg.hpsh.run_as.gid) == -1 || setuid(conf::cfg.hpsh.run_as.uid) == -1)) + { + std::cerr << errno << ": Hpsh process setgid/uid failed." + << "\n"; + exit(1); + } - char *argv[] = {(char *)HPSH_EXEC_PATH, (char *)("-s1"), fd_str.data(), NULL}; execv(argv[0], argv); - std::cerr << errno << "Error executing hpfs." << std::endl; + std::cerr << errno << ": Error executing hpsh." + << "\n"; close(ctx.control_fds[0]); - exit(EXIT_FAILURE); + exit(1); } + ctx.is_initialized = true; + + LOG_INFO << "Hpsh handler started."; + return 0; } void deinit() { - std::cout << "De-initializing hpsh process.." << std::endl; + // This is not initialized if disabled in config. + if (!conf::cfg.hpsh.enabled) + return; ctx.is_shutting_down = true; @@ -89,7 +103,7 @@ namespace hpsh } } - std::cout << "Stopped hpsh process.." << std::endl; + LOG_INFO << "Hpsh handler stopped."; } int check_hpsh_exited(const bool block) @@ -103,7 +117,7 @@ namespace hpsh } if (wait_res == -1) { - std::cerr << errno << ": hpsh process waitpid error. pid:" << ctx.hpsh_pid << std::endl; + LOG_ERROR << errno << ": Hpsh process waitpid error. pid:" << ctx.hpsh_pid; ctx.hpsh_pid = 0; return -1; } @@ -113,18 +127,18 @@ namespace hpsh if (WIFEXITED(scstatus)) { - std::cerr << "Contract process ended normally." << std::endl; + LOG_DEBUG << "Hpsh process ended normally."; return 1; } else { - std::cerr << "Contract process ended prematurely. Exit code " << WEXITSTATUS(scstatus) << std::endl; + LOG_WARNING << "Hpsh process ended prematurely. Exit code " << WEXITSTATUS(scstatus); return -1; } } } - int execute(std::string_view pubkey, std::string_view message) + int execute(std::string_view id, std::string_view pubkey, std::string_view message) { if (ctx.is_shutting_down) return -1; @@ -132,7 +146,7 @@ namespace hpsh int child_fds[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, child_fds) == -1) { - std::cerr << errno << "Error initializing socket pair." << std::endl; + LOG_ERROR << errno << ": Error initializing socket pair."; return -1; } @@ -161,7 +175,7 @@ namespace hpsh if (sendmsg(ctx.control_fds[1], &msg, 0) < 0) { - std::cerr << errno << "Error writing to control fd." << std::endl; + LOG_ERROR << errno << ": Error writing to control fd."; close(child_fds[0]); close(child_fds[1]); return -1; @@ -169,7 +183,7 @@ namespace hpsh if (write(child_fds[1], message.data(), sizeof(message)) < 0) { - std::cerr << errno << "Error writing to child fd." << std::endl; + LOG_ERROR << errno << ": Error writing to child fd."; close(child_fds[0]); close(child_fds[1]); return -1; @@ -177,7 +191,7 @@ namespace hpsh { std::scoped_lock lock(ctx.command_mutex); - ctx.commands.push_back(command_context{std::string(pubkey), {child_fds[0], child_fds[1]}, std::string(), false}); + ctx.commands.push_back(command_context{std::string(id), std::string(pubkey), {child_fds[0], child_fds[1]}, std::string(), false}); } return 0; @@ -203,7 +217,7 @@ namespace hpsh if (poll(&pfd, 1, POLL_TIMEOUT) == -1) { - std::cerr << errno << "Error in poll" << std::endl; + LOG_ERROR << errno << ": Error in poll"; continue; } else if (pfd.revents & POLLIN) @@ -219,7 +233,7 @@ namespace hpsh if (errno == EPIPE || errno == ECONNRESET) itr->read_completed = true; else - std::cerr << errno << "Error reading from fd" << std::endl; + LOG_ERROR << errno << ": Error reading from fd"; } } else @@ -230,10 +244,20 @@ namespace hpsh // Send command back to user; if (itr->read_completed) { - std::cout << "Received full output for user " << itr->pubkey << std::endl; - std::cout << itr->response.data() << std::endl; + { + std::scoped_lock lock(usr::ctx.users_mutex); - std::list collected_commands; + // Find the user session by user pubkey. + const auto user_itr = usr::ctx.users.find(itr->pubkey); + if (user_itr != usr::ctx.users.end()) // match found + { + const usr::connected_user &user = user_itr->second; + msg::usrmsg::usrmsg_parser parser(user.protocol); + std::vector msg; + parser.create_hpsh_response_container(msg, itr->id, itr->response); + user.session.send(msg); + } + } { std::scoped_lock lock(ctx.command_mutex); itr = ctx.commands.erase(itr); diff --git a/src/hpsh/hpsh.hpp b/src/hpsh/hpsh.hpp index db41dfd3..7f902cf2 100644 --- a/src/hpsh/hpsh.hpp +++ b/src/hpsh/hpsh.hpp @@ -1,27 +1,15 @@ #ifndef _HP_HPSH_ #define _HP_HPSH_ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "util.hpp" - +#include "../pchheader.hpp" +#include "../conf.hpp" +#include "../usr/usr.hpp" namespace hpsh { struct command_context { + std::string id; std::string pubkey; int child_fds[2]; std::string response; @@ -36,6 +24,7 @@ namespace hpsh int hpsh_pid; std::thread watcher_thread; bool is_shutting_down; + bool is_initialized = false; }; extern hpsh_context ctx; @@ -46,7 +35,7 @@ namespace hpsh int check_hpsh_exited(const bool block); - int execute(std::string_view pubkey, std::string_view message); + int execute(std::string_view id, std::string_view pubkey, std::string_view message); void response_watcher(); } diff --git a/src/hpsh/util.cpp b/src/hpsh/util.cpp deleted file mode 100644 index 2e9d97a0..00000000 --- a/src/hpsh/util.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "util.hpp" - -namespace util -{ - constexpr mode_t DIR_PERMS = 0755; - - /** - * Sleeps the current thread for specified no. of milliseconds. - */ - void sleep(const uint64_t milliseconds) - { - std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); - } - - // Applies signal mask to the calling thread. - void mask_signal() - { - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGINT); - sigaddset(&mask, SIGPIPE); - pthread_sigmask(SIG_BLOCK, &mask, NULL); - } - - /** - * Clears signal mask and signal handlers from the caller. - * Called by other processes forked from hpcore threads so they get detatched from - * the hpcore signal setup. - */ - void fork_detach() - { - // Restore signal handlers to defaults. - signal(SIGINT, SIG_DFL); - signal(SIGSEGV, SIG_DFL); - signal(SIGABRT, SIG_DFL); - - // Remove any signal masks applied by hpcore. - sigset_t mask; - sigemptyset(&mask); - pthread_sigmask(SIG_SETMASK, &mask, NULL); - - // Set process group id (so the terminal doesn't send kill signals to forked children). - setpgrp(); - } -} // namespace util diff --git a/src/hpsh/util.hpp b/src/hpsh/util.hpp deleted file mode 100644 index beb9833f..00000000 --- a/src/hpsh/util.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _HP_UTIL_UTIL_ -#define _HP_UTIL_UTIL_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * Contains helper functions and data structures used by multiple other subsystems. - */ - -namespace util -{ - void sleep(const uint64_t milliseconds); - - void mask_signal(); - - void fork_detach(); - -} // namespace util - -#endif diff --git a/src/msg/bson/usrmsg_bson.cpp b/src/msg/bson/usrmsg_bson.cpp index 7f8eb79c..2505e734 100644 --- a/src/msg/bson/usrmsg_bson.cpp +++ b/src/msg/bson/usrmsg_bson.cpp @@ -161,6 +161,31 @@ namespace msg::usrmsg::bson encoder.flush(); } + /** + * Constructs a hpsh response message. + * @param msg Buffer to construct the generated bson message into. + * Message format: + * { + * "type": "hpsh_response", + * "reply_for": "", + * "content": + * } + * @param content The contract binary output content to be put in the message. + */ + void create_hpsh_response_container(std::vector &msg, std::string_view reply_for, std::string_view content) + { + jsoncons::bson::bson_bytes_encoder encoder(msg); + encoder.begin_object(); + encoder.key(msg::usrmsg::FLD_TYPE); + encoder.string_value(msg::usrmsg::MSGTYPE_HPSH_RESPONSE); + encoder.key(msg::usrmsg::FLD_REPLY_FOR); + encoder.string_value(reply_for); + encoder.key(msg::usrmsg::FLD_CONTENT); + encoder.byte_string_value(content); + encoder.end_object(); + encoder.flush(); + } + /** * Constructs a contract read response message. * @param msg Buffer to construct the generated bson message into. @@ -196,7 +221,7 @@ namespace msg::usrmsg::bson * "ledger_hash": , * "outputs": [, , ...], // The output order is the hash generation order. * "output_hash": , [output hash = hash(pubkey+all outputs for the user)] - * "hash_tree": [], // Collapsed merkle tree with user's hash element marked as null. + * "hash_tree": [], // Collapsed merkle tree with user's hash element marked as null. * "unl_sig": [["", ""], ...] // Binary UNL pubkeys and signatures of root hash. * } * @param hash This user's combined output hash. [output hash = hash(pubkey+all outputs for the user)] @@ -466,7 +491,7 @@ namespace msg::usrmsg::bson /** * Extracts a contract read request message sent by user. - * + * * @param extracted_content The content to be passed to the contract, extracted from the message. * @param d The bson document holding the read request message. * Accepted signed input container format: @@ -497,30 +522,30 @@ namespace msg::usrmsg::bson return 0; } - /** - * Extracts a contract shell input message sent by user. - * - * @param extracted_content The content to be passed to the contract, extracted from the message. - * @param d The bson document holding the shell input message. + /** + * Extracts a hpsh input message sent by user. + * + * @param extracted_content The content to be passed to the hpsh, extracted from the message. + * @param d The bson document holding the hpsh input message. * Accepted signed input container format: * { - * "type": "contract_shell_input", + * "type": "hpsh_request", * "id": "", * "content": * } * @return 0 on successful extraction. -1 for failure. */ - int extract_shell_input(std::string &extracted_id, std::string &extracted_content, const jsoncons::ojson &d) + int extract_hpsh_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::ojson &d) { if (!d.contains(msg::usrmsg::FLD_ID) || !d[msg::usrmsg::FLD_ID].is()) { - LOG_DEBUG << "Shell input 'id' field missing or invalid."; + LOG_DEBUG << "Hpsh input 'id' field missing or invalid."; return -1; } if (!d.contains(msg::usrmsg::FLD_CONTENT) || !d[msg::usrmsg::FLD_CONTENT].is_byte_string_view()) { - LOG_DEBUG << "Shell input 'content' field missing or invalid."; + LOG_DEBUG << "Hpsh input 'content' field missing or invalid."; return -1; } @@ -532,9 +557,9 @@ namespace msg::usrmsg::bson /** * Extracts a signed input container message sent by user. - * + * * @param extracted_input_container The input container extracted from the message. - * @param extracted_sig The binary signature extracted from the message. + * @param extracted_sig The binary signature extracted from the message. * @param d The bson document holding the input container. * Accepted signed input container format: * { diff --git a/src/msg/bson/usrmsg_bson.hpp b/src/msg/bson/usrmsg_bson.hpp index 9a511f36..cc06be4f 100644 --- a/src/msg/bson/usrmsg_bson.hpp +++ b/src/msg/bson/usrmsg_bson.hpp @@ -17,6 +17,8 @@ namespace msg::usrmsg::bson void create_contract_input_status(std::vector &msg, std::string_view status, std::string_view reason, std::string_view input_hash, const uint64_t ledger_seq_no, const util::h32 &ledger_hash); + void create_hpsh_response_container(std::vector &msg, std::string_view reply_for, std::string_view content); + void create_contract_read_response_container(std::vector &msg, std::string_view reply_for, std::string_view content); void create_contract_output_container(std::vector &msg, std::string_view hash, const ::std::vector &outputs, @@ -43,7 +45,7 @@ namespace msg::usrmsg::bson int extract_read_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::ojson &d); - int extract_shell_input(std::string &extracted_id, std::string &extracted_content, const jsoncons::ojson &d); + int extract_hpsh_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::ojson &d); int extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig, const jsoncons::ojson &d); diff --git a/src/msg/json/usrmsg_json.cpp b/src/msg/json/usrmsg_json.cpp index a867e99d..58d271cb 100644 --- a/src/msg/json/usrmsg_json.cpp +++ b/src/msg/json/usrmsg_json.cpp @@ -34,7 +34,7 @@ namespace msg::usrmsg::json * Constructs user challenge message json and the challenge string required for * initial user challenge handshake. This gets called when a user establishes * a web socket connection to HP. - * + * * @param msg Buffer to construct the generated json message string into. * Message format: * { @@ -84,7 +84,7 @@ namespace msg::usrmsg::json /** * Constructs server challenge response message json. This gets sent when we receive * a challenge from the user. - * + * * @param msg Buffer to construct the generated json message string into. * Message format: * { @@ -325,6 +325,52 @@ namespace msg::usrmsg::json msg += "\"}"; } + /** + * Constructs a hpsh response message. + * @param msg Buffer to construct the generated json message string into. + * Message format: + * { + * "type": "hpsh_response", + * "reply_for": "", + * "content": "" + * } + * @param content The contract binary output content to be put in the message. + */ + void create_hpsh_response_container(std::vector &msg, std::string_view reply_for, std::string_view content) + { + msg.reserve(content.size() + 256); + msg += "{\""; + msg += msg::usrmsg::FLD_TYPE; + msg += SEP_COLON; + msg += msg::usrmsg::MSGTYPE_HPSH_RESPONSE; + msg += SEP_COMMA; + msg += msg::usrmsg::FLD_REPLY_FOR; + msg += SEP_COLON; + msg += reply_for; + msg += SEP_COMMA; + msg += msg::usrmsg::FLD_CONTENT; + msg += SEP_COLON_NOQUOTE; + + if (is_json_string(content)) + { + // Process the final string using jsoncons. + jsoncons::json jstring = content; + jsoncons::json_options options; + options.escape_all_non_ascii(true); + + std::string escaped_content; + jstring.dump(escaped_content); + + msg += escaped_content; + } + else + { + msg += content; + } + + msg += "}"; + } + /** * Constructs a contract read response message. * @param msg Buffer to construct the generated json message string into. @@ -381,7 +427,7 @@ namespace msg::usrmsg::json * "ledger_hash": "", * "outputs": ["", "", ...], // The output order is the hash generation order. * "output_hash": "", [output hash = hash(pubkey+all outputs for the user)] - * "hash_tree": [], // Collapsed merkle tree with user's hash element marked as null. + * "hash_tree": [], // Collapsed merkle tree with user's hash element marked as null. * "unl_sig": [["", ""], ...] // UNL pubkeys and signatures of root hash. * } * @param hash This user's combined output hash. [output hash = hash(pubkey+all outputs for the user)] @@ -566,12 +612,12 @@ namespace msg::usrmsg::json * { * "type": "health_event", * "event": "proposal" | "connectivity", - * + * * // proposal * "comm_latency": {min:0, max:0, avg:0}, * "read_latency": {min:0, max:0, avg:0} * "batch_size": 0 - * + * * // connectivity * "peer_count": 0, * "weakly_connected": true | false @@ -697,7 +743,7 @@ namespace msg::usrmsg::json /** * Verifies the user handshake response with the original challenge issued to the user * and the user public key contained in the response. - * + * * @param extracted_pubkeyhex The hex public key extracted from the response. * @param extracted_protocol The protocol code extracted from the response. * @param extracted_server_challenge Any server challenge issued by user. @@ -842,7 +888,7 @@ namespace msg::usrmsg::json /** * Extracts a contract read request message sent by user. - * + * * @param extracted_content The content to be passed to the contract, extracted from the message. * @param d The json document holding the read request message. * Accepted signed input container format: @@ -872,30 +918,30 @@ namespace msg::usrmsg::json return 0; } - /** - * Extracts a contract shell input message sent by user. - * - * @param extracted_content The content to be passed to the contract, extracted from the message. - * @param d The json document holding the shell input message. + /** + * Extracts a hpsh input message sent by user. + * + * @param extracted_content The content to be passed to the, extracted from the message. + * @param d The json document holding the hpsh input message. * Accepted signed input container format: * { - * "type": "contract_shell_input", + * "type": "hpsh_request", * "id": "", * "content": "" * } * @return 0 on successful extraction. -1 for failure. */ - int extract_shell_input(std::string &extracted_id, std::string &extracted_content, const jsoncons::json &d) + int extract_hpsh_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::json &d) { if (!d.contains(msg::usrmsg::FLD_ID) || !d[msg::usrmsg::FLD_ID].is()) { - LOG_DEBUG << "Shell input 'id' field missing or invalid."; + LOG_DEBUG << "Hpsh input 'id' field missing or invalid."; return -1; } if (!d.contains(msg::usrmsg::FLD_CONTENT) || !d[msg::usrmsg::FLD_CONTENT].is()) { - LOG_DEBUG << "Shell input 'content' field missing or invalid."; + LOG_DEBUG << "Hpsh input 'content' field missing or invalid."; return -1; } @@ -906,9 +952,9 @@ namespace msg::usrmsg::json /** * Extracts a signed input container message sent by user. - * + * * @param extracted_input_container The input container extracted from the message. - * @param extracted_sig The binary signature extracted from the message. + * @param extracted_sig The binary signature extracted from the message. * @param d The json document holding the input container. * Accepted signed input container format: * { diff --git a/src/msg/json/usrmsg_json.hpp b/src/msg/json/usrmsg_json.hpp index eef0e06c..ff5c827d 100644 --- a/src/msg/json/usrmsg_json.hpp +++ b/src/msg/json/usrmsg_json.hpp @@ -21,6 +21,8 @@ namespace msg::usrmsg::json void create_contract_input_status(std::vector &msg, std::string_view status, std::string_view reason, std::string_view input_hash, const uint64_t ledger_seq_no, const util::h32 &ledger_hash); + void create_hpsh_response_container(std::vector &msg, std::string_view reply_for, std::string_view content); + void create_contract_read_response_container(std::vector &msg, std::string_view reply_for, std::string_view content); void create_contract_output_container(std::vector &msg, std::string_view hash, const ::std::vector &outputs, @@ -47,7 +49,7 @@ namespace msg::usrmsg::json int extract_read_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::json &d); - int extract_shell_input(std::string &extracted_id, std::string &extracted_content, const jsoncons::json &d); + int extract_hpsh_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::json &d); int extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig, const jsoncons::json &d); diff --git a/src/msg/usrmsg_common.hpp b/src/msg/usrmsg_common.hpp index d8682e49..6844e578 100644 --- a/src/msg/usrmsg_common.hpp +++ b/src/msg/usrmsg_common.hpp @@ -80,8 +80,8 @@ namespace msg::usrmsg constexpr const char *MSGTYPE_SERVER_CHALLENGE_RESPONSE = "server_challenge_response"; constexpr const char *MSGTYPE_CONTRACT_READ_REQUEST = "contract_read_request"; constexpr const char *MSGTYPE_CONTRACT_READ_RESPONSE = "contract_read_response"; - constexpr const char *MSGTYPE_CONTRACT_SHELL_INPUT = "contract_shell_input"; - constexpr const char *MSGTYPE_CONTRACT_SHELL_OUTPUT = "contract_shell_output"; + constexpr const char *MSGTYPE_HPSH_REQUEST = "hpsh_request"; + constexpr const char *MSGTYPE_HPSH_RESPONSE = "hpsh_response"; constexpr const char *MSGTYPE_CONTRACT_INPUT = "contract_input"; constexpr const char *MSGTYPE_CONTRACT_INPUT_STATUS = "contract_input_status"; constexpr const char *MSGTYPE_CONTRACT_OUTPUT = "contract_output"; diff --git a/src/msg/usrmsg_parser.cpp b/src/msg/usrmsg_parser.cpp index d87822f4..69a3e4bd 100644 --- a/src/msg/usrmsg_parser.cpp +++ b/src/msg/usrmsg_parser.cpp @@ -38,6 +38,14 @@ namespace msg::usrmsg busrmsg::create_contract_input_status(msg, status, reason, input_hash, ledger_seq_no, ledger_hash); } + void usrmsg_parser::create_hpsh_response_container(std::vector &msg, std::string_view reply_for, std::string_view content) const + { + if (protocol == util::PROTOCOL::JSON) + jusrmsg::create_hpsh_response_container(msg, reply_for, content); + else + busrmsg::create_hpsh_response_container(msg, reply_for, content); + } + void usrmsg_parser::create_contract_read_response_container(std::vector &msg, std::string_view reply_for, std::string_view content) const { if (protocol == util::PROTOCOL::JSON) @@ -121,12 +129,12 @@ namespace msg::usrmsg return busrmsg::extract_read_request(extracted_id, extracted_content, bdoc); } - int usrmsg_parser::extract_shell_input(std::string &extracted_id, std::string &extracted_content) const + int usrmsg_parser::extract_hpsh_request(std::string &extracted_id, std::string &extracted_content) const { if (protocol == util::PROTOCOL::JSON) - return jusrmsg::extract_shell_input(extracted_id, extracted_content, jdoc); + return jusrmsg::extract_hpsh_request(extracted_id, extracted_content, jdoc); else - return busrmsg::extract_shell_input(extracted_id, extracted_content, bdoc); + return busrmsg::extract_hpsh_request(extracted_id, extracted_content, bdoc); } int usrmsg_parser::extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig) const diff --git a/src/msg/usrmsg_parser.hpp b/src/msg/usrmsg_parser.hpp index 8d721416..8ca9ce2d 100644 --- a/src/msg/usrmsg_parser.hpp +++ b/src/msg/usrmsg_parser.hpp @@ -26,6 +26,8 @@ namespace msg::usrmsg void create_contract_input_status(std::vector &msg, std::string_view status, std::string_view reason, std::string_view input_hash, const uint64_t ledger_seq_no, const util::h32 &ledger_hash) const; + void create_hpsh_response_container(std::vector &msg, std::string_view reply_for, std::string_view content) const; + void create_contract_read_response_container(std::vector &msg, std::string_view reply_for, std::string_view content) const; void create_contract_output_container(std::vector &msg, std::string_view hash, const ::std::vector &outputs, @@ -49,7 +51,7 @@ namespace msg::usrmsg int extract_read_request(std::string &extracted_id, std::string &extracted_content) const; - int extract_shell_input(std::string &extracted_id, std::string &extracted_content) const; + int extract_hpsh_request(std::string &extracted_id, std::string &extracted_content) const; int extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig) const; diff --git a/src/usr/usr.cpp b/src/usr/usr.cpp index 6871841c..096646dd 100644 --- a/src/usr/usr.cpp +++ b/src/usr/usr.cpp @@ -273,19 +273,13 @@ namespace usr user.session.send(resp); return 0; } - else if (msg_type == msg::usrmsg::MSGTYPE_CONTRACT_SHELL_INPUT) + else if (msg_type == msg::usrmsg::MSGTYPE_HPSH_REQUEST) { std::string id, content; - if (parser.extract_shell_input(id, content) != -1) + if (hpsh::ctx.is_initialized && parser.extract_hpsh_request(id, content) != -1) { - - LOG_INFO << "shell input received:" << content; - // std::string response = hpsh::serve(content.c_str()); - if (hpsh::execute(std::string("user_").append(std::to_string(1)), content.c_str()) == -1) - { - std::cout << "\nError sending message:" << content.c_str() << std::endl; - } - // LOG_INFO << "response: " << response; + if (hpsh::execute(id, user.pubkey, content.c_str()) == -1) + return -1; return 0; } diff --git a/test/bin/hpsh b/test/bin/hpsh index cf4cd294..eb008ec0 100755 Binary files a/test/bin/hpsh and b/test/bin/hpsh differ