cwUi.h/cpp : Handle partial messages arriving from the websocket by buffering and reconstructing the message.

This commit is contained in:
kevin 2022-05-14 10:16:09 -04:00
parent f4852f7b90
commit 95b0d4f213
2 changed files with 73 additions and 9 deletions

View File

@ -86,6 +86,9 @@ namespace cw
appIdMapRecd_t* appIdMap; // map of application parent/child/js id's appIdMapRecd_t* appIdMap; // map of application parent/child/js id's
char* buf; // buf[bufN] output message formatting buffer char* buf; // buf[bufN] output message formatting buffer
unsigned bufN; // unsigned bufN; //
char* recvBuf;
unsigned recvBufN;
unsigned recvBufIdx;
unsigned* sessA; // sessA[ sessN ] array of wsSessId's unsigned* sessA; // sessA[ sessN ] array of wsSessId's
unsigned sessN; unsigned sessN;
@ -153,6 +156,7 @@ namespace cw
mem::release(p->sessA); mem::release(p->sessA);
mem::release(p->eleA); mem::release(p->eleA);
mem::release(p->buf); mem::release(p->buf);
mem::release(p->recvBuf);
mem::release(p); mem::release(p);
@ -1082,6 +1086,9 @@ cw::rc_t cw::ui::create(
p->sendCbArg = sendCbArg; p->sendCbArg = sendCbArg;
p->buf = mem::allocZ<char>(fmtBufByteN); p->buf = mem::allocZ<char>(fmtBufByteN);
p->bufN = fmtBufByteN; p->bufN = fmtBufByteN;
p->recvBuf = mem::allocZ<char>(fmtBufByteN);
p->recvBufN = fmtBufByteN;
p->recvBufIdx = 0;
// create the root element // create the root element
if((ele = _createBaseEle(p, nullptr, kRootAppId, kInvalidId, "uiDivId" )) == nullptr || ele->uuId != kRootUuId ) if((ele = _createBaseEle(p, nullptr, kRootAppId, kInvalidId, "uiDivId" )) == nullptr || ele->uuId != kRootUuId )
@ -1182,14 +1189,55 @@ cw::rc_t cw::ui::onDisconnect( handle_t h, unsigned wsSessId )
return kOkRC; return kOkRC;
} }
cw::rc_t cw::ui::onReceive( handle_t h, unsigned wsSessId, const void* msg, unsigned msgByteN ) cw::rc_t cw::ui::onReceive( handle_t h, unsigned wsSessId, const void* void_msg, unsigned msgByteN )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
ui_t* p = _handleToPtr(h); ui_t* p = _handleToPtr(h);
opId_t opId = _labelToOpId((const char*)msg); opId_t opId = kInvalidOpId;
value_t value; value_t value;
ele_t* ele; ele_t* ele;
const char* src_msg = (const char*)void_msg;
const char* msg = src_msg;
// if the incoming message is valid
if( msgByteN > 0 and src_msg != nullptr )
{
// if there is a partial msg in the recv buffer (recvBufIdx!=0)
// or the incoming message is a partial mesg - then buffer the message
// (Note: incoming messages that are not zero terminated are partial.")
if( p->recvBufIdx != 0 || src_msg[msgByteN-1] != 0 )
{
// verify the buffer is large enough to hold the msg
if(p->recvBufIdx + msgByteN > p->recvBufN )
{
rc = cwLogError(kOpFailRC,"The UI input buffer (%i) is too small.", p->recvBufN);
p->recvBufIdx = 0;
}
else
{
// update it with the incoming text
strncpy( p->recvBuf + p->recvBufIdx, src_msg, msgByteN );
p->recvBufIdx += msgByteN;
msg = p->recvBuf;
}
}
// if the incoming message is not zero terminated then it was a partial
// message it was buffered and there is nothing else to do.
if( src_msg[msgByteN-1] != 0)
return rc;
}
// the message is being processed so the buffer will end up empty
// (if it was being used)
p->recvBufIdx = 0;
// parse the 'opId' from the message
opId = _labelToOpId(msg);
switch( opId ) switch( opId )
{ {
case kInitOpId: case kInitOpId:
@ -1874,9 +1922,10 @@ namespace cw
cw::rc_t cw::ui::ws::parseArgs( const object_t& o, args_t& args, const char* object_label ) cw::rc_t cw::ui::ws::parseArgs( const object_t& o, args_t& args, const char* object_label )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
const object_t* op = &o; const object_t* op = &o;
char* uiCfgFn = nullptr; char* uiCfgFn = nullptr;
char* physRootDir = nullptr;
memset(&args,0,sizeof(args)); memset(&args,0,sizeof(args));
@ -1894,10 +1943,17 @@ cw::rc_t cw::ui::ws::parseArgs( const object_t& o, args_t& args, const char* ob
rc = cwLogError(rc,"'ui' cfg. parse failed."); rc = cwLogError(rc,"'ui' cfg. parse failed.");
} }
// expand the physical root directory
if((physRootDir = filesys::expandPath( args.physRootDir)) == nullptr )
{
rc = cwLogError(kInvalidArgRC,"The physical root directory of the UI cfg. is invalid.");
goto errLabel;
}
// if a default UI resource script was given then convert it into an object // if a default UI resource script was given then convert it into an object
if( uiCfgFn != nullptr ) if( uiCfgFn != nullptr )
{ {
char* fn = filesys::makeFn( args.physRootDir, uiCfgFn, nullptr, nullptr ); char* fn = filesys::makeFn( physRootDir, uiCfgFn, nullptr, nullptr );
if((rc = objectFromFile(fn,args.uiRsrc)) != kOkRC ) if((rc = objectFromFile(fn,args.uiRsrc)) != kOkRC )
rc = cwLogError(rc,"An error occurred while parsing the UI resource script in '%s'.", cwStringNullGuard(uiCfgFn)); rc = cwLogError(rc,"An error occurred while parsing the UI resource script in '%s'.", cwStringNullGuard(uiCfgFn));
@ -1905,6 +1961,9 @@ cw::rc_t cw::ui::ws::parseArgs( const object_t& o, args_t& args, const char* ob
mem::release(fn); mem::release(fn);
} }
errLabel:
mem::release(physRootDir);
return rc; return rc;
} }
@ -2029,7 +2088,7 @@ cw::rc_t cw::ui::ws::exec( handle_t h )
cwLogError(rc,"The UI websock execution failed."); cwLogError(rc,"The UI websock execution failed.");
// make the idle callback // make the idle callback
ui::onReceive( p->uiH, kInvalidId, "idle", strlen("idle") ); ui::onReceive( p->uiH, kInvalidId, "idle", strlen("idle")+1 );
return rc; return rc;
} }

7
cwUi.h
View File

@ -41,7 +41,12 @@ namespace cw
// A UI was disconnected // A UI was disconnected
rc_t onDisconnect( handle_t h, unsigned wsSessId ); rc_t onDisconnect( handle_t h, unsigned wsSessId );
// Receive a msg from a remote UI // Receive a msg from a remote UI.
//
// Note that individual messages are delinated with zero termination.
// Therefore a message which is not zero terminated is considered
// a partial message and will be buffered until the suffix of the message
// arrives.
rc_t onReceive( handle_t h, unsigned wsSessId, const void* msg, unsigned byteN ); rc_t onReceive( handle_t h, unsigned wsSessId, const void* msg, unsigned byteN );
// Locate an element whose parent uuid is 'parentUuId' with a child named 'eleName'. // Locate an element whose parent uuid is 'parentUuId' with a child named 'eleName'.