From 9e983b70b2a94c2cc4b444dcabcfdae6ac93fb67 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 13 May 2020 22:01:40 +0200 Subject: [PATCH] plain_wallet api refactored due to ios app crash --- src/common/error_codes.h | 1 + src/wallet/plain_wallet_api.cpp | 141 ++++++++++++++++++++++++-------- 2 files changed, 108 insertions(+), 34 deletions(-) diff --git a/src/common/error_codes.h b/src/common/error_codes.h index 8feb9012..f8ad7898 100644 --- a/src/common/error_codes.h +++ b/src/common/error_codes.h @@ -34,5 +34,6 @@ #define API_RETURN_CODE_WRONG_SEED "WRONG_SEED" #define API_RETURN_CODE_GENESIS_MISMATCH "GENESIS_MISMATCH" #define API_RETURN_CODE_DISCONNECTED "DISCONNECTED" +#define API_RETURN_CODE_UNINITIALIZED "UNINITIALIZED" diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 0cc8d5e1..f6e0d9b8 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -27,21 +27,42 @@ #define GENERAL_INTERNAL_ERRROR_INIT "Failed to intialize library" //TODO: global objects, subject to refactoring -wallets_manager gwm; -std::atomic initialized(false); -std::atomic gjobs_counter(1); -std::map gjobs; -epee::critical_section gjobs_lock; -std::string gconfig_folder; +struct plain_wallet_instance +{ + plain_wallet_instance() :initialized(false), gjobs_counter(1) + {} + wallets_manager gwm; + std::atomic initialized; + + std::atomic gjobs_counter; + std::map gjobs; + epee::critical_section gjobs_lock; +}; + +std::shared_ptr ginstance_ptr; + +epee::misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&]() +{ + std::cout << "[LEAVE HANDLER CALLED]" << ENDL; +}); namespace plain_wallet { typedef epee::json_rpc::response error_response; + + std::string get_set_working_dir(bool need_to_set = false, const std::string val = "") + { + static std::string working_dir; + if (need_to_set) + working_dir = val; + return working_dir; + } + std::string get_bundle_working_dir() { - return gconfig_folder; + return get_set_working_dir(); // #ifdef WIN32 // return boost::dll::program_location().parent_path().string(); // #elif IOS_BUILD @@ -56,7 +77,7 @@ namespace plain_wallet } void set_bundle_working_dir(const std::string& dir) { - gconfig_folder = dir; + get_set_working_dir(true, dir); } std::string get_wallets_folder() @@ -102,15 +123,33 @@ namespace plain_wallet return "{}"; } + void deinit() + { + auto local_ptr = std::atomic_load(&ginstance_ptr); + if (local_ptr) + { + std::atomic_store(&ginstance_ptr, std::shared_ptr()); + //wait other callers finish + local_ptr->gjobs_lock.lock(); + local_ptr->gjobs_lock.unlock(); + local_ptr.reset(); + } + } + std::string init(const std::string& ip, const std::string& port, const std::string& working_dir, int log_level) { - if (initialized) + auto local_ptr = std::atomic_load(&ginstance_ptr); + if (local_ptr) { LOG_ERROR("Double-initialization in plain_wallet detected."); epee::json_rpc::response ok_response = AUTO_VAL_INIT(ok_response); ok_response.result.return_code = API_RETURN_CODE_ALREADY_EXISTS; return epee::serialization::store_t_to_json(ok_response); } + + std::cout << "[INIT PLAIN_WALLET_INSTANCE]" << ENDL; + std::shared_ptr ptr(new plain_wallet_instance()); + set_bundle_working_dir(working_dir); initialize_logs(log_level); @@ -122,13 +161,13 @@ namespace plain_wallet args[1] = const_cast(argss_1.c_str()); args[2] = const_cast(argss_2.c_str()); args[3] = nullptr; - if (!gwm.init(3, args, nullptr)) + if (!ptr->gwm.init(3, args, nullptr)) { LOG_ERROR("Failed to init wallets_manager"); return GENERAL_INTERNAL_ERRROR_INIT; } - if(!gwm.start()) + if(!ptr->gwm.start()) { LOG_ERROR("Failed to start wallets_manager"); return GENERAL_INTERNAL_ERRROR_INIT; @@ -155,7 +194,7 @@ namespace plain_wallet return epee::serialization::store_t_to_json(err_result); } - initialized = true; + std::atomic_store(&ginstance_ptr, ptr); epee::json_rpc::response ok_response = AUTO_VAL_INIT(ok_response); ok_response.result.return_code = API_RETURN_CODE_OK; return epee::serialization::store_t_to_json(ok_response); @@ -213,9 +252,21 @@ namespace plain_wallet return epee::serialization::store_t_to_json(ok_response); } +#define GET_INSTANCE_PTR(ptr_name) \ + auto ptr_name = std::atomic_load(&ginstance_ptr); \ + if (!ptr_name) \ + { \ + LOG_ERROR("Core already deinitialised or not initialized yet."); \ + epee::json_rpc::response ok_response = AUTO_VAL_INIT(ok_response); \ + ok_response.result.return_code = API_RETURN_CODE_UNINITIALIZED; \ + return epee::serialization::store_t_to_json(ok_response); \ + } + std::string get_connectivity_status() { - return gwm.get_connectivity_status(); + GET_INSTANCE_PTR(inst_ptr); + + return inst_ptr->gwm.get_connectivity_status(); } std::string get_version() @@ -254,16 +305,18 @@ namespace plain_wallet std::string open(const std::string& path, const std::string& password) { + GET_INSTANCE_PTR(inst_ptr); + std::string full_path = get_wallets_folder() + path; epee::json_rpc::response ok_response = AUTO_VAL_INIT(ok_response); - std::string rsp = gwm.open_wallet(epee::string_encoding::convert_to_unicode(full_path), password, 20, ok_response.result); + std::string rsp = inst_ptr->gwm.open_wallet(epee::string_encoding::convert_to_unicode(full_path), password, 20, ok_response.result); if (rsp == API_RETURN_CODE_OK || rsp == API_RETURN_CODE_FILE_RESTORED) { if (rsp == API_RETURN_CODE_FILE_RESTORED) { ok_response.result.recovered = true; } - gwm.run_wallet(ok_response.result.wallet_id); + inst_ptr->gwm.run_wallet(ok_response.result.wallet_id); return epee::serialization::store_t_to_json(ok_response); } @@ -271,18 +324,21 @@ namespace plain_wallet err_result.error.code = rsp; return epee::serialization::store_t_to_json(err_result); } + std::string restore(const std::string& seed, const std::string& path, const std::string& password) { + GET_INSTANCE_PTR(inst_ptr); + std::string full_path = get_wallets_folder() + path; epee::json_rpc::response ok_response = AUTO_VAL_INIT(ok_response); - std::string rsp = gwm.restore_wallet(epee::string_encoding::convert_to_unicode(full_path), password, seed, ok_response.result); + std::string rsp = inst_ptr->gwm.restore_wallet(epee::string_encoding::convert_to_unicode(full_path), password, seed, ok_response.result); if (rsp == API_RETURN_CODE_OK || rsp == API_RETURN_CODE_FILE_RESTORED) { if (rsp == API_RETURN_CODE_FILE_RESTORED) { ok_response.result.recovered = true; } - gwm.run_wallet(ok_response.result.wallet_id); + inst_ptr->gwm.run_wallet(ok_response.result.wallet_id); return epee::serialization::store_t_to_json(ok_response); } error_response err_result = AUTO_VAL_INIT(err_result); @@ -292,16 +348,18 @@ namespace plain_wallet std::string generate(const std::string& path, const std::string& password) { + GET_INSTANCE_PTR(inst_ptr); + std::string full_path = get_wallets_folder() + path; epee::json_rpc::response ok_response = AUTO_VAL_INIT(ok_response); - std::string rsp = gwm.generate_wallet(epee::string_encoding::convert_to_unicode(full_path), password, ok_response.result); + std::string rsp = inst_ptr->gwm.generate_wallet(epee::string_encoding::convert_to_unicode(full_path), password, ok_response.result); if (rsp == API_RETURN_CODE_OK || rsp == API_RETURN_CODE_FILE_RESTORED) { if (rsp == API_RETURN_CODE_FILE_RESTORED) { ok_response.result.recovered = true; } - gwm.run_wallet(ok_response.result.wallet_id); + inst_ptr->gwm.run_wallet(ok_response.result.wallet_id); return epee::serialization::store_t_to_json(ok_response); } error_response err_result = AUTO_VAL_INIT(err_result); @@ -311,34 +369,44 @@ namespace plain_wallet std::string close_wallet(hwallet h) { + GET_INSTANCE_PTR(inst_ptr); + std::string r = "{\"response\": \""; - r += gwm.close_wallet(h); + r += inst_ptr->gwm.close_wallet(h); r += "\"}"; return r; } std::string get_wallet_status(hwallet h) { - return gwm.get_wallet_status(h); + GET_INSTANCE_PTR(inst_ptr); + return inst_ptr->gwm.get_wallet_status(h); } + std::string invoke(hwallet h, const std::string& params) { - return gwm.invoke(h, params); + GET_INSTANCE_PTR(inst_ptr); + return inst_ptr->gwm.invoke(h, params); } void put_result(uint64_t job_id, const std::string& res) { - CRITICAL_REGION_LOCAL(gjobs_lock); - gjobs[job_id] = res; + auto inst_ptr = std::atomic_load(&ginstance_ptr); + if (!inst_ptr) + { + return; + } + CRITICAL_REGION_LOCAL(inst_ptr->gjobs_lock); + inst_ptr->gjobs[job_id] = res; LOG_PRINT_L2("[ASYNC_CALL]: Finished(result put), job id: " << job_id); } - std::string async_call(const std::string& method_name, uint64_t instance_id, const std::string& params) { + GET_INSTANCE_PTR(inst_ptr); std::function async_callback; - uint64_t job_id = gjobs_counter++; + uint64_t job_id = inst_ptr->gjobs_counter++; if (method_name == "close") { async_callback = [job_id, instance_id]() @@ -413,17 +481,22 @@ namespace plain_wallet std::string try_pull_result(uint64_t job_id) { - //TODO: need refactoring - CRITICAL_REGION_LOCAL(gjobs_lock); - auto it = gjobs.find(job_id); - if (it == gjobs.end()) - { - return "{\"delivered\": false}"; + auto inst_ptr = std::atomic_load(&ginstance_ptr); + if (!inst_ptr) + { + return "{\"status\": \"canceled\"}"; } - std::string res = "{\"delivered\": true, \"result\": "; + //TODO: need refactoring + CRITICAL_REGION_LOCAL(inst_ptr->gjobs_lock); + auto it = inst_ptr->gjobs.find(job_id); + if (it == inst_ptr->gjobs.end()) + { + return "{\"status\": \"idle\"}"; + } + std::string res = "{\"status\": \"delivered\", \"result\": "; res += it->second; res += " }"; - gjobs.erase(it); + inst_ptr->gjobs.erase(it); return res; }