Merge pull request #15135 from dumganhar/ws-close-fix

Closes websocket connection by dispatching a 'resetDirector' event.
This commit is contained in:
Ricardo Quesada 2016-03-10 17:39:47 -08:00
commit 9477bfd801
6 changed files with 97 additions and 4 deletions

View File

@ -61,7 +61,6 @@ THE SOFTWARE.
#include "base/CCConfiguration.h" #include "base/CCConfiguration.h"
#include "base/CCAsyncTaskPool.h" #include "base/CCAsyncTaskPool.h"
#include "platform/CCApplication.h" #include "platform/CCApplication.h"
#include "network/WebSocket.h"
#if CC_ENABLE_SCRIPT_BINDING #if CC_ENABLE_SCRIPT_BINDING
#include "CCScriptSupport.h" #include "CCScriptSupport.h"
@ -92,6 +91,7 @@ const char *Director::EVENT_AFTER_DRAW = "director_after_draw";
const char *Director::EVENT_AFTER_VISIT = "director_after_visit"; const char *Director::EVENT_AFTER_VISIT = "director_after_visit";
const char *Director::EVENT_BEFORE_UPDATE = "director_before_update"; const char *Director::EVENT_BEFORE_UPDATE = "director_before_update";
const char *Director::EVENT_AFTER_UPDATE = "director_after_update"; const char *Director::EVENT_AFTER_UPDATE = "director_after_update";
const char *Director::EVENT_RESET = "director_reset";
Director* Director::getInstance() Director* Director::getInstance()
{ {
@ -165,6 +165,7 @@ bool Director::init(void)
_eventAfterUpdate->setUserData(this); _eventAfterUpdate->setUserData(this);
_eventProjectionChanged = new (std::nothrow) EventCustom(EVENT_PROJECTION_CHANGED); _eventProjectionChanged = new (std::nothrow) EventCustom(EVENT_PROJECTION_CHANGED);
_eventProjectionChanged->setUserData(this); _eventProjectionChanged->setUserData(this);
_eventResetDirector = new (std::nothrow) EventCustom(EVENT_RESET);
//init TextureCache //init TextureCache
initTextureCache(); initTextureCache();
initMatrixStack(); initMatrixStack();
@ -194,6 +195,7 @@ Director::~Director(void)
delete _eventAfterDraw; delete _eventAfterDraw;
delete _eventAfterVisit; delete _eventAfterVisit;
delete _eventProjectionChanged; delete _eventProjectionChanged;
delete _eventResetDirector;
delete _renderer; delete _renderer;
@ -977,8 +979,7 @@ void Director::reset()
_runningScene = nullptr; _runningScene = nullptr;
_nextScene = nullptr; _nextScene = nullptr;
// Close all websocket connection. It has to be invoked before cleaning scheduler _eventDispatcher->dispatchEvent(_eventResetDirector);
network::WebSocket::closeAllConnections();
// cleanup scheduler // cleanup scheduler
getScheduler()->unscheduleAll(); getScheduler()->unscheduleAll();

View File

@ -102,6 +102,8 @@ public:
static const char* EVENT_BEFORE_UPDATE; static const char* EVENT_BEFORE_UPDATE;
/** Director will trigger an event after Schedule::update() is invoked. */ /** Director will trigger an event after Schedule::update() is invoked. */
static const char* EVENT_AFTER_UPDATE; static const char* EVENT_AFTER_UPDATE;
/** Director will trigger an event while resetting Director */
static const char* EVENT_RESET;
/** Director will trigger an event after Scene::render() is invoked. */ /** Director will trigger an event after Scene::render() is invoked. */
static const char* EVENT_AFTER_VISIT; static const char* EVENT_AFTER_VISIT;
/** Director will trigger an event after a scene is drawn, the data is sent to GPU. */ /** Director will trigger an event after a scene is drawn, the data is sent to GPU. */
@ -540,7 +542,7 @@ protected:
@since v3.0 @since v3.0
*/ */
EventDispatcher* _eventDispatcher; EventDispatcher* _eventDispatcher;
EventCustom *_eventProjectionChanged, *_eventAfterDraw, *_eventAfterVisit, *_eventBeforeUpdate, *_eventAfterUpdate; EventCustom *_eventProjectionChanged, *_eventAfterDraw, *_eventAfterVisit, *_eventBeforeUpdate, *_eventAfterUpdate, *_eventResetDirector;
/* delta time since last tick to main loop */ /* delta time since last tick to main loop */
float _deltaTime; float _deltaTime;

View File

@ -30,6 +30,8 @@
#include "WebSocket.h" #include "WebSocket.h"
#include "base/CCDirector.h" #include "base/CCDirector.h"
#include "base/CCScheduler.h" #include "base/CCScheduler.h"
#include "base/CCEventDispatcher.h"
#include "base/CCEventListenerCustom.h"
#include <thread> #include <thread>
#include <mutex> #include <mutex>
@ -324,6 +326,13 @@ WebSocket::WebSocket()
} }
__websocketInstances->push_back(this); __websocketInstances->push_back(this);
std::shared_ptr<bool> isDestroyed = _isDestroyed;
_resetDirectorListener = Director::getInstance()->getEventDispatcher()->addCustomEventListener(Director::EVENT_RESET, [this, isDestroyed](EventCustom*){
if (*isDestroyed)
return;
close();
});
} }
WebSocket::~WebSocket() WebSocket::~WebSocket()
@ -352,6 +361,9 @@ WebSocket::~WebSocket()
LOGD("ERROR: WebSocket instance (%p) wasn't added to the container which saves websocket instances!\n", this); LOGD("ERROR: WebSocket instance (%p) wasn't added to the container which saves websocket instances!\n", this);
} }
} }
Director::getInstance()->getEventDispatcher()->removeEventListener(_resetDirectorListener);
*_isDestroyed = true; *_isDestroyed = true;
} }

View File

@ -49,6 +49,8 @@ struct lws_protocols;
NS_CC_BEGIN NS_CC_BEGIN
class EventListenerCustom;
namespace network { namespace network {
class WsThreadHelper; class WsThreadHelper;
@ -240,6 +242,7 @@ private:
Delegate* _delegate; Delegate* _delegate;
int _SSLConnection; int _SSLConnection;
struct lws_protocols* _wsProtocols; struct lws_protocols* _wsProtocols;
EventListenerCustom* _resetDirectorListener;
}; };
} }

View File

@ -1,5 +1,6 @@
#include "WebSocketTest.h" #include "WebSocketTest.h"
#include "../ExtensionsTest.h" #include "../ExtensionsTest.h"
#include "testResource.h"
USING_NS_CC; USING_NS_CC;
USING_NS_CC_EXT; USING_NS_CC_EXT;
@ -7,6 +8,7 @@ USING_NS_CC_EXT;
WebSocketTests::WebSocketTests() WebSocketTests::WebSocketTests()
{ {
ADD_TEST_CASE(WebSocketTest); ADD_TEST_CASE(WebSocketTest);
ADD_TEST_CASE(WebSocketCloseTest);
} }
WebSocketTest::WebSocketTest() WebSocketTest::WebSocketTest()
@ -256,3 +258,56 @@ void WebSocketTest::onMenuSendBinaryClicked(cocos2d::Ref *sender)
_sendBinaryStatus->setString(warningStr.c_str()); _sendBinaryStatus->setString(warningStr.c_str());
} }
} }
WebSocketCloseTest::WebSocketCloseTest()
: _wsiTest(nullptr)
{
auto winSize = Director::getInstance()->getWinSize();
_wsiTest = new network::WebSocket();
if (!_wsiTest->init(*this, "ws://echo.websocket.org"))
{
CC_SAFE_DELETE(_wsiTest);
}
auto closeItem = MenuItemImage::create(s_pathClose, s_pathClose, [](Ref* sender){
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
});
closeItem->setPosition(VisibleRect::right().x / 2, VisibleRect::top().y * 2 / 3);
auto menu = Menu::create(closeItem, nullptr);
menu->setPosition(Vec2::ZERO);
addChild(menu, 1);
auto notifyLabel = Label::createWithTTF("See log window, when enter there's should have\n'Websocket opened' log,\nwhen close there's should have'websocket closed' log", "fonts/arial.ttf", 20);
notifyLabel->setPosition(VisibleRect::right().x / 2, VisibleRect::top().y / 3);
notifyLabel->setAlignment(TextHAlignment::CENTER);
addChild(notifyLabel, 1);
}
// Delegate methods
void WebSocketCloseTest::onOpen(network::WebSocket* ws)
{
log("Websocket (%p) opened", ws);
}
void WebSocketCloseTest::onMessage(network::WebSocket* ws, const network::WebSocket::Data& data)
{
log("Websocket get message from %p", ws);
}
void WebSocketCloseTest::onClose(network::WebSocket* ws)
{
log("websocket (%p) closed.", ws);
CC_SAFE_DELETE(ws);
}
void WebSocketCloseTest::onError(network::WebSocket* ws, const network::WebSocket::ErrorCode& error)
{
log("Error was fired, error code: %d", error);
}

View File

@ -52,4 +52,24 @@ private:
int _sendBinaryTimes; int _sendBinaryTimes;
}; };
class WebSocketCloseTest : public TestCase
, public cocos2d::network::WebSocket::Delegate
{
public:
CREATE_FUNC(WebSocketCloseTest);
virtual void onOpen(cocos2d::network::WebSocket* ws)override;
virtual void onMessage(cocos2d::network::WebSocket* ws, const cocos2d::network::WebSocket::Data& data)override;
virtual void onClose(cocos2d::network::WebSocket* ws)override;
virtual void onError(cocos2d::network::WebSocket* ws, const cocos2d::network::WebSocket::ErrorCode& error)override;
WebSocketCloseTest();
virtual std::string title() const override { return "WebSocket close by resetDirector event Test"; }
std::string subtitle() const override { return "Click close button, Program should close without crash."; }
private:
cocos2d::network::WebSocket* _wsiTest;
};
#endif /* defined(__TestCpp__WebSocketTest__) */ #endif /* defined(__TestCpp__WebSocketTest__) */