| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- /****************************************************************************
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos.com
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated engine source code (the "Software"), a limited,
- worldwide, royalty-free, non-assignable, revocable and non-exclusive license
- to use Cocos Creator solely to develop games on your target platforms. You shall
- not use Cocos Creator software for developing other software or tools that's
- used for developing games. You are not granted to publish, distribute,
- sublicense, and/or sell copies of Cocos Creator.
- The software or tools in this License Agreement are licensed, not sold.
- Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
- #include "jsb_socketio.hpp"
- #include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
- #include "cocos/scripting/js-bindings/manual/jsb_conversions.hpp"
- #include "cocos/scripting/js-bindings/manual/jsb_global.h"
- #include "cocos/network/SocketIO.h"
- #include "base/ccUTF8.h"
- #include "platform/CCApplication.h"
- using namespace cocos2d;
- using namespace cocos2d::network;
- se::Class* __jsb_SocketIO_class = nullptr;
- class JSB_SocketIODelegate : public Ref, public SocketIO::SIODelegate
- {
- public:
- //c++11 map to callbacks
- typedef std::unordered_map<std::string/* eventName */, se::ValueArray/* 0:callbackFunc, 1:target */> JSB_SIOCallbackRegistry;
- JSB_SocketIODelegate()
- {
- }
- virtual ~JSB_SocketIODelegate()
- {
- CCLOGINFO("In the destructor of JSB_SocketIODelegate(%p)", this);
- }
- virtual void onConnect(SIOClient* client) override
- {
- }
- virtual void onMessage(SIOClient* client, const std::string& data) override
- {
- }
- virtual void onClose(SIOClient* client) override
- {
- CCLOG("JSB SocketIO::SIODelegate->onClose method called from native");
- this->fireEventToScript(client, "disconnect", "");
- auto iter = se::NativePtrToObjectMap::find(client);
- if (iter != se::NativePtrToObjectMap::end())
- {
- iter->second->unroot();
- }
- if (getReferenceCount() == 1)
- {
- autorelease();
- }
- else
- {
- release();
- }
- }
- virtual void onError(SIOClient* client, const std::string& data) override
- {
- CCLOG("JSB SocketIO::SIODelegate->onError method called from native with data: %s", data.c_str());
- this->fireEventToScript(client, "error", data);
- auto iter = se::NativePtrToObjectMap::find(client);
- if (iter != se::NativePtrToObjectMap::end())
- {
- iter->second->unroot();
- }
- }
- virtual void fireEventToScript(SIOClient* client, const std::string& eventName, const std::string& data) override
- {
- CCLOG("JSB SocketIO::SIODelegate->fireEventToScript method called from native with name '%s' data: %s", eventName.c_str(), data.c_str());
- se::ScriptEngine::getInstance()->clearException();
- se::AutoHandleScope hs;
- if (cocos2d::Application::getInstance() == nullptr)
- return;
- auto iter = se::NativePtrToObjectMap::find(client); //IDEA: client probably be a new value with the same address as the old one, it may cause undefined result.
- if (iter == se::NativePtrToObjectMap::end())
- return;
- se::Value dataVal;
- if (data.empty())
- {
- dataVal.setNull();
- }
- else
- {
- dataVal.setString(data);
- }
- JSB_SIOCallbackRegistry::iterator it = _eventRegistry.find(eventName);
- if (it != _eventRegistry.end())
- {
- const se::ValueArray& cbStruct = it->second;
- assert(cbStruct.size() == 2);
- const se::Value& callback = cbStruct[0];
- const se::Value& target = cbStruct[1];
- if (callback.isObject() && callback.toObject()->isFunction() && target.isObject())
- {
- se::ValueArray args;
- args.push_back(dataVal);
- callback.toObject()->call(args, target.toObject());
- }
- }
- if (eventName == "disconnect")
- {
- cocos2d::log("disconnect ... "); //IDEA:
- }
- }
- void addEvent(const std::string& eventName, const se::Value& callback, const se::Value& target)
- {
- assert(callback.isObject() && callback.toObject()->isFunction());
- assert(target.isObject());
- _eventRegistry[eventName].clear();
- _eventRegistry[eventName].push_back(callback);
- _eventRegistry[eventName].push_back(target);
- target.toObject()->attachObject(callback.toObject());
- }
- private:
- JSB_SIOCallbackRegistry _eventRegistry;
- };
- static bool SocketIO_finalize(se::State& s)
- {
- SIOClient* cobj = (SIOClient*)s.nativeThisObject();
- CCLOGINFO("jsbindings: finalizing JS object %p (SocketIO)", cobj);
- cobj->disconnect();
- JSB_SocketIODelegate* delegate = static_cast<JSB_SocketIODelegate*>(cobj->getDelegate());
- if (delegate->getReferenceCount() == 1)
- {
- delegate->autorelease();
- }
- else
- {
- delegate->release();
- }
- cobj->release();
- return true;
- }
- SE_BIND_FINALIZE_FUNC(SocketIO_finalize)
- static bool SocketIO_prop_getTag(se::State& s)
- {
- SIOClient* cobj = (SIOClient*)s.nativeThisObject();
- s.rval().setString(cobj->getTag());
- return true;
- }
- SE_BIND_PROP_GET(SocketIO_prop_getTag)
- static bool SocketIO_prop_setTag(se::State& s)
- {
- SIOClient* cobj = (SIOClient*)s.nativeThisObject();
- cobj->setTag(s.args()[0].toString().c_str());
- return true;
- }
- SE_BIND_PROP_SET(SocketIO_prop_setTag)
- static bool SocketIO_send(se::State& s)
- {
- const auto& args = s.args();
- int argc = (int)args.size();
- SIOClient* cobj = (SIOClient*)s.nativeThisObject();
- if (argc == 1)
- {
- std::string payload;
- bool ok = seval_to_std_string(args[0], &payload);
- SE_PRECONDITION2(ok, false, "Converting payload failed!");
- cobj->send(payload);
- return true;
- }
- SE_REPORT_ERROR("Wrong number of arguments: %d, expected: %d", argc, 1);
- return false;
- }
- SE_BIND_FUNC(SocketIO_send)
- static bool SocketIO_emit(se::State& s)
- {
- const auto& args = s.args();
- int argc = (int)args.size();
- SIOClient* cobj = (SIOClient*)s.nativeThisObject();
- if (argc >= 1)
- {
- bool ok = false;
- std::string eventName;
- ok = seval_to_std_string(args[0], &eventName);
- SE_PRECONDITION2(ok, false, "Converting eventName failed!");
- std::string payload;
- if (argc >= 2)
- {
- const auto& arg1 = args[1];
- // Add this check to make it compatible with old version.
- // jsval_to_std_string in v1.6 returns empty string if arg1 is null or undefined
- // while seval_to_std_string since 1.7.2 follows JS standard to return "null" or "undefined".
- // Therefore, we need a workaround to make it be compatible with versions lower than v1.7.
- if (!arg1.isNullOrUndefined())
- {
- ok = seval_to_std_string(arg1, &payload);
- SE_PRECONDITION2(ok, false, "Converting payload failed!");
- }
- }
- cobj->emit(eventName, payload);
- return true;
- }
- SE_REPORT_ERROR("Wrong number of arguments: %d, expected: %d", argc, 2);
- return false;
- }
- SE_BIND_FUNC(SocketIO_emit)
- static bool SocketIO_disconnect(se::State& s)
- {
- const auto& args = s.args();
- int argc = (int)args.size();
- SIOClient* cobj = (SIOClient*)s.nativeThisObject();
- if (argc == 0)
- {
- cobj->disconnect();
- return true;
- }
- SE_REPORT_ERROR("Wrong number of arguments: %d, expected: %d", argc, 0);
- return false;
- }
- SE_BIND_FUNC(SocketIO_disconnect)
- static bool SocketIO_on(se::State& s)
- {
- const auto& args = s.args();
- int argc = (int)args.size();
- SIOClient* cobj = (SIOClient*)s.nativeThisObject();
- if (argc == 2)
- {
- bool ok = false;
- std::string eventName;
- ok = seval_to_std_string(args[0], &eventName);
- SE_PRECONDITION2(ok, false, "Converting eventName failed!");
- CCLOG("JSB SocketIO eventName to: '%s'", eventName.c_str());
- ((JSB_SocketIODelegate *)cobj->getDelegate())->addEvent(eventName, args[1], se::Value(s.thisObject()));
- return true;
- }
- SE_REPORT_ERROR("Wrong number of arguments: %d, expected: %d", argc, 2);
- return false;
- }
- SE_BIND_FUNC(SocketIO_on)
- // static
- static bool SocketIO_connect(se::State& s)
- {
- const auto& args = s.args();
- int argc = (int)args.size();
- CCLOG("JSB SocketIO.connect method called");
- if (argc >= 1 && argc <= 3)
- {
- std::string url;
- std::string caFilePath;
- bool ok = false;
- ok = seval_to_std_string(args[0], &url);
- SE_PRECONDITION2(ok, false, "Error processing arguments");
- if (argc == 2)
- {
- if (args[1].isObject())
- {
- // Just ignore the option argument
- }
- else if (args[1].isString())
- {
- // Assume it's CA root file path
- ok = seval_to_std_string(args[1], &caFilePath);
- SE_PRECONDITION2( ok, false, "Error processing arguments");
- }
- }
- if (argc == 3)
- {
- // Just ignore the option argument
- if (args[2].isString())
- {
- // Assume it's CA root file path
- ok = seval_to_std_string(args[2], &caFilePath);
- SE_PRECONDITION2( ok, false, "Error processing arguments");
- }
- }
- JSB_SocketIODelegate* siodelegate = new (std::nothrow) JSB_SocketIODelegate();
- CCLOG("Calling native SocketIO.connect method");
- SIOClient* ret = SocketIO::connect(url, *siodelegate, caFilePath);
- if (ret != nullptr)
- {
- ret->retain();
- siodelegate->retain();
- se::Object* obj = se::Object::createObjectWithClass(__jsb_SocketIO_class);
- obj->setPrivateData(ret);
- s.rval().setObject(obj);
- obj->root();
- return true;
- }
- else
- {
- siodelegate->release();
- SE_REPORT_ERROR("SocketIO.connect return nullptr!");
- return false;
- }
- }
- SE_REPORT_ERROR("JSB SocketIO.connect: Wrong number of arguments");
- return false;
- }
- SE_BIND_FUNC(SocketIO_connect)
- // static
- static bool SocketIO_close(se::State& s)
- {
- const auto& args = s.args();
- int argc = (int)args.size();
- if (argc == 0)
- {
- return true;
- }
- SE_REPORT_ERROR("Wrong number of arguments: %d, expected: %d", argc, 0);
- return false;
- }
- SE_BIND_FUNC(SocketIO_close)
- bool register_all_socketio(se::Object* obj)
- {
- se::Class* cls = se::Class::create("SocketIO", obj, nullptr, nullptr);
- cls->defineFinalizeFunction(_SE(SocketIO_finalize));
- cls->defineProperty("tag", _SE(SocketIO_prop_getTag), _SE(SocketIO_prop_setTag));
- cls->defineFunction("send", _SE(SocketIO_send));
- cls->defineFunction("emit", _SE(SocketIO_emit));
- cls->defineFunction("disconnect", _SE(SocketIO_disconnect));
- cls->defineFunction("on", _SE(SocketIO_on));
- cls->install();
-
- JSBClassType::registerClass<SocketIO>(cls);
- se::Value ctorVal;
- obj->getProperty("SocketIO", &ctorVal);
- ctorVal.toObject()->defineFunction("connect", _SE(SocketIO_connect));
- ctorVal.toObject()->defineFunction("close", _SE(SocketIO_close));
- __jsb_SocketIO_class = cls;
- se::ScriptEngine::getInstance()->clearException();
- return true;
- }
|