#include "JcWallet.h" #include "WalletEvent.h" #include #include #include "stdarg.h" #include #include "cocos/scripting/js-bindings/jswrapper/SeApi.h" #include "cocos/scripting/js-bindings/manual/jsb_global.h" #include "scripting/js-bindings/event/EventDispatcher.h" #include "scripting/js-bindings/manual/jsb_conversions.hpp" #include "platform/CCApplication.h" #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC) #include "AppDelegate.h" #endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) cocos2d::Application *cocos_android_app_init(int width, int height); #endif using namespace cocos2d; NS_CC_BEGIN cocos2d::Application *g_app = nullptr; JcWallet *JcWallet::_instance = nullptr; bool _isStarted = false; uv_async_t gasync = {0}; struct AsyncTaskData { std::mutex mtx; std::list > tasks; }; // run in server thread loop void flush_tasks_in_server_loop_cb(uv_async_t *asyn) { AsyncTaskData *data = (AsyncTaskData *) asyn->data; std::lock_guard guard(data->mtx); while (!data->tasks.empty()) { // fetch task, run task data->tasks.front()(); // drop task data->tasks.pop_front(); } } void init_libuv_async_handle(uv_async_t *async) { memset(async, 0, sizeof(uv_async_t)); uv_loop_t *loop = uv_default_loop(); uv_async_init(loop, async, cocos2d::flush_tasks_in_server_loop_cb); async->data = new AsyncTaskData(); uv_run(loop, UV_RUN_DEFAULT); } // run in game thread, dispatch runnable object into server loop void schedule_task_into_server_thread_task_queue(uv_async_t *asyn, std::function func) { AsyncTaskData *data = (AsyncTaskData *) asyn->data; { std::lock_guard guard(data->mtx); data->tasks.emplace_back(func); } //notify server thread to invoke `flush_tasks_in_server_loop_cb()` uv_async_send(asyn); } #define RUN_IN_SERVERTHREAD(task) do { \ schedule_task_into_server_thread_task_queue(&gasync, [=](){ \ task; \ }); \ } while(0) bool runGlobalMethod(const char *name, se::ValueArray args, se::Value *value) { se::AutoHandleScope scope; bool ok = false; auto global = se::ScriptEngine::getInstance()->getGlobalObject(); se::Value func; if (global->getProperty(name, &func) && func.isObject()) { ok = func.toObject()->call(args, global, value); } return ok; } bool addToArgArray(se::ValueArray *args, std::string strVal) { // std::string strVal(valChar); se::Value tmpVal; bool ok = true; ok &= std_string_to_seval(strVal, &tmpVal); args->push_back(tmpVal); return ok; } JcWallet::JcWallet() { JcWallet::_instance = this; } void JcWallet::initEnv() { if (!_isStarted) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC) g_app = new AppDelegate(1, 1); #elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) g_app = cocos_android_app_init(1, 1); #endif EventDispatcher::init(); g_app->start(); _isStarted = true; } } void JcWallet::initJSThread(std::shared_ptr wallet) { wallet->initEnv(); cocos2d::init_libuv_async_handle(&gasync); } JcWallet::~JcWallet() { EventDispatcher::destroy(); se::ScriptEngine::destroyInstance(); uv_loop_close(uv_default_loop()); JcWallet::_instance = nullptr; } char *JcWallet::runJsMethod(std::shared_ptr data) { se::ValueArray args; cocos2d::log("thread: %ld call method %s", uv_thread_self(), data->methodName.c_str()); for (int i = 0; i < data->paramList.size(); i++) { addToArgArray(&args, data->paramList[i]); } se::Value value; bool ok = runGlobalMethod(data->methodName.c_str(), args, &value); static std::string result; if (ok && !value.isNullOrUndefined()) { result = value.toString(); } else { result = ""; } cocos2d::log("method: %s ::result: %s", data->methodName.c_str(), result.c_str()); WalletEvent::Emit("wallet_inited", result.c_str()); return const_cast(result.c_str()); } extern "C" { void initEnv() { if (!_isStarted) { std::shared_ptr wallet(JcWallet::getInstance()); std::thread([=]() { JcWallet::initJSThread(wallet); }).detach(); } } char *runWalletMethod(const char *methodName, int paramCount, char **paramList) { JSMethodParam *data = new JSMethodParam(); std::string methodNameStr(methodName); data->methodName = methodNameStr; data->paramCount = paramCount; for (int i = 0; i < paramCount; i++) { char *arg = *(paramList + i); std::string strVal(arg); data->paramList.push_back(strVal); } std::shared_ptr params(data); RUN_IN_SERVERTHREAD(JcWallet::getInstance()->runJsMethod(params)); return "1"; } } NS_CC_END