mirror of
https://github.com/nasa/trick.git
synced 2024-12-20 21:53:10 +00:00
parent
ba4c86858a
commit
fee9b89a07
@ -6,44 +6,37 @@ LIBRARY DEPENDENCIES:
|
||||
#ifndef WSSESSION_HH
|
||||
#define WSSESSION_HH
|
||||
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <mongoose.h>
|
||||
#include "WSSessionVariable.hh"
|
||||
|
||||
inline uint64_t to_nanoseconds(struct timespec* t) {
|
||||
return t->tv_sec * (uint64_t)1000000000L + t->tv_nsec;
|
||||
}
|
||||
|
||||
class WSsession {
|
||||
public:
|
||||
WSsession( struct mg_connection *nc);
|
||||
void setTimeInterval(unsigned int milliseconds);
|
||||
void addVariable(char* vname);
|
||||
void stageValuesSynchronously();
|
||||
void stageValues();
|
||||
void sendValues();
|
||||
void pause();
|
||||
void unpause();
|
||||
void clear();
|
||||
void exit();
|
||||
int handle_msg (std::string);
|
||||
int emitError(const char* fmt, ... );
|
||||
|
||||
public:
|
||||
WSsession( struct mg_connection *nc);
|
||||
void setTimeInterval(unsigned int milliseconds);
|
||||
void addVariable(char* vname);
|
||||
void stageValuesSynchronously();
|
||||
void stageValues();
|
||||
void sendValues();
|
||||
void pause();
|
||||
void unpause();
|
||||
void clear();
|
||||
void exit();
|
||||
int handle_msg (const char* client_msg);
|
||||
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<WSsessionVariable*> sessionVariables;
|
||||
bool cyclicSendEnabled;
|
||||
double stageTime;
|
||||
bool valuesStaged;
|
||||
long long nextTime;
|
||||
long long intervalTimeTics;
|
||||
|
||||
static int bad_ref_int ;
|
||||
|
||||
private:
|
||||
WSsession() {}
|
||||
REF2* make_error_ref(const char* in_name);
|
||||
struct mg_connection* connection;
|
||||
std::vector<WSsessionVariable*> sessionVariables;
|
||||
bool cyclicSendEnabled;
|
||||
double stageTime;
|
||||
bool valuesStaged;
|
||||
long long nextTime;
|
||||
long long intervalTimeTics;
|
||||
};
|
||||
#endif
|
||||
|
@ -16,20 +16,19 @@ LIBRARY DEPENDENCIES:
|
||||
|
||||
class WSsessionVariable {
|
||||
|
||||
public:
|
||||
WSsessionVariable( REF2* variableType);
|
||||
~WSsessionVariable();
|
||||
const char* getName();
|
||||
void stageValue();
|
||||
void writeValue( std::ostream& chkpnt_os );
|
||||
public:
|
||||
WSsessionVariable( REF2* variableType);
|
||||
~WSsessionVariable();
|
||||
const char* getName();
|
||||
void stageValue();
|
||||
void writeValue( std::ostream& chkpnt_os );
|
||||
|
||||
|
||||
private:
|
||||
WSsessionVariable() {}
|
||||
REF2 *varInfo;
|
||||
void *address;
|
||||
int size;
|
||||
void *stageBuffer;
|
||||
bool deref;
|
||||
};
|
||||
private:
|
||||
WSsessionVariable() {}
|
||||
REF2 *varInfo;
|
||||
void *address;
|
||||
int size;
|
||||
void *stageBuffer;
|
||||
bool deref;
|
||||
};
|
||||
#endif
|
||||
|
@ -0,0 +1,14 @@
|
||||
/*************************************************************************
|
||||
PURPOSE: (Represent Websocket variable server connection.)
|
||||
LIBRARY DEPENDENCIES:
|
||||
( (../src/http_GET_handlers.o))
|
||||
**************************************************************************/
|
||||
#ifndef HANDLE_HTTP_GET_HANDLERS_HH
|
||||
#define HANDLE_HTTP_GET_HANDLERS_HH
|
||||
|
||||
#include <mongoose.h>
|
||||
|
||||
void handle_HTTP_GET_vs_connections(struct mg_connection *nc, struct http_message *hm);
|
||||
void handle_HTTP_GET_alloc_info(struct mg_connection *nc, struct http_message *hm);
|
||||
|
||||
#endif
|
@ -11,27 +11,40 @@ LIBRARY DEPENDENCIES:
|
||||
#include <sys/socket.h>
|
||||
#include <mongoose.h>
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "../include/WSSession.hh"
|
||||
|
||||
typedef struct {
|
||||
typedef void (*httpMethodHandler)(struct mg_connection *, struct http_message *);
|
||||
|
||||
struct mg_mgr mgr; /* ** mongoose */
|
||||
struct mg_connection *nc; /* ** mongoose */
|
||||
const char* port;
|
||||
const char* document_root;
|
||||
pthread_t server_thread; /* ** */
|
||||
bool shutting_down;
|
||||
class HTTP_Server {
|
||||
public:
|
||||
const char* port;
|
||||
const char* document_root;
|
||||
struct mg_mgr mgr; /* ** mongoose */
|
||||
struct mg_connection *listener; /* ** mongoose */
|
||||
pthread_t server_thread; /* ** */
|
||||
bool shutting_down;
|
||||
|
||||
} HTTP_Server ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int http_default_data(HTTP_Server * S) ;
|
||||
int http_init(HTTP_Server * S) ;
|
||||
int http_top_of_frame(HTTP_Server * S) ;
|
||||
int http_shutdown(HTTP_Server * S) ;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
std::map< std::string, httpMethodHandler> httpMethodHandlerMap; /* ** */
|
||||
pthread_mutex_t APIMapLock; /* ** */
|
||||
std::map<mg_connection*, WSsession*> sessionMap; /* ** */
|
||||
pthread_mutex_t sessionMapLock; /* ** */
|
||||
struct mg_serve_http_opts http_server_options; /* ** mongoose*/
|
||||
struct mg_bind_opts bind_opts; /* ** mongoose*/
|
||||
pthread_cond_t serviceConnections; /* ** */
|
||||
|
||||
// Trick Job-functions
|
||||
int http_default_data();
|
||||
int http_init();
|
||||
int http_top_of_frame();
|
||||
int http_shutdown();
|
||||
|
||||
void sendSessionValues(struct mg_connection *nc);
|
||||
void handleClientMessage(struct mg_connection *nc, std::string msg);
|
||||
void addSession(struct mg_connection *nc, WSsession* session);
|
||||
void deleteSession(struct mg_connection *nc);
|
||||
void install_API_GET_handler(std::string APIname, httpMethodHandler handler);
|
||||
void handle_API_GET_request(struct mg_connection *nc, http_message *hm, std::string handlerName);
|
||||
};
|
||||
#endif
|
||||
|
@ -9,13 +9,13 @@ LIBRARY DEPENDENCIES:
|
||||
class HttpSimObject : public Trick::SimObject {
|
||||
|
||||
public:
|
||||
HTTP_Server http_server ;
|
||||
HTTP_Server server ;
|
||||
|
||||
HttpSimObject() {
|
||||
("default_data") http_default_data( &http_server ) ;
|
||||
("initialization") http_init( &http_server ) ;
|
||||
("top_of_frame") http_top_of_frame( &http_server ) ;
|
||||
("shutdown") http_shutdown( &http_server ) ;
|
||||
("default_data") server.http_default_data() ;
|
||||
("initialization") server.http_init() ;
|
||||
("top_of_frame") server.http_top_of_frame() ;
|
||||
("shutdown") server.http_shutdown() ;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3,12 +3,12 @@ PURPOSE: (Represent the state and initial conditions of an http server)
|
||||
LIBRARY DEPENDENCIES:
|
||||
((simpleJSON.o))
|
||||
**************************************************************************/
|
||||
#include <sstream>
|
||||
#include <iomanip> // for setprecision
|
||||
#include "trick/memorymanager_c_intf.h"
|
||||
#include "trick/exec_proto.h"
|
||||
#include "../include/WSSession.hh"
|
||||
#include "../include/simpleJSON.hh"
|
||||
#include <sstream>
|
||||
#include <iomanip> // for setprecision
|
||||
|
||||
WSsession::WSsession( struct mg_connection *nc ) {
|
||||
connection = nc;
|
||||
@ -141,10 +141,10 @@ void WSsession::clear() {
|
||||
|
||||
void WSsession::exit() {}
|
||||
|
||||
int WSsession::handle_msg (const char* client_msg) {
|
||||
int WSsession::handle_msg (std::string client_msg) {
|
||||
|
||||
int status = 0;
|
||||
std::vector<Member*> members = parseJSON(client_msg);
|
||||
std::vector<Member*> members = parseJSON(client_msg.c_str());
|
||||
std::vector<Member*>::iterator it;
|
||||
const char *cmd;
|
||||
const char *var_name;
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*************************************************************************
|
||||
PURPOSE: ( HTTP-GET-method-handlers )
|
||||
LIBRARY DEPENDENCIES:
|
||||
( (../src/http_GET_handlers.o))
|
||||
**************************************************************************/
|
||||
|
||||
#include <sstream>
|
||||
#include "../include/http_GET_handlers.hh"
|
||||
|
||||
#include "trick/VariableServer.hh"
|
||||
extern Trick::VariableServer * the_vs ;
|
||||
|
||||
#include "trick/MemoryManager.hh"
|
||||
extern Trick::MemoryManager* trick_MM;
|
||||
|
||||
// In the Trick HTTP Server, a HTTP GET request whose URI starts with the API_PREFIX
|
||||
// is processed by a http-handler-function of the following form:
|
||||
//
|
||||
// void HTTP_METHOD_HANDLER( struct mg_connection *, struct http_message *);
|
||||
//
|
||||
// The purpose of these functions are generally to produce dynamically generated
|
||||
// HTTP responses, like JSON. These handler-functions are installed into the HTTP_Server
|
||||
// with the member-function <HTTP_Server-object>.install_API_GET_handler. For example:
|
||||
//
|
||||
// http.server.install_API_GET_handler("vs_connections", &handle_HTTP_GET_vs_connections);
|
||||
//
|
||||
// installs the function handle_HTTP_GET_vs_connections() with the key "vs_connections".
|
||||
// So if, for example the host and port of the webserver is "localhost:8888", and the API_PREFIX is "/api/v1/",
|
||||
// then loading the URL "localhost:8888/api/v1/vs_connections" in your browser will cause
|
||||
// handle_HTTP_GET_vs_connections() to run and return its response, which in this case is a JSON object
|
||||
// describing the variable server connections.
|
||||
|
||||
|
||||
// Send a JSON object to the given mongoose HTTP connection that describes the
|
||||
// Variable Server Connections.
|
||||
void handle_HTTP_GET_vs_connections(struct mg_connection *nc, struct http_message *hm) {
|
||||
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
std::stringstream ss;
|
||||
ss << *the_vs << std::endl;
|
||||
std::string someJSON = ss.str();
|
||||
mg_printf_http_chunk(nc, "%s", someJSON.c_str());
|
||||
mg_send_http_chunk(nc, "", 0);
|
||||
}
|
||||
|
||||
static int getIntegerQueryValue(struct http_message *hm, const char* key, int defaultVal) {
|
||||
char value_text[100];
|
||||
if ( mg_get_http_var(&(hm->query_string), key, value_text, sizeof(value_text)) > 0) {
|
||||
return atoi(value_text);
|
||||
} else {
|
||||
return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
// Send a JSON object to the given mongoose HTTP connection that contains information
|
||||
// about a range of memory allocations in the Trick Memory Manager.
|
||||
void handle_HTTP_GET_alloc_info(struct mg_connection *nc, struct http_message *hm) {
|
||||
int start = getIntegerQueryValue(hm, "start", 0);
|
||||
int count = getIntegerQueryValue(hm, "count", 10);
|
||||
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
std::stringstream ss;
|
||||
trick_MM->write_JSON_alloc_list(ss, start, count);
|
||||
std::string someJSON = ss.str();
|
||||
mg_printf_http_chunk(nc, "%s", someJSON.c_str());
|
||||
mg_send_http_chunk(nc, "", 0);
|
||||
}
|
@ -4,6 +4,7 @@ LIBRARY DEPENDENCIES:
|
||||
(
|
||||
(WSSession.o)
|
||||
(WSSessionVariable.o)
|
||||
(http_GET_handlers.o)
|
||||
)
|
||||
**************************************************************************/
|
||||
|
||||
@ -33,158 +34,58 @@ Messages sent from Server to Client
|
||||
}
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "../include/http_server.h"
|
||||
#include "../include/WSSession.hh"
|
||||
#include "trick/exec_proto.h"
|
||||
|
||||
#include "trick/VariableServer.hh"
|
||||
extern Trick::VariableServer * the_vs ;
|
||||
#include "trick/MemoryManager.hh"
|
||||
extern Trick::MemoryManager* trick_MM;
|
||||
#include "../include/http_GET_handlers.hh"
|
||||
|
||||
static const struct mg_str s_get_method = MG_MK_STR("GET");
|
||||
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 api_prefix = MG_MK_STR("/api/v1");
|
||||
|
||||
// ============================================================================
|
||||
// HTTP GET Handlers
|
||||
// ============================================================================
|
||||
|
||||
// Respond to HTTP GET method with URI="/api/v1/vs_connections".
|
||||
void handle_HTTP_GET_vs_connections(struct mg_connection *nc, struct http_message *hm) {
|
||||
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
std::stringstream ss;
|
||||
ss << *the_vs << std::endl;
|
||||
std::string tmp = ss.str();
|
||||
mg_printf_http_chunk(nc, "%s", tmp.c_str());
|
||||
mg_send_http_chunk(nc, "", 0);
|
||||
}
|
||||
|
||||
int getIntegerQueryValue(struct http_message *hm, const char* key, int defaultVal) {
|
||||
char value_text[100];
|
||||
if ( mg_get_http_var(&(hm->query_string), key, value_text, sizeof(value_text)) > 0) {
|
||||
return atoi(value_text);
|
||||
} else {
|
||||
return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
// Respond to HTTP GET method with URI="/api/v1/alloc_info".
|
||||
void handle_HTTP_GET_alloc_info(struct mg_connection *nc, struct http_message *hm) {
|
||||
int start = getIntegerQueryValue(hm, "start", 0);
|
||||
int count = getIntegerQueryValue(hm, "count", 10);
|
||||
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
std::stringstream ss;
|
||||
trick_MM->write_JSON_alloc_list(ss, start, count);
|
||||
std::string tmp = ss.str();
|
||||
mg_printf_http_chunk(nc, "%s", tmp.c_str());
|
||||
mg_send_http_chunk(nc, "", 0);
|
||||
}
|
||||
|
||||
#define DEBUG
|
||||
static struct mg_serve_http_opts http_server_options;
|
||||
std::map<mg_connection*, WSsession*> sessionMap;
|
||||
pthread_mutex_t sessionMapLock;
|
||||
pthread_cond_t serviceConnections;
|
||||
static const struct mg_str api_prefix = MG_MK_STR("/api/v1/");
|
||||
|
||||
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
|
||||
http_message *hm = (struct http_message *)ev_data;
|
||||
HTTP_Server* hs = (HTTP_Server *)nc->user_data;
|
||||
|
||||
switch(ev) {
|
||||
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
|
||||
|
||||
#ifdef DEBUG
|
||||
char * s = strndup(hm->uri.p, hm->uri.len);
|
||||
printf("WEBSOCKET[%p] OPENED. URI=\"%s\"\n", nc, s);
|
||||
free(s);
|
||||
#endif
|
||||
std::string uri(hm->uri.p, hm->uri.len);
|
||||
std::cout << "WEBSOCKET[" << (void*)nc << "] OPENED. URI=\"" << uri << "\"." << std::endl;
|
||||
// Create a session object to store information about this web-socket connection.
|
||||
WSsession* session = new WSsession(nc);
|
||||
|
||||
pthread_mutex_lock(&sessionMapLock);
|
||||
sessionMap.insert( std::pair<mg_connection*, WSsession*>(nc, session) );
|
||||
pthread_mutex_unlock(&sessionMapLock);
|
||||
|
||||
hs->addSession(nc, session);
|
||||
} break;
|
||||
|
||||
case MG_EV_WEBSOCKET_FRAME: {
|
||||
// --------------------------------------------------------
|
||||
// Process websocket messages from the client (web browser).
|
||||
// --------------------------------------------------------
|
||||
case MG_EV_WEBSOCKET_FRAME: { // Process websocket messages from the client (web browser).
|
||||
struct websocket_message *wm = (struct websocket_message *) ev_data;
|
||||
char* msg = strndup((char*)wm->data, wm->size);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("WEBSOCKET[%p] RECIEVED: %s\n", nc, msg);
|
||||
#endif
|
||||
std::string msg ((char*)wm->data, wm->size);
|
||||
std::cout << "WEBSOCKET[" << (void*)nc << "] RECIEVED: " << msg << std::endl;
|
||||
if (nc->flags & MG_F_IS_WEBSOCKET) {
|
||||
// Find the session that goes with this connection.
|
||||
std::map<mg_connection*, WSsession*>::iterator iter;
|
||||
iter = sessionMap.find(nc);
|
||||
if (iter != sessionMap.end()) {
|
||||
WSsession* session = iter->second;
|
||||
session->handle_msg(msg);
|
||||
}
|
||||
hs->handleClientMessage(nc, msg);
|
||||
}
|
||||
free(msg);
|
||||
} break;
|
||||
case MG_EV_CLOSE: {
|
||||
if (nc->flags & MG_F_IS_WEBSOCKET) {
|
||||
std::map<mg_connection*, WSsession*>::iterator iter;
|
||||
iter = sessionMap.find(nc);
|
||||
if (iter != sessionMap.end()) {
|
||||
WSsession* session = iter->second;
|
||||
delete session;
|
||||
sessionMap.erase(iter);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("WEBSOCKET[%p] CLOSED.\n", nc);
|
||||
#endif
|
||||
hs->deleteSession(nc);
|
||||
std::cout << "WEBSOCKET[" << (void*)nc << "] CLOSED." << std::endl;
|
||||
}
|
||||
} break;
|
||||
case MG_EV_POLL: {
|
||||
// The MG_EV_POLL event is sent to all connections for each invocation of mg_mgr_poll().
|
||||
// The threaded function connectionAttendant() [below] periodically calls mg_mgr_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).
|
||||
if (nc->flags & MG_F_IS_WEBSOCKET) {
|
||||
|
||||
// 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*, WSsession*>::iterator iter;
|
||||
iter = sessionMap.find(nc);
|
||||
if (iter != sessionMap.end()) {
|
||||
WSsession* session = iter->second;
|
||||
session->sendValues();
|
||||
}
|
||||
hs->sendSessionValues(nc);
|
||||
}
|
||||
} break;
|
||||
case MG_EV_HTTP_REQUEST: {
|
||||
|
||||
#ifdef DEBUG
|
||||
char * s = strndup(hm->uri.p, hm->uri.len);
|
||||
printf("HTTP_REQUEST: URI = \"%s\"\n", s);
|
||||
free(s);
|
||||
#endif
|
||||
std::string uri(hm->uri.p, hm->uri.len);
|
||||
std::cout << "HTTP_REQUEST: URI = \"" << uri << "\"" << std::endl;
|
||||
if (mg_str_starts_with(hm->uri, api_prefix)) {
|
||||
struct mg_str key;
|
||||
key.p = hm->uri.p + api_prefix.len;
|
||||
key.len = hm->uri.len - api_prefix.len;
|
||||
|
||||
if (mg_strcmp(hm->method, s_get_method)==0) {
|
||||
if (mg_vcmp(&key, "/vs_connections") == 0) {
|
||||
handle_HTTP_GET_vs_connections(nc, hm);
|
||||
} else if (mg_vcmp(&key, "/alloc_info") == 0) {
|
||||
handle_HTTP_GET_alloc_info(nc, hm);
|
||||
} else {
|
||||
mg_http_send_error(nc, 404, "No such API.");
|
||||
}
|
||||
std::string handlerName (hm->uri.p + api_prefix.len, hm->uri.len - api_prefix.len);
|
||||
hs->handle_API_GET_request(nc, hm, handlerName);
|
||||
} else if (mg_strcmp(hm->method, s_put_method)==0) {
|
||||
mg_http_send_error(nc, 405, "PUT method not allowed.");
|
||||
} else if (mg_strcmp(hm->method, s_delete_method)==0) {
|
||||
@ -192,7 +93,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
}
|
||||
} else {
|
||||
// Serve the files in the document-root directory, as specified by the URI.
|
||||
mg_serve_http(nc, (struct http_message *) ev_data, http_server_options);
|
||||
mg_serve_http(nc, (struct http_message *) ev_data, hs->http_server_options);
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
@ -203,62 +104,118 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
// =========================================================================
|
||||
// This function runs in its own pthread to operate the webserver.
|
||||
// =========================================================================
|
||||
void* connectionAttendant (void* arg) {
|
||||
static void* connectionAttendant (void* arg) {
|
||||
HTTP_Server *S = (HTTP_Server*)arg;
|
||||
while(1) {
|
||||
pthread_mutex_lock(&sessionMapLock);
|
||||
pthread_mutex_lock(&S->sessionMapLock);
|
||||
// Wait here until the serviceConnections condition is signaled by the top_of_frame job.
|
||||
pthread_cond_wait(&serviceConnections, &sessionMapLock);
|
||||
pthread_cond_wait(&S->serviceConnections, &S->sessionMapLock);
|
||||
if (S->shutting_down) {
|
||||
pthread_mutex_unlock(&sessionMapLock);
|
||||
pthread_mutex_unlock(&S->sessionMapLock);
|
||||
return NULL;
|
||||
} else {
|
||||
mg_mgr_poll(&S->mgr, 50);
|
||||
}
|
||||
pthread_mutex_unlock(&sessionMapLock);
|
||||
pthread_mutex_unlock(&S->sessionMapLock);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void HTTP_Server::install_API_GET_handler(std::string APIname, httpMethodHandler handler) {
|
||||
pthread_mutex_lock(&APIMapLock);
|
||||
httpMethodHandlerMap.insert(std::pair<std::string, httpMethodHandler>(APIname, handler));
|
||||
pthread_mutex_unlock(&APIMapLock);
|
||||
}
|
||||
|
||||
void HTTP_Server::handle_API_GET_request(struct mg_connection *nc, http_message *hm, std::string handlerName) {
|
||||
std::map<std::string, httpMethodHandler>::iterator iter;
|
||||
iter = httpMethodHandlerMap.find(handlerName);
|
||||
if (iter != httpMethodHandlerMap.end()) {
|
||||
httpMethodHandler handler = iter->second;
|
||||
handler(nc, hm);
|
||||
} else {
|
||||
mg_http_send_error(nc, 404, "No such API.");
|
||||
}
|
||||
}
|
||||
|
||||
void HTTP_Server::sendSessionValues(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*, WSsession*>::iterator iter;
|
||||
iter = sessionMap.find(nc);
|
||||
if (iter != sessionMap.end()) {
|
||||
WSsession* session = iter->second;
|
||||
session->sendValues();
|
||||
}
|
||||
}
|
||||
|
||||
void HTTP_Server::deleteSession(struct mg_connection *nc) {
|
||||
std::map<mg_connection*, WSsession*>::iterator iter;
|
||||
iter = sessionMap.find(nc);
|
||||
if (iter != sessionMap.end()) {
|
||||
WSsession* session = iter->second;
|
||||
delete session;
|
||||
sessionMap.erase(iter);
|
||||
}
|
||||
}
|
||||
void HTTP_Server::handleClientMessage(struct mg_connection *nc, std::string msg) {
|
||||
std::map<mg_connection*, WSsession*>::iterator iter;
|
||||
iter = sessionMap.find(nc);
|
||||
if (iter != sessionMap.end()) {
|
||||
WSsession* session = iter->second;
|
||||
session->handle_msg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void HTTP_Server::addSession(struct mg_connection *nc, WSsession* session) {
|
||||
pthread_mutex_lock(&sessionMapLock);
|
||||
sessionMap.insert( std::pair<mg_connection*, WSsession*>(nc, session) );
|
||||
pthread_mutex_unlock(&sessionMapLock);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Trick Sim Interface Functions
|
||||
// =========================================================================
|
||||
|
||||
int http_default_data(HTTP_Server *S) {
|
||||
S->port = "8888";
|
||||
S->shutting_down = false;
|
||||
S->document_root = "www";
|
||||
int HTTP_Server::http_default_data() {
|
||||
port = "8888";
|
||||
document_root = "www";
|
||||
shutting_down = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_init(HTTP_Server *S) {
|
||||
int HTTP_Server::http_init() {
|
||||
|
||||
http_server_options.document_root = S->document_root;
|
||||
http_server_options.document_root = document_root;
|
||||
http_server_options.enable_directory_listing = "yes";
|
||||
|
||||
mg_mgr_init(&S->mgr, NULL);
|
||||
install_API_GET_handler("vs_connections", &handle_HTTP_GET_vs_connections);
|
||||
install_API_GET_handler("alloc_info", &handle_HTTP_GET_alloc_info);
|
||||
|
||||
std::cout << "Trick Webserver: Starting, and listening on port " << S->port << ".\n"
|
||||
<< "Trick Webserver: Document root = \"" << S->document_root << "\""
|
||||
<< std::endl;
|
||||
mg_mgr_init( &mgr, NULL );
|
||||
|
||||
S->nc = mg_bind(&S->mgr, S->port, ev_handler);
|
||||
if (S->nc == NULL) {
|
||||
std::cerr << "Trick Webserver: ERROR: Failed to create listener.\n"
|
||||
<< "Perhaps another program is already using port " << S->port << "."
|
||||
<< std::endl;
|
||||
return 1;
|
||||
memset(&bind_opts, 0, sizeof(bind_opts));
|
||||
bind_opts.user_data = this;
|
||||
listener = mg_bind_opt( &mgr, port, ev_handler, bind_opts);
|
||||
|
||||
if (listener != NULL) {
|
||||
std::cout << "Trick Webserver: Starting, and listening on port " << port << ".\n"
|
||||
<< "Trick Webserver: Document root = \"" << document_root << "\""
|
||||
<< std::endl;
|
||||
} else {
|
||||
std::cerr << "Trick Webserver: ERROR: Failed to create listener.\n"
|
||||
<< "Perhaps another program is already using port " << port << "."
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
mg_set_protocol_http_websocket(S->nc);
|
||||
|
||||
mg_set_protocol_http_websocket( listener );
|
||||
pthread_cond_init(&serviceConnections, NULL);
|
||||
pthread_create( &S->server_thread, NULL, connectionAttendant, (void*)S);
|
||||
pthread_create( &server_thread, NULL, connectionAttendant, (void*)this );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_top_of_frame(HTTP_Server * S) {
|
||||
if (S->nc != NULL) {
|
||||
|
||||
int HTTP_Server::http_top_of_frame() {
|
||||
if (listener != NULL) {
|
||||
// Have all of the sessions stage their data. We do this here, in a
|
||||
// top_of_frame job, so that all of the data is time-homogeneous.
|
||||
std::map<mg_connection*, WSsession*>::iterator iter;
|
||||
@ -268,21 +225,20 @@ int http_top_of_frame(HTTP_Server * S) {
|
||||
session->stageValuesSynchronously();
|
||||
}
|
||||
pthread_mutex_unlock(&sessionMapLock);
|
||||
|
||||
// Signal the server thread to construct and send the values-message to the client.
|
||||
pthread_cond_signal( &serviceConnections );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_shutdown(HTTP_Server *S) {
|
||||
if (S->nc != NULL) {
|
||||
std::cout << "Trick Webserver: Shutting down on port " << S->port << "." << std::endl;
|
||||
S->shutting_down = true;
|
||||
int HTTP_Server::http_shutdown() {
|
||||
if (listener != NULL) {
|
||||
std::cout << "Trick Webserver: Shutting down on port " << port << "." << std::endl;
|
||||
shutting_down = true;
|
||||
|
||||
// Send the serviceConnections signal one last time so the connectionAttendant thread can quit.
|
||||
pthread_cond_signal( &serviceConnections );
|
||||
pthread_join(S->server_thread, NULL);
|
||||
pthread_join(server_thread, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user