cocos_android/Classes/JcWallet.cpp
2022-07-20 16:43:57 +08:00

170 lines
5.4 KiB
C++

#include "JcWallet.h"
#include "WalletEvent.h"
#include <atomic>
#include <iostream>
#include "stdarg.h"
#include <string>
#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<std::function<void()> > 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<std::mutex> 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<void()> func) {
AsyncTaskData *data = (AsyncTaskData *) asyn->data;
{
std::lock_guard<std::mutex> 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<JcWallet> 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<JSMethodParam> 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<char *>(result.c_str());
}
extern "C" {
void initEnv() {
if (!_isStarted) {
std::shared_ptr<JcWallet> 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<JSMethodParam> params(data);
RUN_IN_SERVERTHREAD(JcWallet::getInstance()->runJsMethod(params));
return "1";
}
}
NS_CC_END