mirror of
https://github.com/nasa/trick.git
synced 2024-12-18 20:57:55 +00:00
This commit is contained in:
parent
adc3a3e425
commit
c011f27a2c
@ -4,45 +4,85 @@
|
||||
<title>WS Experiments</title>
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
table { border-collapse: collapse; width: 100%; }
|
||||
th, td { text-align: left; padding: 8px; }
|
||||
tr:nth-child(even){background-color: #f2f2f2}
|
||||
th { background-color: #562399; color: white; }
|
||||
</style>
|
||||
<header>
|
||||
</header>
|
||||
<section>
|
||||
</section>
|
||||
|
||||
<div class="variableDisplay"></div>
|
||||
<table class="variables">
|
||||
<tr>
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="output"></div>
|
||||
<script type="text/javascript">
|
||||
|
||||
function log(s) {
|
||||
var p = document.createElement("p");
|
||||
p.style.wordWrap = "break-word";
|
||||
p.textContent = s;
|
||||
output.appendChild(p);
|
||||
}
|
||||
function sendMessage(msg) {
|
||||
ws.send(msg);
|
||||
log("Message sent");
|
||||
//log("Sent : " + msg);
|
||||
}
|
||||
|
||||
function log(s) {
|
||||
var p = document.createElement("p");
|
||||
p.style.wordWrap = "break-word";
|
||||
p.textContent = s;
|
||||
output.appendChild(p);
|
||||
//console.log(s);
|
||||
// Interface to Trick WebSocket Variable Server
|
||||
function setPeriod(period) {
|
||||
sendMessage(`{ "cmd" : "var_cycle", "period" : "${period}" }`);
|
||||
}
|
||||
function addVariable(v) {
|
||||
sendMessage(`{ "cmd" : "var_add", "var_name" : "${v}" }`);
|
||||
|
||||
// create a row in the table that contains two <td>s, one for the var_name and one for its value.
|
||||
let tr = document.createElement('tr');
|
||||
let td1 = document.createElement('td');
|
||||
td1.textContent = `${v}`;
|
||||
let td2 = document.createElement('td');
|
||||
td2.textContent = "";
|
||||
td2.className = "values";
|
||||
tr.appendChild(td1);
|
||||
tr.appendChild(td2);
|
||||
varTable.appendChild(tr);
|
||||
}
|
||||
|
||||
var varTable = document.querySelector('table.variables');
|
||||
var ws = new WebSocket("ws://localhost:8888", "myProtocol");
|
||||
|
||||
// Event handler for the WebSocket connection opening
|
||||
// WebSocket Event Handlers
|
||||
ws.onopen = function(e) {
|
||||
log("Connection established");
|
||||
sendMessage("Hello WebSocket Server from Browser Client!");
|
||||
setPeriod(100);
|
||||
addVariable("dyn.cannon.pos[0]");
|
||||
addVariable("dyn.cannon.pos[1]");
|
||||
addVariable("dyn.cannon.vel[0]");
|
||||
addVariable("dyn.cannon.vel[1]");
|
||||
addVariable("I.dont.exist");
|
||||
sendMessage("{ \"cmd\" : \"var_unpause\" }");
|
||||
};
|
||||
// Event handler for receiving text messages
|
||||
ws.onmessage = function(e) {
|
||||
log(e.data);
|
||||
//log("Recieved : " + e.data);
|
||||
let msg = JSON.parse(e.data);
|
||||
if (msg.msg_type == "values") {
|
||||
let valueNodes = varTable.getElementsByClassName("values");
|
||||
for (let i = 0; i < msg.values.length; i++ ) {
|
||||
valueNodes[i].textContent = msg.values[i];
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
// Event handler for errors in the WebSocket object
|
||||
ws.onerror = function(e) {
|
||||
console.log("WebSocket Error: " , e);
|
||||
//Custom function for handling errors
|
||||
handleErrors(e);
|
||||
};
|
||||
// Event handler for closed connections
|
||||
ws.onclose = function(e) {
|
||||
console.log("Connection closed", e);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*************************************************************************
|
||||
PURPOSE: (Represent Websocket variable server connection.)
|
||||
LIBRARY DEPENDENCIES:
|
||||
( (../src/WSSession.cpp))
|
||||
( (../src/WSSession.o))
|
||||
**************************************************************************/
|
||||
#ifndef WSSESSION_HH
|
||||
#define WSSESSION_HH
|
||||
@ -9,6 +9,7 @@ LIBRARY DEPENDENCIES:
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
#include <mongoose.h>
|
||||
#include "WSSessionVariable.hh"
|
||||
|
||||
inline uint64_t to_nanoseconds(struct timespec* t) {
|
||||
return t->tv_sec * (uint64_t)1000000000L + t->tv_nsec;
|
||||
@ -19,18 +20,23 @@ class WSsession {
|
||||
public:
|
||||
WSsession( struct mg_connection *c );
|
||||
void setTimeInterval(unsigned int milliseconds);
|
||||
void addVariable(const char* vname);
|
||||
void addVariable(char* vname);
|
||||
void sendValues();
|
||||
void synchSend(); // This must be called at a frequency greater than or equal to the interval.
|
||||
void pause();
|
||||
void unpause();
|
||||
int emitError(const char* fmt, ... );
|
||||
|
||||
static int bad_ref_int ;
|
||||
|
||||
private:
|
||||
WSsession() {}
|
||||
REF2* make_error_ref(const char* in_name);
|
||||
struct mg_connection* connection;
|
||||
std::vector<const char*> varNames;
|
||||
std::vector<WSsessionVariable*> sessionVariables;
|
||||
struct timespec lastTime;
|
||||
struct timespec interval;
|
||||
bool enabled;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
@ -0,0 +1,35 @@
|
||||
/*************************************************************************
|
||||
PURPOSE: (Represent Websocket variable server variable.)
|
||||
LIBRARY DEPENDENCIES:
|
||||
( (../src/WSSessionVariable.o))
|
||||
**************************************************************************/
|
||||
#ifndef WSSESSIONVARIABLE_HH
|
||||
#define WSSESSIONVARIABLE_HH
|
||||
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
#include <mongoose.h>
|
||||
#include <iostream>
|
||||
#include <trick/reference.h>
|
||||
|
||||
#define MAX_ARRAY_LENGTH 4096
|
||||
|
||||
class WSsessionVariable {
|
||||
|
||||
public:
|
||||
WSsessionVariable( REF2* variableType);
|
||||
~WSsessionVariable();
|
||||
const char* getName();
|
||||
void write_value( std::ostream& chkpnt_os );
|
||||
|
||||
|
||||
private:
|
||||
WSsessionVariable() {}
|
||||
REF2 *varInfo;
|
||||
void *address;
|
||||
int size;
|
||||
void *buffer_in;
|
||||
void *buffer_out;
|
||||
bool deref;
|
||||
};
|
||||
#endif
|
@ -0,0 +1,21 @@
|
||||
/*************************************************************************
|
||||
PURPOSE: (Represent Websocket variable server connection.)
|
||||
LIBRARY DEPENDENCIES:
|
||||
( (../src/WSSession.o))
|
||||
**************************************************************************/
|
||||
#ifndef SIMPLEJSON_HH
|
||||
#define SIMPLEJSON_HH
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Member {
|
||||
public:
|
||||
const char* key;
|
||||
const char* valText;
|
||||
int type;
|
||||
Member(const char *k, const char *v, int t);
|
||||
};
|
||||
|
||||
std::vector<Member*> parseJSON( const char *json_s);
|
||||
|
||||
#endif
|
@ -1,4 +1,11 @@
|
||||
#include "trick/memorymanager_c_intf.h"
|
||||
#include "../include/WSSession.hh"
|
||||
#include <sstream>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
WSsession::WSsession( struct mg_connection *c ) {
|
||||
connection = c;
|
||||
@ -9,19 +16,109 @@ void WSsession::setTimeInterval(unsigned int milliseconds) {
|
||||
interval.tv_sec = milliseconds / 1000;
|
||||
interval.tv_nsec = (milliseconds % 1000) * 1000000L;
|
||||
}
|
||||
void WSsession::addVariable(const char* vname){
|
||||
varNames.push_back(vname);
|
||||
|
||||
int WSsession::bad_ref_int = 0 ;
|
||||
|
||||
REF2* WSsession::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;
|
||||
}
|
||||
void WSsession::sendValues() {
|
||||
std::vector<const char*>::iterator it;
|
||||
for (it = varNames.begin(); it != varNames.end(); it++ ) {
|
||||
// ==================================================================
|
||||
// FIXME: Get the values of the variables and send them to the client.
|
||||
// Currently we just send the names for testing.
|
||||
// ==================================================================
|
||||
mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, *it, strlen(*it));
|
||||
|
||||
//
|
||||
// #include "trick/exec_proto.h"
|
||||
// time = (double)exec_get_time_tics() / exec_get_time_tic_value() ;
|
||||
|
||||
//REF2* Trick::VariableServerThread::make_time_ref() {
|
||||
// REF2* new_ref;
|
||||
// new_ref = (REF2*)calloc(1, sizeof(REF2));
|
||||
// new_ref->reference = strdup("time") ;
|
||||
// new_ref->units = strdup("s") ;
|
||||
// new_ref->address = (char *)&time ;
|
||||
// new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ;
|
||||
// new_ref->attr->type = TRICK_DOUBLE ;
|
||||
// new_ref->attr->units = strdup("s") ;
|
||||
// new_ref->attr->size = sizeof(double) ;
|
||||
// return new_ref;
|
||||
//}
|
||||
|
||||
#define MAX_MSG_SIZE 4096
|
||||
int WSsession::emitError(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 WSsession::addVariable(char* vname){
|
||||
|
||||
REF2 * new_ref ;
|
||||
// if ( strcmp(vname, "time") == 0 ) {
|
||||
// new_ref = make_time_ref();
|
||||
// } else {
|
||||
new_ref = ref_attributes(vname) ;
|
||||
// }
|
||||
|
||||
if ( new_ref == NULL ) {
|
||||
emitError("Variable Server could not find variable %s.\n", vname);
|
||||
new_ref = make_error_ref(vname);
|
||||
} else if ( new_ref->attr ) {
|
||||
if ( new_ref->attr->type == TRICK_STRUCTURED ) {
|
||||
emitError("Variable Server: var_add cant add \"%s\" because its a composite variable.\n", vname);
|
||||
free(new_ref);
|
||||
new_ref = make_error_ref(vname);
|
||||
|
||||
} else if ( new_ref->attr->type == TRICK_STL ) {
|
||||
emitError("Variable Server: var_add cant add \"%s\" because its an STL variable.\n", vname);
|
||||
free(new_ref);
|
||||
new_ref = make_error_ref(vname);
|
||||
}
|
||||
} else {
|
||||
emitError("Variable Server: BAD MOJO - Missing ATTRIBUTES.");
|
||||
free(new_ref);
|
||||
new_ref = make_error_ref(vname);
|
||||
}
|
||||
|
||||
if ( new_ref != NULL ) {
|
||||
WSsessionVariable *sessionVariable = new WSsessionVariable( new_ref ) ;
|
||||
sessionVariables.push_back( sessionVariable ) ;
|
||||
}
|
||||
}
|
||||
|
||||
void WSsession::sendValues() {
|
||||
std::vector<WSsessionVariable*>::iterator it;
|
||||
std::stringstream ss;
|
||||
ss << "{ \"msg_type\" : \"values\",\n";
|
||||
ss << " \"values\" : [\n";
|
||||
for (it = sessionVariables.begin(); it != sessionVariables.end(); it++ ) {
|
||||
if (it != sessionVariables.begin()) ss << ",\n";
|
||||
(*it)->write_value(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 WSsession::synchSend() { // This must be called at a frequency greater than or equal to the interval.
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &now);
|
||||
@ -34,24 +131,3 @@ void WSsession::synchSend() { // This must be called at a frequency greater than
|
||||
}
|
||||
void WSsession::pause() { enabled = false;}
|
||||
void WSsession::unpause() { enabled = true; }
|
||||
|
||||
// int main ( int argc, char* argv[]) {
|
||||
// WSsessionMap wsmap;
|
||||
// struct mg_connection *c
|
||||
// WSsession* wsess = new WSsession(c);
|
||||
// struct timespec nap, t2;
|
||||
|
||||
// nap.tv_sec = 0;
|
||||
// nap.tv_nsec = 10000000L;
|
||||
//
|
||||
// wsess->setTimeInterval(500);
|
||||
// wsess->addVariable("dyn.cannon.pos[0]");
|
||||
// wsess->addVariable("dyn.cannon.pos[1]");
|
||||
// wsess->unpause();
|
||||
//
|
||||
// while(1) {
|
||||
// wsess->synchSend();
|
||||
// if ( nanosleep(&nap, &t2) < 0) { return -1; };
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
|
@ -0,0 +1,177 @@
|
||||
#include "trick/memorymanager_c_intf.h" // for get_size.
|
||||
#include "../include/WSSessionVariable.hh"
|
||||
#include <math.h> // for fpclassify
|
||||
#include <iomanip> // for setprecision
|
||||
|
||||
|
||||
|
||||
WSsessionVariable::WSsessionVariable(REF2 * ref ) {
|
||||
varInfo = ref;
|
||||
address = varInfo->address;
|
||||
size = varInfo->attr->size ;
|
||||
deref = false;
|
||||
|
||||
TRICK_TYPE string_type = varInfo->attr->type ;
|
||||
|
||||
if ( varInfo->num_index == varInfo->attr->num_index ) {
|
||||
// single value
|
||||
} else if ( varInfo->attr->index[varInfo->attr->num_index - 1].size != 0 ) {
|
||||
// Constrained array
|
||||
for ( int i = varInfo->attr->num_index-1; i > varInfo->num_index-1 ; i-- ) {
|
||||
size *= varInfo->attr->index[i].size ;
|
||||
}
|
||||
} else {
|
||||
// Unconstrained array
|
||||
if ((varInfo->attr->num_index - varInfo->num_index) > 1 ) {
|
||||
printf("Variable Server Error: var_add(%s) requests more than one dimension of dynamic array.\n", varInfo->reference);
|
||||
printf("Data is not contiguous so returned values are unpredictable.\n") ;
|
||||
}
|
||||
if ( varInfo->attr->type == TRICK_CHARACTER ) {
|
||||
string_type = TRICK_STRING ;
|
||||
deref = true;
|
||||
} else if ( varInfo->attr->type == TRICK_WCHAR ) {
|
||||
string_type = TRICK_WSTRING ;
|
||||
} else {
|
||||
deref = true ;
|
||||
size *= get_size((char*)address) ;
|
||||
}
|
||||
}
|
||||
|
||||
// handle strings: set a max buffer size, the copy size may vary so will be set in copy_sim_data
|
||||
if (( string_type == TRICK_STRING ) || ( string_type == TRICK_WSTRING )) {
|
||||
size = MAX_ARRAY_LENGTH ;
|
||||
}
|
||||
|
||||
buffer_in = calloc( size, 1 ) ;
|
||||
buffer_out = calloc( size, 1 ) ;
|
||||
|
||||
}
|
||||
|
||||
WSsessionVariable::~WSsessionVariable() {
|
||||
|
||||
if (buffer_in != NULL) free( buffer_in );
|
||||
if (buffer_out != NULL) free( buffer_out );
|
||||
if (varInfo != NULL) free( varInfo );
|
||||
}
|
||||
|
||||
|
||||
const char* WSsessionVariable::getName() {
|
||||
return varInfo->reference;
|
||||
}
|
||||
|
||||
static void write_quoted_str( std::ostream& os, const char* s) {
|
||||
int ii;
|
||||
int len = strlen(s);
|
||||
os << "\"" ;
|
||||
for (ii=0 ; ii<len ; ii++) {
|
||||
switch ((s)[ii]) {
|
||||
case '\n': os << "\\n"; break;
|
||||
case '\t': os << "\\t"; break;
|
||||
case '\b': os << "\\b"; break;
|
||||
case '\"': os << "\\\""; break;
|
||||
default : os << s[ii] ; break;
|
||||
}
|
||||
}
|
||||
os << "\"" ;
|
||||
}
|
||||
|
||||
void WSsessionVariable::write_value( std::ostream& outs ) {
|
||||
|
||||
switch(varInfo->attr->type) {
|
||||
case TRICK_UNSIGNED_CHARACTER:
|
||||
outs << std::dec << (int)*(unsigned char*)address ;
|
||||
break;
|
||||
case TRICK_BOOLEAN:
|
||||
if (*(bool*)address) {
|
||||
outs << "\"true\"" ;
|
||||
} else {
|
||||
outs << "\"false\"" ;
|
||||
}
|
||||
break;
|
||||
case TRICK_CHARACTER:
|
||||
if (isprint( *(char*)address) ) {
|
||||
outs << "'" << *(char*)address << "'" ;
|
||||
} else {
|
||||
unsigned int ch = *(unsigned char*)address;
|
||||
outs << "'\\x" << std::hex << ch << "'" ;
|
||||
}
|
||||
break;
|
||||
case TRICK_WCHAR:
|
||||
outs << std::dec << *(wchar_t*)address;
|
||||
break;
|
||||
case TRICK_SHORT:
|
||||
outs << std::dec << *(short*)address;
|
||||
break;
|
||||
case TRICK_UNSIGNED_SHORT:
|
||||
outs << std::dec << *(unsigned short*)address;
|
||||
break;
|
||||
case TRICK_INTEGER:
|
||||
outs << std::dec << *(int*)address;
|
||||
break;
|
||||
case TRICK_UNSIGNED_INTEGER:
|
||||
outs << std::dec << *(unsigned int*)address;
|
||||
break;
|
||||
case TRICK_LONG:
|
||||
outs << std::dec << *(long*)address;
|
||||
break;
|
||||
case TRICK_UNSIGNED_LONG:
|
||||
outs << std::dec << *(unsigned long*)address;
|
||||
break;
|
||||
case TRICK_FLOAT:
|
||||
if (fpclassify( *(float*)address) != FP_NAN) {
|
||||
outs << std::setprecision(8) << *(float*)address;
|
||||
} else {
|
||||
outs << "NAN";
|
||||
}
|
||||
break;
|
||||
case TRICK_DOUBLE:
|
||||
if (fpclassify( *(double*)address) != FP_NAN) {
|
||||
outs << std::setprecision(16) << *(double*)address;
|
||||
} else {
|
||||
outs << "NAN";
|
||||
}
|
||||
break;
|
||||
// case TRICK_BITFIELD: {
|
||||
// int sbf = 0;
|
||||
// src_addr = (char*)address + offset * (size_t)attr->size;
|
||||
// if (attr->size == sizeof(int)) {
|
||||
// sbf = extract_bitfield_any( *(int*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
|
||||
// } else if (attr->size == sizeof(short)) {
|
||||
// sbf = extract_bitfield_any( *(short*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
|
||||
// } else if (attr->size == sizeof(char)) {
|
||||
// sbf = extract_bitfield_any( *(char*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
|
||||
// } else {
|
||||
// message_publish(MSG_ERROR, "Checkpoint Agent INTERNAL ERROR:\n"
|
||||
// "Unsupported bitfield size (%d) bytes.\n", attr->size) ;
|
||||
// }
|
||||
// outs << std::dec << sbf;
|
||||
// } break;
|
||||
// case TRICK_UNSIGNED_BITFIELD: {
|
||||
// int bf = 0;
|
||||
// src_addr = (char*)address + offset * (size_t)attr->size;
|
||||
// if (attr->size == sizeof(int)) {
|
||||
// bf = extract_unsigned_bitfield_any( *(unsigned int*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
|
||||
// } else if (attr->size == sizeof(short)) {
|
||||
// bf = extract_unsigned_bitfield_any( *(unsigned short*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
|
||||
// } else if (attr->size == sizeof(char)) {
|
||||
// bf = extract_unsigned_bitfield_any( *(unsigned char*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
|
||||
// } else {
|
||||
// message_publish(MSG_ERROR, "Checkpoint Agent INTERNAL ERROR:\n"
|
||||
// "Unsupported bitfield size (%d) bytes.\n", attr->size) ;
|
||||
// }
|
||||
// outs << std::dec << bf;
|
||||
// } break;
|
||||
case TRICK_LONG_LONG:
|
||||
outs << std::dec << *(long long*)address;
|
||||
break;
|
||||
case TRICK_UNSIGNED_LONG_LONG:
|
||||
outs << std::dec << *(unsigned long long*)address;
|
||||
break;
|
||||
case TRICK_STRING:
|
||||
write_quoted_str(outs, (*(std::string*)address).c_str());
|
||||
break;
|
||||
default:
|
||||
outs << "\"Error\""; // ERROR
|
||||
break;
|
||||
}
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
/************************************************************************
|
||||
PURPOSE: (Represent the state and initial conditions of an http server)
|
||||
LIBRARY DEPENDENCIES:
|
||||
((WSSession.o))
|
||||
(
|
||||
(WSSession.o)
|
||||
(WSSessionVariable.o)
|
||||
(simpleJSON.o)
|
||||
)
|
||||
**************************************************************************/
|
||||
/*
|
||||
Messages sent from Client to Server
|
||||
@ -26,20 +30,16 @@ Messages sent from Server to Client
|
||||
{ "msg_type" : "var_list"
|
||||
"values" : []
|
||||
}
|
||||
|
||||
LEXEMES:
|
||||
{
|
||||
}
|
||||
"[^""]"
|
||||
:
|
||||
,
|
||||
[0-9]+
|
||||
}
|
||||
*/
|
||||
#include "../include/http_server.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
//#include <glib.h>
|
||||
//#include <json-glib/json-glib.h>
|
||||
#include "../include/http_server.h"
|
||||
#include "../include/WSSession.hh"
|
||||
#include "../include/simpleJSON.hh"
|
||||
|
||||
#include "trick/VariableServer.hh"
|
||||
extern Trick::VariableServer * the_vs ;
|
||||
@ -92,7 +92,55 @@ void handle_HTTP_GET_alloc_info(struct mg_connection *nc, struct http_message *h
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
int handle_JSON_var_server_msg (WSsession* session, const char* client_msg) {
|
||||
|
||||
int status = 0;
|
||||
std::vector<Member*> members = parseJSON(client_msg);
|
||||
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) {
|
||||
//const gchar* var_name = json_object_get_string_member( object, "var_name");
|
||||
session->addVariable( strdup(var_name) );
|
||||
printf("session->addVariable(\"%s\")\n", var_name);
|
||||
} else if ( strcmp(cmd, "var_cycle") == 0 ) {
|
||||
//int period = json_object_get_int_member( object, "period");
|
||||
session->setTimeInterval(period);
|
||||
printf("session->setTimeInterval(%d)\n", period);
|
||||
} else if ( strcmp(cmd, "var_pause") == 0 ) {
|
||||
session->pause();
|
||||
printf("session->pause()\n");
|
||||
} else if ( strcmp(cmd, "var_unpause") == 0 ) {
|
||||
session->unpause();
|
||||
printf("session->unpause()\n");
|
||||
} else if ( strcmp(cmd, "var_send") == 0 ) {
|
||||
//TODO
|
||||
} else if ( strcmp(cmd, "var_clear") == 0 ) {
|
||||
//TODO
|
||||
} else if ( strcmp(cmd, "var_exit") == 0 ) {
|
||||
//TODO
|
||||
} else {
|
||||
printf ("Unknown Command \"%s\".\n", cmd);
|
||||
status = 1;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
#define DEBUG
|
||||
static struct mg_serve_http_opts http_server_options;
|
||||
std::map<mg_connection*, WSsession*> wsSessionMap;
|
||||
|
||||
@ -102,26 +150,30 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
|
||||
switch(ev) {
|
||||
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("DEBUG: Event MG_EV_WEBSOCKET_HANDSHAKE_DONE. nc = %p.\n", nc);
|
||||
char * s = strndup(hm->uri.p, hm->uri.len);
|
||||
printf("DEBUG: WS URI = \"%s\"\n", s);
|
||||
#endif
|
||||
WSsession* session = new WSsession(nc);
|
||||
|
||||
session->setTimeInterval(500); // TEMPORARY for development
|
||||
session->addVariable("dyn.cannon.pos[0]");// TEMPORARY for development
|
||||
session->addVariable("dyn.cannon.pos[1]");// TEMPORARY for development
|
||||
session->unpause(); // TEMPORARY for development
|
||||
|
||||
wsSessionMap.insert( std::pair<mg_connection*, WSsession*>(nc, session) );
|
||||
|
||||
} break;
|
||||
case MG_EV_WEBSOCKET_FRAME: {
|
||||
printf("DEBUG: Event MG_EV_WEBSOCKET_FRAME. nc = %p.\n", nc);
|
||||
// Process messages recieved from the (web browser) client.
|
||||
struct websocket_message *wm = (struct websocket_message *) ev_data;
|
||||
|
||||
char* msg = strndup((char*)wm->data, wm->size);
|
||||
#ifdef DEBUG
|
||||
printf("DEBUG: Even t MG_EV_WEBSOCKET_FRAME: nc = %p message = %s\n", nc, msg);
|
||||
#endif
|
||||
if (nc->flags & MG_F_IS_WEBSOCKET) {
|
||||
std::map<mg_connection*, WSsession*>::iterator iter;
|
||||
// Find the session that goes with this connection.
|
||||
iter = wsSessionMap.find(nc);
|
||||
if (iter != wsSessionMap.end()) {
|
||||
WSsession* session = iter->second;
|
||||
handle_JSON_var_server_msg(session, msg);
|
||||
}
|
||||
}
|
||||
free(msg);
|
||||
|
||||
} break;
|
||||
@ -145,9 +197,6 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
}
|
||||
} break;
|
||||
case MG_EV_POLL: {
|
||||
#ifdef DEBUG
|
||||
printf("DEBUG: Event MG_EV_POLL. nc = %p.\n", nc);
|
||||
#endif
|
||||
if (nc->flags & MG_F_IS_WEBSOCKET) {
|
||||
std::map<mg_connection*, WSsession*>::iterator iter;
|
||||
// Find the session that goes with this connection.
|
||||
@ -161,12 +210,10 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
case MG_EV_HTTP_REQUEST: {
|
||||
#ifdef DEBUG
|
||||
printf("DEBUG: Event MG_EV_HTTP_REQUEST.\n");
|
||||
#endif
|
||||
char * s = strndup(hm->uri.p, hm->uri.len);
|
||||
#ifdef DEBUG
|
||||
printf("DEBUG: URI = \"%s\"\n", s);
|
||||
#endif
|
||||
free(s);
|
||||
#endif
|
||||
if (has_prefix(&hm->uri, &api_prefix)) {
|
||||
struct mg_str key;
|
||||
key.p = hm->uri.p + api_prefix.len;
|
||||
@ -202,7 +249,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
void* service_connections (void* arg) {
|
||||
HTTP_Server *S = (HTTP_Server*)arg;
|
||||
while (!S->shutting_down) {
|
||||
mg_mgr_poll(&S->mgr, 1000);
|
||||
mg_mgr_poll(&S->mgr, 50);
|
||||
struct timespec nap, t2;
|
||||
nap.tv_sec = 0;
|
||||
nap.tv_nsec = 100000000L;
|
||||
|
215
trick_sims/Cannon/models/mongoose_httpd/src/simpleJSON.cpp
Normal file
215
trick_sims/Cannon/models/mongoose_httpd/src/simpleJSON.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include "../include/simpleJSON.hh"
|
||||
|
||||
class LexicalAnalyzer {
|
||||
public:
|
||||
enum Lexeme {
|
||||
END_OF_INPUT,
|
||||
ERROR,
|
||||
LEFT_BRACE,
|
||||
RIGHT_BRACE,
|
||||
LEFT_SQUARE_BRACKET,
|
||||
RIGHT_SQUARE_BRACKET,
|
||||
COLON,
|
||||
COMMA,
|
||||
STRING,
|
||||
INTEGER
|
||||
};
|
||||
|
||||
LexicalAnalyzer(const char*);
|
||||
int next_lexeme();
|
||||
char* getLexText();
|
||||
|
||||
private:
|
||||
const char * s;
|
||||
const char * p;
|
||||
const char * vs;
|
||||
size_t vlen;
|
||||
char getch();
|
||||
void ungetch() ;
|
||||
LexicalAnalyzer(){}
|
||||
};
|
||||
|
||||
LexicalAnalyzer::LexicalAnalyzer(const char* str) {
|
||||
s = str;
|
||||
p = str;
|
||||
vs = NULL;
|
||||
vlen = 0;
|
||||
}
|
||||
|
||||
char LexicalAnalyzer::getch() {
|
||||
char ch;
|
||||
if ((ch = *p) != 0) { p++; }
|
||||
return ch;
|
||||
}
|
||||
|
||||
void LexicalAnalyzer::ungetch() {
|
||||
if (p > s) { p--; }
|
||||
}
|
||||
|
||||
char* LexicalAnalyzer::getLexText() {
|
||||
if (vlen > 0) {
|
||||
return strndup(vs, vlen);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int LexicalAnalyzer::next_lexeme() {
|
||||
int state = 0;
|
||||
vlen = 0;
|
||||
char ch;
|
||||
while ((ch = getch()) != 0) {
|
||||
switch (state) {
|
||||
case 0 : { // Initial state.
|
||||
if (ch == '{') {
|
||||
return LEFT_BRACE ;
|
||||
} else if (ch == '}') {
|
||||
return RIGHT_BRACE ;
|
||||
} else if (ch == '[') {
|
||||
return LEFT_SQUARE_BRACKET ;
|
||||
} else if (ch == ']') {
|
||||
return RIGHT_SQUARE_BRACKET ;
|
||||
} else if (ch == ':') {
|
||||
return COLON ;
|
||||
} else if (ch == ',') {
|
||||
return COMMA ;
|
||||
} else if ( ch == '"') {
|
||||
state = 1;
|
||||
vs = p;
|
||||
} else if ( isdigit(ch) ) {
|
||||
ungetch();
|
||||
state = 2;
|
||||
vs = p;
|
||||
} else if (isspace(ch)) {
|
||||
state = 0;
|
||||
}
|
||||
} break;
|
||||
case 1 : { // String literal accumulation state.
|
||||
while ((ch != 0 ) && (ch != '"'))
|
||||
ch = getch();
|
||||
if (ch == '"') {
|
||||
vlen = p-vs-1 ;
|
||||
return STRING ;
|
||||
} else {
|
||||
return ERROR ;
|
||||
}
|
||||
} break;
|
||||
case 2 : { // Integer literal accumulation state.
|
||||
while ((ch != 0 ) && (isdigit(ch)))
|
||||
ch = getch();
|
||||
vlen = p-vs-1;
|
||||
return INTEGER ;
|
||||
} break;
|
||||
default:
|
||||
return ERROR ;
|
||||
}
|
||||
}
|
||||
return END_OF_INPUT;
|
||||
}
|
||||
|
||||
const char *token_text(int token) {
|
||||
const char *text;
|
||||
switch (token) {
|
||||
case LexicalAnalyzer::END_OF_INPUT : text = "END_OF_INPUT"; break;
|
||||
case LexicalAnalyzer::ERROR : text = "ERROR"; break;
|
||||
case LexicalAnalyzer::LEFT_BRACE : text = "LEFT_BRACE"; break;
|
||||
case LexicalAnalyzer::RIGHT_BRACE : text = "RIGHT_BRACE"; break;
|
||||
case LexicalAnalyzer::LEFT_SQUARE_BRACKET : text = "LEFT_SQUARE_BRACKET"; break;
|
||||
case LexicalAnalyzer::RIGHT_SQUARE_BRACKET : text = "RIGHT_SQUARE_BRACKET"; break;
|
||||
case LexicalAnalyzer::COLON : text = "COLON"; break;
|
||||
case LexicalAnalyzer::COMMA : text = "COMMA"; break;
|
||||
case LexicalAnalyzer::STRING : text = "STRING"; break;
|
||||
case LexicalAnalyzer::INTEGER : text = "INTEGER"; break;
|
||||
default : text = "**UNKNOWN**"; break;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
Member::Member(const char *k, const char *v, int t) {
|
||||
key=k;
|
||||
valText=v;
|
||||
type=t;
|
||||
}
|
||||
|
||||
Member* parseJSON_member(LexicalAnalyzer &lexan) {
|
||||
|
||||
const char* key;
|
||||
const char* valText;
|
||||
int type;
|
||||
|
||||
int token;
|
||||
token = lexan.next_lexeme();
|
||||
if ( token == LexicalAnalyzer::STRING ) {
|
||||
key = lexan.getLexText();
|
||||
} else {
|
||||
std::cout << "ERROR: Expected STRING. Found \"" << token_text(token) << "\"." << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
token = lexan.next_lexeme();
|
||||
if ( token != LexicalAnalyzer::COLON ) {
|
||||
std::cout << "ERROR: Expected COLON. Found \"" << token_text(token) << "\"." << std::endl;
|
||||
token_text(token);
|
||||
delete key;
|
||||
return NULL;
|
||||
}
|
||||
token = lexan.next_lexeme();
|
||||
if (( token == LexicalAnalyzer::STRING) || ( token == LexicalAnalyzer::INTEGER )) {
|
||||
valText = lexan.getLexText();
|
||||
type = token;
|
||||
} else {
|
||||
std::cout << "ERROR: Expected STRING or INTEGER. Found \"" << token_text(token) << "." << std::endl;
|
||||
token_text(token);
|
||||
return NULL;
|
||||
}
|
||||
Member *member = new Member(key, valText, type);
|
||||
return member;
|
||||
}
|
||||
|
||||
std::vector<Member*> parseJSON( const char *json_s) {
|
||||
|
||||
std::vector<Member*> members;
|
||||
Member* member;
|
||||
int token;
|
||||
bool okiedokey = true;
|
||||
LexicalAnalyzer lexan(json_s);
|
||||
token = lexan.next_lexeme();
|
||||
if ( token == LexicalAnalyzer::LEFT_BRACE ) {
|
||||
member = parseJSON_member(lexan);
|
||||
if (member != NULL) {
|
||||
members.push_back(member);
|
||||
token = lexan.next_lexeme();
|
||||
while ( okiedokey && (token == LexicalAnalyzer::COMMA) ) {
|
||||
member = parseJSON_member(lexan);
|
||||
if (member != NULL) {
|
||||
members.push_back(member);
|
||||
} else {
|
||||
okiedokey = false;
|
||||
}
|
||||
token = lexan.next_lexeme();
|
||||
}
|
||||
} else {
|
||||
okiedokey = false;
|
||||
}
|
||||
if ( token != LexicalAnalyzer::RIGHT_BRACE ) {
|
||||
std::cout << "ERROR: Expected RIGHT_BRACE. Found \"" << token_text(token) << "\"." << std::endl;
|
||||
token_text(token);
|
||||
okiedokey = false;
|
||||
}
|
||||
} else {
|
||||
std::cout << "ERROR: Expected LEFT_BRACE. Found \"" << token_text(token) << "\"." << std::endl;
|
||||
okiedokey = false;
|
||||
}
|
||||
if (okiedokey == false) {
|
||||
std::vector<Member*>::iterator it;
|
||||
it = members.begin();
|
||||
while (it != members.end()) {
|
||||
delete *it;
|
||||
it = members.erase(it);
|
||||
}
|
||||
}
|
||||
return members;
|
||||
}
|
Loading…
Reference in New Issue
Block a user