Code cleanup

This commit is contained in:
JCash 2020-09-02 16:54:37 +02:00
parent 5de32250c3
commit 26a9ef0143
8 changed files with 242 additions and 136 deletions

57
docs/index.md Normal file
View File

@ -0,0 +1,57 @@
---
title: Defold websocket extension API documentation
brief: This manual covers how to use websockets with Defold
---
# Defold websocket extension API documentation
This extension supports both secure (`wss://`) and non secure (`ws://`) websocket connections.
All platforms should support this extension.
Here is how you connect to a websocket and listen to events:
```lua
local function websocket_callback(self, conn, data)
if data.event == websocket.EVENT_DISCONNECTED then
print("disconnected " .. conn)
self.connection = nil
elseif data.event == websocket.EVENT_CONNECTED then
print("Connected " .. conn)
-- self.connection = conn
elseif data.event == websocket.EVENT_ERROR then
print("Error:", data.error)
elseif data.event == websocket.EVENT_MESSAGE then
print("Receiving: '" .. tostring(data.message) .. "'")
end
end
function init(self)
self.url = "ws://echo.websocket.org"
local params = {}
self.connection = websocket.connect(self.url, params, websocket_callback)
end
function finalize(self)
if self.connection ~= nil then
websocket.disconnect(self.connection)
end
end
```
## Installation
To use this library in your Defold project, add the following URL to your `game.project` dependencies:
https://github.com/defold/extension-websocket/archive/master.zip
We recommend using a link to a zip file of a [specific release](https://github.com/defold/extension-websocket/releases).
## Source code
The source code is available on [GitHub](https://github.com/defold/extension-websocket)
## API reference
https://defold.com/extension-websocket/api/

View File

@ -16,7 +16,7 @@ background_color {
nodes {
position {
x: 10.0
y: 1113.0
y: 949.0
z: 0.0
w: 1.0
}
@ -78,7 +78,7 @@ nodes {
nodes {
position {
x: 214.0
y: 568.0
y: 314.0
z: 0.0
w: 1.0
}
@ -236,7 +236,7 @@ nodes {
nodes {
position {
x: 320.0
y: 438.0
y: 184.0
z: 0.0
w: 1.0
}
@ -394,7 +394,7 @@ nodes {
nodes {
position {
x: 320.0
y: 503.0
y: 249.0
z: 0.0
w: 1.0
}
@ -552,7 +552,7 @@ nodes {
nodes {
position {
x: 429.0
y: 568.0
y: 314.0
z: 0.0
w: 1.0
}
@ -710,7 +710,7 @@ nodes {
nodes {
position {
x: 320.0
y: 568.0
y: 314.0
z: 0.0
w: 1.0
}

View File

@ -57,22 +57,14 @@ end
local function websocket_callback(self, conn, data)
if data.event == websocket.EVENT_DISCONNECTED then
log("Disconnected: " .. tostring(conn))
self.connection = nil
update_gui(self)
if data.error then
log("Diconnect error:", data.error)
self.connection = nil
end
elseif data.event == websocket.EVENT_CONNECTED then
if data.error then
log("Connection error:", data.error)
self.connection = nil
end
update_gui(self)
log("Connected: " .. tostring(conn))
elseif data.event == websocket.EVENT_ERROR then
if data.error then
log("Error:", data.error)
end
log("Error: '" .. data.error .. "'")
elseif data.event == websocket.EVENT_MESSAGE then
log("Receiving: '" .. tostring(data.message) .. "'")
end
@ -84,9 +76,6 @@ local function connect(self, scheme)
self.url = scheme .. URL
log("Connecting to " .. self.url)
self.connection = websocket.connect(self.url, params, websocket_callback)
if self.connection == nil then
print("Failed to connect to " .. self.url .. ": " .. err)
end
end
local function disconnect(self)

View File

@ -5,8 +5,8 @@ main_collection = /examples/websocket.collectionc
shared_state = 1
[display]
width = 960
height = 640
width = 640
height = 960
[project]
title = extension-websocket

View File

@ -0,0 +1,119 @@
- name: websocket
type: table
desc: Functions and constants for using websockets. Supported on all platforms.
members:
#*****************************************************************************************************
- name: connect
type: function
desc: Connects to a remote address
parameters:
- name: url
type: string
desc: url of the remote connection
- name: params
type: table
desc: optional parameters as properties. The following parameters can be set
members:
- name: callback
type: function
desc: callback that receives all messages from the connection
parameters:
- name: self
type: object
desc: The script instance that was used to register the callback
- name: connection
type: object
desc: the connection
- name: data
type: table
desc: the event payload
members:
- name: event
type: number
desc: The current event. One of the following
- `websocket.EVENT_CONNECTED`
- `websocket.EVENT_DISCONNECTED`
- `websocket.EVENT_ERROR`
- `websocket.EVENT_MESSAGE`
- name: message
type: string
desc: The received data. Only valid if event is `websocket.EVENT_MESSAGE`
- name: error
type: string
desc: The error string. Only valid if event is `websocket.EVENT_ERROR`
returns:
- name: connection
type: object
desc: the connection
examples:
- desc: |-
```lua
local function websocket_callback(self, conn, data)
if data.event == websocket.EVENT_DISCONNECTED then
print("disconnected " .. conn)
self.connection = nil
elseif data.event == websocket.EVENT_CONNECTED then
print("Connected " .. conn)
-- self.connection = conn
elseif data.event == websocket.EVENT_ERROR then
print("Error:", data.error)
elseif data.event == websocket.EVENT_MESSAGE then
print("Receiving: '" .. tostring(data.message) .. "'")
end
end
function init(self)
self.url = "ws://echo.websocket.org"
local params = {}
self.connection = websocket.connect(self.url, params, websocket_callback)
end
function finalize(self)
if self.connection ~= nil then
websocket.disconnect(self.connection)
end
end
```
#*****************************************************************************************************
- name: disconnect
type: function
desc: Explicitly close a websocket
parameters:
- name: connection
type: object
desc: the websocket connection
#*****************************************************************************************************
- name: EVENT_CONNECTED
type: number
desc: The websocket was connected
- name: EVENT_DISCONNECTED
type: number
desc: The websocket disconnected
- name: EVENT_MESSAGE
type: number
desc: The websocket received data
- name: EVENT_ERROR
type: number
desc: The websocket encountered an error

View File

@ -24,21 +24,7 @@ struct WebsocketContext
} g_Websocket;
Result SetStatus(WebsocketConnection* conn, Result status, const char* format, ...)
{
if (conn->m_Status == RESULT_OK)
{
va_list lst;
va_start(lst, format);
conn->m_BufferSize = vsnprintf(conn->m_Buffer, conn->m_BufferCapacity, format, lst);
va_end(lst);
conn->m_Status = status;
}
return status;
}
static void HandleCallback(WebsocketConnection* conn, int event, const uint8_t* msg, size_t msg_len);
static void HandleCallback(WebsocketConnection* conn, int event);
#define STRING_CASE(_X) case _X: return #_X;
@ -71,7 +57,37 @@ const char* StateToString(State err)
#undef STRING_CASE
#define WS_DEBUG(...)
//#define WS_DEBUG dmLogWarning
//#define WS_DEBUG(...) dmLogWarning(__VA_ARGS__);
#define CLOSE_CONN(...) \
SetStatus(conn, RESULT_ERROR, __VA_ARGS__); \
CloseConnection(conn);
static void SetState(WebsocketConnection* conn, State state)
{
State prev_state = conn->m_State;
if (prev_state != state)
{
conn->m_State = state;
WS_DEBUG("%s -> %s", StateToString(prev_state), StateToString(conn->m_State));
}
}
Result SetStatus(WebsocketConnection* conn, Result status, const char* format, ...)
{
if (conn->m_Status == RESULT_OK)
{
va_list lst;
va_start(lst, format);
conn->m_BufferSize = vsnprintf(conn->m_Buffer, conn->m_BufferCapacity, format, lst);
va_end(lst);
conn->m_Status = status;
}
return status;
}
// ***************************************************************************************************
// LUA functions
@ -100,7 +116,7 @@ static WebsocketConnection* CreateConnection(const char* url)
static void DestroyConnection(WebsocketConnection* conn)
{
#if defined(HAVE_WSLAY)
if (conn->m_State == STATE_CONNECTED)
if (conn->m_Ctx)
WSL_Exit(conn->m_Ctx);
#endif
@ -126,9 +142,7 @@ static void CloseConnection(WebsocketConnection* conn)
#endif
}
conn->m_State = STATE_DISCONNECTED;
WS_DEBUG("%s -> %s", StateToString(prev_state), StateToString(conn->m_State));
SetState(conn, STATE_DISCONNECTED);
}
static int FindConnection(WebsocketConnection* conn)
@ -226,17 +240,14 @@ static int LuaSend(lua_State* L)
dmSocket::Result sr = Send(conn, string, string_length, 0);
if (dmSocket::RESULT_OK != sr)
{
conn->m_Status = RESULT_ERROR;
dmSnPrintf(conn->m_Buffer, conn->m_BufferCapacity, "Failed to send on websocket");
HandleCallback(conn, EVENT_ERROR, 0, 0);
CloseConnection(conn);
CLOSE_CONN("Failed to send on websocket");
}
#endif
return 0;
}
static void HandleCallback(WebsocketConnection* conn, int event, const uint8_t* msg, size_t msg_len)
static void HandleCallback(WebsocketConnection* conn, int event)
{
if (!dmScript::IsCallbackValid(conn->m_Callback))
return;
@ -257,17 +268,12 @@ static void HandleCallback(WebsocketConnection* conn, int event, const uint8_t*
lua_pushinteger(L, event);
lua_setfield(L, -2, "event");
lua_pushinteger(L, conn->m_Status);
lua_setfield(L, -2, "status");
if (conn->m_Status != RESULT_OK)
{
lua_pushstring(L, conn->m_Buffer);
if (EVENT_ERROR == event) {
lua_pushlstring(L, conn->m_Buffer, conn->m_BufferSize);
lua_setfield(L, -2, "error");
}
if (msg != 0) {
lua_pushlstring(L, (const char*)msg, msg_len);
else if (EVENT_MESSAGE == event) {
lua_pushlstring(L, conn->m_Buffer, conn->m_BufferSize);
lua_setfield(L, -2, "message");
}
@ -381,17 +387,18 @@ static dmExtension::Result WebsocketOnUpdate(dmExtension::Params* params)
{
uint32_t size = g_Websocket.m_Connections.Size();
#define CLOSE_CONN(MSG, ...) \
dmLogError(MSG, __VA_ARGS__); \
CloseConnection(conn);
for (uint32_t i = 0; i < size; ++i)
{
WebsocketConnection* conn = g_Websocket.m_Connections[i];
if (STATE_DISCONNECTED == conn->m_State)
{
HandleCallback(conn, EVENT_DISCONNECTED, 0, 0);
if (RESULT_OK != conn->m_Status)
{
HandleCallback(conn, EVENT_ERROR);
}
HandleCallback(conn, EVENT_DISCONNECTED);
g_Websocket.m_Connections.EraseSwap(i);
--i;
@ -415,7 +422,7 @@ static dmExtension::Result WebsocketOnUpdate(dmExtension::Params* params)
}
#else
int recv_bytes = 0;
dmSocket::Result sr = Receive(conn, conn->m_Buffer, conn->m_BufferCapacity, &recv_bytes);
dmSocket::Result sr = Receive(conn, conn->m_Buffer, conn->m_BufferCapacity-1, &recv_bytes);
if( sr == dmSocket::RESULT_WOULDBLOCK )
{
continue;
@ -424,19 +431,19 @@ static dmExtension::Result WebsocketOnUpdate(dmExtension::Params* params)
if (dmSocket::RESULT_OK == sr)
{
conn->m_BufferSize += recv_bytes;
conn->m_Buffer[conn->m_BufferCapacity-1] = 0;
conn->m_HasMessage = 1;
}
else
{
CLOSE_CONN("Websocket failed to receive data %s", dmSocket::ResultToString(sr));
conn->m_State = STATE_DISCONNECTED;
continue;
}
#endif
if (conn->m_HasMessage)
{
HandleCallback(conn, EVENT_MESSAGE, (uint8_t*)conn->m_Buffer, conn->m_BufferSize);
HandleCallback(conn, EVENT_MESSAGE);
conn->m_HasMessage = 0;
conn->m_BufferSize = 0;
}
@ -466,7 +473,6 @@ static dmExtension::Result WebsocketOnUpdate(dmExtension::Params* params)
int r = WSL_Init(&conn->m_Ctx, g_Websocket.m_BufferSize, (void*)conn);
if (0 != r)
{
SetStatus(conn, RESULT_FAIL_WSLAY_INIT, "Failed initializing wslay: %s", WSL_ResultToString(r));
CLOSE_CONN("Failed initializing wslay: %s", WSL_ResultToString(r));
continue;
}
@ -481,11 +487,9 @@ static dmExtension::Result WebsocketOnUpdate(dmExtension::Params* params)
conn->m_Buffer[0] = 0;
conn->m_BufferSize = 0;
conn->m_State = STATE_CONNECTED;
WS_DEBUG("STATE_HANDSHAKE -> STATE_CONNECTED");
HandleCallback(conn, EVENT_CONNECTED, 0, 0);
SetState(conn, STATE_CONNECTED);
HandleCallback(conn, EVENT_CONNECTED);
}
else if (STATE_HANDSHAKE_WRITE == conn->m_State)
{
@ -500,8 +504,7 @@ static dmExtension::Result WebsocketOnUpdate(dmExtension::Params* params)
continue;
}
conn->m_State = STATE_HANDSHAKE_READ;
WS_DEBUG("STATE_HANDSHAKE_WRITE -> STATE_HANDSHAKE_READ");
SetState(conn, STATE_HANDSHAKE_READ);
}
else if (STATE_CONNECTING == conn->m_State)
{
@ -519,9 +522,7 @@ static dmExtension::Result WebsocketOnUpdate(dmExtension::Params* params)
conn->m_Socket = dmConnectionPool::GetSocket(g_Websocket.m_Pool, conn->m_Connection);
conn->m_SSLSocket = dmConnectionPool::GetSSLSocket(g_Websocket.m_Pool, conn->m_Connection);
conn->m_State = STATE_HANDSHAKE_WRITE;
WS_DEBUG("STATE_CONNECTING -> STATE_HANDSHAKE");
SetState(conn, STATE_HANDSHAKE_WRITE);
}
}
@ -532,3 +533,4 @@ static dmExtension::Result WebsocketOnUpdate(dmExtension::Params* params)
DM_DECLARE_EXTENSION(Websocket, LIB_NAME, dmWebsocket::WebsocketAppInitialize, dmWebsocket::WebsocketAppFinalize, dmWebsocket::WebsocketInitialize, dmWebsocket::WebsocketOnUpdate, 0, dmWebsocket::WebsocketFinalize)
#undef CLOSE_CONN

View File

@ -79,7 +79,7 @@ namespace dmWebsocket
#ifdef __GNUC__
Result SetStatus(WebsocketConnection* conn, Result status, const char* fmt, ...) __attribute__ ((format (printf, 3, 4)));
#else
Result SetStatus(WebsocketCOnnection* conn, Result status, const char* fmt, ...);
Result SetStatus(WebsocketConnection* conn, Result status, const char* fmt, ...);
#endif
// Communication

View File

@ -80,22 +80,6 @@ ssize_t WSL_RecvCallback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len,
{
WebsocketConnection* conn = (WebsocketConnection*)user_data;
// struct Session *session = (struct Session*)user_data;
// ssize_t r;
// while((r = recv(session->fd, buf, len, 0)) == -1 && errno == EINTR);
// if(r == -1) {
// if(errno == EAGAIN || errno == EWOULDBLOCK) {
// wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
// } else {
// wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
// }
// } else if(r == 0) {
// /* Unexpected EOF is also treated as an error */
// wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
// r = -1;
// }
// return r;
int r = -1; // received bytes if >=0, error if < 0
dmSocket::Result socket_result = Receive(conn, buf, len, &r);
@ -119,36 +103,9 @@ ssize_t WSL_SendCallback(wslay_event_context_ptr ctx, const uint8_t *data, size_
{
WebsocketConnection* conn = (WebsocketConnection*)user_data;
// struct Session *session = (struct Session*)user_data;
// ssize_t r;
// int sflags = 0;
// // #ifdef MSG_MORE
// // if(flags & WSLAY_MSG_MORE) {
// // sflags |= MSG_MORE;
// // }
// // #endif // MSG_MORE
// while((r = send(session->fd, data, len, sflags)) == -1 && errno == EINTR);
// if(r == -1) {
// if(errno == EAGAIN || errno == EWOULDBLOCK) {
// wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
// } else {
// wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
// }
// }
// return r;
int sent_bytes = 0;
dmSocket::Result socket_result = Send(conn, (const char*)data, len, &sent_bytes);
// dmSocket::Result socket_result;
// int r = -1; // sent bytes if >=0, error if < 0
// do {
// socket_result = dmSocket::Send(conn->m_Socket, data, len, &r);
// }
// while (r == -1 && socket_result == dmSocket::RESULT_INTR);
if (socket_result != dmSocket::RESULT_OK)
{
if (socket_result == dmSocket::RESULT_WOULDBLOCK || socket_result == dmSocket::RESULT_TRY_AGAIN)
@ -174,24 +131,6 @@ void WSL_OnMsgRecvCallback(wslay_event_context_ptr ctx, const struct wslay_event
} else if (arg->opcode == WSLAY_CONNECTION_CLOSE)
{
// TODO: Store the reason
// close_code = arg->status_code;
// size_t len = arg->msg_length;
// close_reason = "";
// if (len > 2 /* first 2 bytes = close code */) {
// close_reason.parse_utf8((char *)arg->msg + 2, len - 2);
// }
// if (!wslay_event_get_close_sent(_data->ctx)) {
// if (_data->is_server) {
// WSLServer *helper = (WSLServer *)_data->obj;
// helper->_on_close_request(_data->id, close_code, close_reason);
// } else {
// WSLClient *helper = (WSLClient *)_data->obj;
// helper->_on_close_request(close_code, close_reason);
// }
// }
//SetStatus(conn, RESULT_NOT_CONNECTED, "Websocket received close event for %s", conn->m_Url.m_Hostname);
}
}