Comments and rearrangment for clarity.

This commit is contained in:
Penn, John M 047828115 2019-08-21 10:52:48 -05:00
parent 2e08379e42
commit 63605da069
4 changed files with 166 additions and 121 deletions

View File

@ -28,6 +28,7 @@ LIBRARY DEPENDENCIES:
"values" : []
}
**************************************************************************/
#ifndef WSSESSION_HH
#define WSSESSION_HH
@ -40,6 +41,7 @@ LIBRARY DEPENDENCIES:
class VariableServerSession : public WebSocketSession {
public:
VariableServerSession(struct mg_connection *nc);
~VariableServerSession();
void stageData(); /* -- base */
void sendMessage(); /* -- base */
int handleMessage(std::string); /* -- base */

View File

@ -18,7 +18,7 @@ class VariableServerVariable {
public:
VariableServerVariable( REF2* variableType);
~VariableServerVariable();
~VariableServerVariable();
const char* getName();
void stageValue();
void writeValue( std::ostream& chkpnt_os );

View File

@ -12,51 +12,112 @@ LIBRARY DEPENDENCIES:
#include "../include/VariableServerSession.hh"
#include "../include/simpleJSON.hh"
// CONSTRUCTOR
VariableServerSession::VariableServerSession( struct mg_connection *nc ) : WebSocketSession(nc) {
intervalTimeTics = exec_get_time_tic_value(); // Default time interval is one second.
nextTime = LLONG_MAX;
cyclicSendEnabled = false;
}
// DESTRUCTOR
VariableServerSession::~VariableServerSession() {
clear();
}
// Base class virtual function.
void VariableServerSession::stageData() {
long long simulation_time_tics = exec_get_time_tics();
if ( cyclicSendEnabled && ( simulation_time_tics >= nextTime )) {
stageVariableValues();
}
nextTime = (simulation_time_tics - (simulation_time_tics % intervalTimeTics) + intervalTimeTics);
}
// Base class virtual function.
void VariableServerSession::sendMessage() {
std::vector<VariableServerVariable*>::iterator it;
std::stringstream ss;
ss << "{ \"msg_type\" : \"values\",\n";
ss << " \"time\" : " << std::setprecision(16) << stageTime << ",\n";
ss << " \"values\" : [\n";
for (it = sessionVariables.begin(); it != sessionVariables.end(); it++ ) {
if (it != sessionVariables.begin()) ss << ",\n";
(*it)->writeValue(ss);
}
ss << "]}" << std::endl;
std::string tmp = ss.str();
const char * message = tmp.c_str();
mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, message, strlen(message));
}
// Base class virtual function.
int VariableServerSession::handleMessage(std::string client_msg) {
int status = 0;
std::vector<Member*> members = parseJSON(client_msg.c_str());
std::vector<Member*>::iterator it;
const char *cmd;
const char *var_name;
int period;
for (it = members.begin(); it != members.end(); it++ ) {
if (strcmp((*it)->key, "cmd") == 0) {
cmd = (*it)->valText;
} else if (strcmp((*it)->key, "var_name") == 0) {
var_name = (*it)->valText;
} else if (strcmp((*it)->key, "period") == 0) {
period = atoi((*it)->valText);
}
}
if (cmd == NULL) {
printf ("No \"cmd\" member found in client message.\n");
status = 1;
} else if (strcmp(cmd, "var_add") == 0) {
addVariable( strdup(var_name) );
} else if ( strcmp(cmd, "var_cycle") == 0 ) {
setTimeInterval(period);
} else if ( strcmp(cmd, "var_pause") == 0 ) {
pause();
} else if ( strcmp(cmd, "var_unpause") == 0 ) {
unpause();
} else if ( strcmp(cmd, "var_send") == 0 ) {
stageVariableValues();
sendMessage();
} else if ( strcmp(cmd, "var_clear") == 0 ) {
clear();
} else if ( strcmp(cmd, "var_exit") == 0 ) {
//TODO
// nc->flags |= MG_F_SEND_AND_CLOSE;
} else {
sendErrorMessage("Unknown Command: \"%s\".\n", cmd);
status = 1;
}
return status;
}
// #include "trick/input_processor_proto.h"
// for( ii = 0 , jj = 0 ; ii <= msg_len ; ii++ ) {
// if ( incoming_msg[ii] != '\r' ) {
// stripped_msg[jj++] = incoming_msg[ii] ;
// }
// }
//
// ip_parse(stripped_msg); /* returns 0 if no parsing error */
// Remove characters from a string
// str.erase(std::remove(str.begin(), str.end(), '\r'), str.end());
void VariableServerSession::setTimeInterval(unsigned int milliseconds) {
intervalTimeTics = exec_get_time_tic_value() * milliseconds / 1000;
}
int VariableServerSession::bad_ref_int = 0 ;
REF2* VariableServerSession::make_error_ref(const char* in_name) {
REF2* new_ref;
new_ref = (REF2*)calloc(1, sizeof(REF2));
new_ref->reference = strdup(in_name) ;
new_ref->units = NULL ;
new_ref->address = (char *)&bad_ref_int ;
new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ;
new_ref->attr->type = TRICK_NUMBER_OF_TYPES ;
new_ref->attr->units = (char *)"--" ;
new_ref->attr->size = sizeof(int) ;
return new_ref;
}
#define MAX_MSG_SIZE 4096
int VariableServerSession::sendErrorMessage(const char* fmt, ... ) {
char errText[MAX_MSG_SIZE];
char msgText[MAX_MSG_SIZE];
va_list args;
errText[0]=0;
msgText[0]=0;
va_start(args, fmt);
(void) vsnprintf(errText, MAX_MSG_SIZE, fmt, args);
va_end(args);
sprintf(msgText, "{ \"msg_type\" : \"error\",\n"
" \"error\" : \"%s\"}\n", errText);
mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, msgText, strlen(msgText));
return (0);
}
void VariableServerSession::addVariable(char* vname){
REF2 * new_ref ;
new_ref = ref_attributes(vname);
@ -96,32 +157,6 @@ void VariableServerSession::stageVariableValues() {
}
}
void VariableServerSession::stageData() {
long long simulation_time_tics = exec_get_time_tics();
if ( cyclicSendEnabled && ( simulation_time_tics >= nextTime )) {
stageVariableValues();
}
nextTime = (simulation_time_tics - (simulation_time_tics % intervalTimeTics) + intervalTimeTics);
}
void VariableServerSession::sendMessage() {
std::vector<VariableServerVariable*>::iterator it;
std::stringstream ss;
ss << "{ \"msg_type\" : \"values\",\n";
ss << " \"time\" : " << std::setprecision(16) << stageTime << ",\n";
ss << " \"values\" : [\n";
for (it = sessionVariables.begin(); it != sessionVariables.end(); it++ ) {
if (it != sessionVariables.begin()) ss << ",\n";
(*it)->writeValue(ss);
}
ss << "]}" << std::endl;
std::string tmp = ss.str();
const char * message = tmp.c_str();
mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, message, strlen(message));
}
void VariableServerSession::pause() { cyclicSendEnabled = false; }
void VariableServerSession::unpause() { cyclicSendEnabled = true; }
@ -137,46 +172,37 @@ void VariableServerSession::clear() {
void VariableServerSession::exit() {}
int VariableServerSession::handleMessage(std::string client_msg) {
int VariableServerSession::bad_ref_int = 0 ;
int status = 0;
std::vector<Member*> members = parseJSON(client_msg.c_str());
std::vector<Member*>::iterator it;
const char *cmd;
const char *var_name;
int period;
#define MAX_MSG_SIZE 4096
int VariableServerSession::sendErrorMessage(const char* fmt, ... ) {
char errText[MAX_MSG_SIZE];
char msgText[MAX_MSG_SIZE];
va_list args;
for (it = members.begin(); it != members.end(); it++ ) {
if (strcmp((*it)->key, "cmd") == 0) {
cmd = (*it)->valText;
} else if (strcmp((*it)->key, "var_name") == 0) {
var_name = (*it)->valText;
} else if (strcmp((*it)->key, "period") == 0) {
period = atoi((*it)->valText);
}
}
errText[0]=0;
msgText[0]=0;
if (cmd == NULL) {
printf ("No \"cmd\" member found in client message.\n");
status = 1;
} else if (strcmp(cmd, "var_add") == 0) {
addVariable( strdup(var_name) );
} else if ( strcmp(cmd, "var_cycle") == 0 ) {
setTimeInterval(period);
} else if ( strcmp(cmd, "var_pause") == 0 ) {
pause();
} else if ( strcmp(cmd, "var_unpause") == 0 ) {
unpause();
} else if ( strcmp(cmd, "var_send") == 0 ) {
stageVariableValues();
sendMessage();
} else if ( strcmp(cmd, "var_clear") == 0 ) {
clear();
} else if ( strcmp(cmd, "var_exit") == 0 ) {
//TODO
} else {
sendErrorMessage("Unknown Command: \"%s\".\n", cmd);
status = 1;
}
return status;
va_start(args, fmt);
(void) vsnprintf(errText, MAX_MSG_SIZE, fmt, args);
va_end(args);
sprintf(msgText, "{ \"msg_type\" : \"error\",\n"
" \"error\" : \"%s\"}\n", errText);
mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, msgText, strlen(msgText));
return (0);
}
REF2* VariableServerSession::make_error_ref(const char* in_name) {
REF2* new_ref;
new_ref = (REF2*)calloc(1, sizeof(REF2));
new_ref->reference = strdup(in_name) ;
new_ref->units = NULL ;
new_ref->address = (char *)&bad_ref_int ;
new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ;
new_ref->attr->type = TRICK_NUMBER_OF_TYPES ;
new_ref->attr->units = (char *)"--" ;
new_ref->attr->size = sizeof(int) ;
return new_ref;
}

View File

@ -14,6 +14,7 @@ static const struct mg_str s_put_method = MG_MK_STR("PUT");
static const struct mg_str s_delete_method = MG_MK_STR("DELETE");
static const struct mg_str http_api_prefix = MG_MK_STR("/api/http/");
static const struct mg_str ws_api_prefix = MG_MK_STR("/api/ws/");
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
http_message *hm = (struct http_message *)ev_data;
@ -51,8 +52,9 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
} break;
case MG_EV_POLL: {
// The MG_EV_POLL event is sent to all connections for each invocation of mg_mgr_poll(),
// called periodically by the threaded function connectionAttendant() [below].
// Send websocket messages to the client (web browser).
// called periodically by the threaded function connectionAttendant() [below] when it is
// signaled (serviceConnections) from the http_top_of_frame job.
// This is when we send websocket messages to the client (web browser).
if (nc->flags & MG_F_IS_WEBSOCKET) {
httpServer->sendWebSocketSessionMessages(nc);
}
@ -99,12 +101,15 @@ static void* connectionAttendant (void* arg) {
return NULL;
}
// Install a WebSocketSessionMaker with a name (key) by which it can be retrieved.
void HTTP_Server::installWebSocketSessionMaker(std::string name, WebSocketSessionMaker maker) {
pthread_mutex_lock(&WebSocketSessionMakerMapLock);
WebSocketSessionMakerMap.insert(std::pair<std::string, WebSocketSessionMaker>(name, maker));
pthread_mutex_unlock(&WebSocketSessionMakerMapLock);
}
// Lookup and call the WebSocketSessionMaker function by name, end execute it to create and return
// (a pointer to) a WebSocketSession.
WebSocketSession* HTTP_Server::makeWebSocketSession(struct mg_connection *nc, std::string name) {
std::map<std::string, WebSocketSessionMaker>::iterator iter;
iter = WebSocketSessionMakerMap.find(name);
@ -117,12 +122,15 @@ WebSocketSession* HTTP_Server::makeWebSocketSession(struct mg_connection *nc, st
}
}
void HTTP_Server::installHTTPGEThandler(std::string APIname, httpMethodHandler handler) {
// Install an httpMethodHandler with a name (key) by which it can be retrieved.
void HTTP_Server::installHTTPGEThandler(std::string handlerName, httpMethodHandler handler) {
pthread_mutex_lock(&httpGETHandlerMapLock);
httpGETHandlerMap.insert(std::pair<std::string, httpMethodHandler>(APIname, handler));
httpGETHandlerMap.insert(std::pair<std::string, httpMethodHandler>(handlerName, handler));
pthread_mutex_unlock(&httpGETHandlerMapLock);
}
// Lookup the appropriate httpMethodHandler by name, and execute it for the given connection
// and http_message.
void HTTP_Server::handleHTTPGETrequest(struct mg_connection *nc, http_message *hm, std::string handlerName) {
std::map<std::string, httpMethodHandler>::iterator iter;
iter = httpGETHandlerMap.find(handlerName);
@ -134,9 +142,9 @@ void HTTP_Server::handleHTTPGETrequest(struct mg_connection *nc, http_message *h
}
}
// Find the session that goes with the given websocket connection,
// and tell it to send its values to the client (web browser).
void HTTP_Server::sendWebSocketSessionMessages(struct mg_connection *nc) {
// Find the session that goes with the given websocket connection,
// and tell it to send its values to the client (web browser).
std::map<mg_connection*, WebSocketSession*>::iterator iter;
iter = sessionMap.find(nc);
if (iter != sessionMap.end()) {
@ -145,6 +153,8 @@ void HTTP_Server::sendWebSocketSessionMessages(struct mg_connection *nc) {
}
}
// Delete the WebSocketSession associated with the given connection-pointer, and
// erase its pointer from the sessionMap.
void HTTP_Server::deleteWebSocketSession(struct mg_connection *nc) {
std::map<mg_connection*, WebSocketSession*>::iterator iter;
iter = sessionMap.find(nc);
@ -154,6 +164,9 @@ void HTTP_Server::deleteWebSocketSession(struct mg_connection *nc) {
sessionMap.erase(iter);
}
}
// Lookup the WebSocketSession associated with the given connection-pointer, and pass
// the given message to it.
void HTTP_Server::handleWebSocketClientMessage(struct mg_connection *nc, std::string msg) {
std::map<mg_connection*, WebSocketSession*>::iterator iter;
iter = sessionMap.find(nc);
@ -163,36 +176,40 @@ void HTTP_Server::handleWebSocketClientMessage(struct mg_connection *nc, std::st
}
}
// Install a WebSocketSession with a connection-pointer (key) by which it can be retrieved.
void HTTP_Server::addWebSocketSession(struct mg_connection *nc, WebSocketSession* session) {
pthread_mutex_lock(&sessionMapLock);
sessionMap.insert( std::pair<mg_connection*, WebSocketSession*>(nc, session) );
pthread_mutex_unlock(&sessionMapLock);
}
// =========================================================================
// Trick Sim Interface Functions
// =========================================================================
int HTTP_Server::http_default_data() {
port = "8888";
document_root = "www";
shutting_down = false;
return 0;
}
// WebSocketSessionMaker function for a VariableServerSession.
static WebSocketSession* makeVariableServerSession( struct mg_connection *nc ) {
return new VariableServerSession(nc);
}
int HTTP_Server::http_init() {
// =========================================================================
// Trick Sim Interface Functions
// =========================================================================
http_server_options.document_root = document_root;
http_server_options.enable_directory_listing = "yes";
// Trick "default_data" job.
int HTTP_Server::http_default_data() {
port = "8888";
document_root = "www";
shutting_down = false;
installHTTPGEThandler("vs_connections", &handle_HTTP_GET_vs_connections);
installHTTPGEThandler("alloc_info", &handle_HTTP_GET_alloc_info);
installWebSocketSessionMaker("VariableServer", &makeVariableServerSession);
//installWebSocketSessionMaker("VariableServer", [](struct mg_connection *nc) -> WebSocketSession* { return new VariableServerSession(nc); } );
return 0;
}
// Trick "initialization" job.
int HTTP_Server::http_init() {
http_server_options.document_root = document_root;
http_server_options.enable_directory_listing = "yes";
mg_mgr_init( &mgr, NULL );