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

View File

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

View File

@ -30,6 +30,8 @@
#include "WebSocket.h"
#include "base/CCDirector.h"
#include "base/CCScheduler.h"
#include "base/CCEventDispatcher.h"
#include "base/CCEventListenerCustom.h"
#include <thread>
#include <mutex>
@ -324,6 +326,13 @@ WebSocket::WebSocket()
}
__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()
@ -352,6 +361,9 @@ WebSocket::~WebSocket()
LOGD("ERROR: WebSocket instance (%p) wasn't added to the container which saves websocket instances!\n", this);
}
}
Director::getInstance()->getEventDispatcher()->removeEventListener(_resetDirectorListener);
*_isDestroyed = true;
}

View File

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

View File

@ -1,5 +1,6 @@
#include "WebSocketTest.h"
#include "../ExtensionsTest.h"
#include "testResource.h"
USING_NS_CC;
USING_NS_CC_EXT;
@ -7,6 +8,7 @@ USING_NS_CC_EXT;
WebSocketTests::WebSocketTests()
{
ADD_TEST_CASE(WebSocketTest);
ADD_TEST_CASE(WebSocketCloseTest);
}
WebSocketTest::WebSocketTest()
@ -256,3 +258,56 @@ void WebSocketTest::onMenuSendBinaryClicked(cocos2d::Ref *sender)
_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;
};
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__) */