blink1-tool/server/blink1-tiny-server.c

682 lines
24 KiB
C

/*
*
* blink1-tiny-server -- a small cross-platform REST/JSON server for
* controlling a blink(1) device
*
* 2012-2022, Tod Kurt, http://todbot.com/blog/ , http://thingm.com/
*
* Example supported URLs:
*
* localhost:8000/blink1/on
* localhost:8000/blink1/off
* localhost:8000/blink1/red
* localhost:8000/blink1/green
* localhost:8000/blink1/blue
* localhost:8000/blink1/blink?rgb=%23ff0ff&time=1.0&count=3
* localhost:8000/blink1/fadeToRGB?rgb=%23ff00ff&time=1.0
*
*
*/
#include <getopt.h> // for getopt_long_only()
#include <sys/time.h>
#include <signal.h>
#include "mongoose.h"
#include "blink1-lib.h"
//#include "dict.h"
#include "Dictionary.h"
#include "Dictionary.c"
// normally this is obtained from git tags and filled out by the Makefile
#ifndef BLINK1_VERSION
#define BLINK1_VERSION "v0.0"
#endif
const char* blink1_server_name = "blink1-tiny-server";
const char* blink1_server_version = BLINK1_VERSION;
static bool show_html = true;
static bool enable_logging = false;
static char http_listen_host[120] = "localhost"; // or 0.0.0.0 for any
static int http_listen_port = 8934; // was 8000
static char http_listen_url[100]; // will be "http://localhost:8000"
typedef struct cache_info_ {
blink1_device* dev; // device, if opened, NULL otherwise
int64_t atime; // time last used
} cache_info;
static int64_t idle_atime = 1000 /* milliseconds */;
static cache_info cache_infos[cache_max];
DictionaryRef patterndict;
DictionaryCallbacks patterndictc;
typedef struct _url_info
{
char url[100];
char desc[100];
} url_info;
// FIXME: how to make Emacs format these better?
static const url_info supported_urls[]
= {
{"/blink1/", "simple status page"},
{"/blink1/id", "get blink1 serial number"},
{"/blink1/on", "turn blink(1) full bright white"},
{"/blink1/off", "turn blink(1) dark"},
{"/blink1/red", "turn blink(1) solid red"},
{"/blink1/green", "turn blink(1) solid green"},
{"/blink1/blue", "turn blink(1) solid blue"},
{"/blink1/cyan", "turn blink(1) solid cyan"},
{"/blink1/yellow", "turn blink(1) solid yellow"},
{"/blink1/magenta", "turn blink(1) solid magenta"},
{"/blink1/fadeToRGB", "turn blink(1) specified RGB color by 'rgb' arg"},
{"/blink1/blink", "blink the blink(1) the specified RGB color"},
{"/blink1/pattern/play", "play color pattern specified by 'pattern' arg"},
{"/blink1/random", "turn the blink(1) a random color"},
{"/blink1/servertickle/on","Enable servertickle, uses 'millis' or 'time' arg"},
{"/blink1/servertickle/off","Disable servertickle"}
};
void usage()
{
fprintf(stderr,
"Usage: \n"
" %s [options]\n"
"where [options] can be:\n"
" --port port, -p port port to listen on (default %d)\n"
" --host host, -H host host to listen on ('127.0.0.1' or '0.0.0.0')\n"
" --no-html do not serve static HTML help\n"
" --logging log accesses to stdout\n"
" --version version of this program\n"
" --help, -h this help page\n"
"\n",
blink1_server_name, http_listen_port);
fprintf(stderr,
"Supported URIs:\n");
for( int i=0; i< sizeof(supported_urls)/sizeof(url_info); i++ ) {
fprintf(stderr," %s -- %s\n", supported_urls[i].url, supported_urls[i].desc);
}
fprintf(stderr,"\n");
fprintf(stderr,
"Supported query arguments: (not all urls support all args)\n"
" 'rgb' -- hex RGB color code. e.g. 'rgb=FF9900' or 'rgb=%%23FF9900\n"
" 'time' -- time in seconds. e.g. 'time=0.5' \n"
" 'bright' -- brightness, 1-255, 0=full e.g. half-bright 'bright=127'\n"
" 'ledn' -- which LED to set. 0=all/1=top/2=bot, e.g. 'ledn=0'\n"
" 'millis' -- milliseconds to fade, or blink, e.g. 'millis=500'\n"
" 'count' -- number of times to blink, for /blink1/blink, e.g. 'count=3'\n"
" 'pattern'-- color pattern string (e.g. '3,00ffff,0.2,0,000000,0.2,0')\n"
"\n"
"Examples: \n"
" /blink1/blue?bright=127 -- set blink1 blue, at half-intensity \n"
" /blink1/fadeToRGB?rgb=FF00FF&millis=500 -- fade to purple over 500ms\n"
" /blink1/pattern/play?pattern=3,00ffff,0.2,0,000000,0.2,0 -- blink cyan 3 times\n"
" /blink1/servertickle?on=1&millis=5000 -- turn servertickle on with 5 sec timer\n"
"\n"
);
}
void cache_flush(int idle_threshold_millis);
blink1_device* cache_getDeviceById(uint32_t id)
{
int i = blink1_getCacheIndexById(id);
blink1_device* dev=NULL;
if( i>=0 ) {
dev = cache_infos[i].dev;
}
// printf("cache_getDeviceById: %p from %d at %d\n", dev, id, i);
if( !dev ) {
dev = blink1_openById(id);
if( !dev ) {
cache_flush(0);
blink1_enumerate();
dev = blink1_openById(id);
if( !dev ) {
return NULL;
}
}
i = blink1_getCacheIndexByDev(dev);
// printf("cache_getDeviceById: %p to %d \n", dev, i);
if( i>=0 ) {
cache_infos[i].dev = dev;
}
}
// printf("cache_getDeviceById: return %p\n", dev);
return dev;
}
#define cache_return(dev) { cache_return_internal(dev); dev=NULL; }
void cache_return_internal( blink1_device* dev )
{
int i = blink1_getCacheIndexByDev(dev);
// printf("cache_return_internal: %p at %d\n", dev, i);
if( i>=0 ) {
cache_infos[i].atime = mg_millis();
}
else {
blink1_close(dev);
}
}
void cache_flush(int idle_threshold_millis)
{
int64_t deadline = mg_millis() - idle_threshold_millis;
int count = blink1_getCachedCount();
for( int i=0; i< count; i++ ) {
if( cache_infos[i].dev && cache_infos[i].atime < deadline ) {
// printf("DEBUG cache_flush: id=%d handle=%p atime=%lld\n", i, cache_infos[i].dev, cache_infos[i].atime);
blink1_close(cache_infos[i].dev)
cache_infos[i].atime = 0;
}
}
}
void blink1_do_color(rgb_t rgb, uint32_t millis, uint32_t id,
uint8_t ledn, uint8_t bright, char* status)
{
blink1_device* dev = cache_getDeviceById(id);
if( !dev ) {
sprintf(status+strlen(status), ": error: no blink1 found");
return;
}
blink1_adjustBrightness( bright, &rgb.r, &rgb.g, &rgb.b);
if( millis==0 ) { millis = 200; }
int rc = blink1_fadeToRGBN( dev, millis, rgb.r,rgb.g,rgb.b, ledn );
if( rc == -1 ) {
fprintf(stderr, "error, couldn't fadeToRGB on blink1\n");
sprintf(status+strlen(status), ": error, couldn't fadeToRGB on blink1");
}
else {
sprintf(status, "blink1 set color #%2.2x%2.2x%2.2x", rgb.r,rgb.g,rgb.b);
}
cache_return(dev);
}
//
//
void DictionaryPrintAsJsonMg(struct mg_connection *nc, DictionaryRef d )
{
size_t i;
struct DictionaryItem * item;
if( d == NULL || d->items == NULL ) { return; }
for( i = 0; i < d->size; i++ ) {
item = d->items[ i ];
while( item ) {
const char* v = item->value;
if( v[0] == '[' || v[0] == '{' ) { // hack if value is json array/object
mg_http_printf_chunk(nc,"\"%s\": %s,\n", item->key,item->value);
} else {
mg_http_printf_chunk(nc,"\"%s\": \"%s\",\n", item->key,item->value);
}
item = item->next;
}
}
}
static void log_access(struct mg_connection *c, char* uri_str, int resp_code) {
//CLF format: 127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
time_t rawtime;
time( &rawtime );
char date_str[100];
strftime(date_str, sizeof(date_str), "%d/%b/%Y:%H:%M:%S %z", localtime(&rawtime));
char ip_str[20];
mg_snprintf(ip_str, 20, "%d.%d.%d.%d", c->rem.ip[0],c->rem.ip[1],c->rem.ip[2],c->rem.ip[3] );
printf("%s - [%s] \"%s %s HTTP/1.1\" %d %d\n", ip_str, date_str, "GET", uri_str, resp_code, 0 ); // can't get response length I guess
}
static void ev_handler(struct mg_connection *c, int ev, void *ev_data)
{
if(ev != MG_EV_HTTP_MSG) {
return;
}
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
uint32_t id=0;
uint8_t ledn=0, bright=0;
char status[1000]; status[0] = 0;
char uri_str[1000];
char tmpstr[1000];
char pattstr[1000];
char pnamestr[1000];
uint16_t millis = 0;
rgb_t rgb = {0,0,0}; // for parsecolor
uint8_t count = 0;
int resp_code = 404; // no found by default
DictionaryCallbacks resultsdictc = DictionaryStandardStringCallbacks();
DictionaryRef resultsdict = DictionaryCreate( 100, &resultsdictc );
struct mg_str* uri = &hm->uri;
struct mg_str* querystr = &hm->query;
mg_snprintf(uri_str, uri->len+1, "%s", uri->ptr); // uri->ptr gives us char ptr
// echoing uri could potentially be used for XSS attack issue #72
// DictionaryInsert(resultsdict, "uri", uri_str);
DictionaryInsert(resultsdict, "version", blink1_server_version);
// parse all possible query args (it's just easier this way)
if( mg_http_get_var(querystr, "millis", tmpstr, sizeof(tmpstr)) > 0 ) {
millis = strtod(tmpstr,NULL);
}
if( mg_http_get_var(querystr, "time", tmpstr, sizeof(tmpstr)) > 0 ) {
millis = 1000 * strtof(tmpstr,NULL);
}
if( mg_http_get_var(querystr, "rgb", tmpstr, sizeof(tmpstr)) > 0 ) {
parsecolor( &rgb, tmpstr);
}
if( mg_http_get_var(querystr, "count", tmpstr, sizeof(tmpstr)) > 0 ) {
count = strtod(tmpstr,NULL);
}
if( mg_http_get_var(querystr, "id", tmpstr, sizeof(tmpstr)) > 0 ) {
char* pch;
pch = strtok(tmpstr, " ,");
int base = (strlen(pch)==8) ? 16:0;
id = strtol(pch,NULL,base);
}
if( mg_http_get_var(querystr, "ledn", tmpstr, sizeof(tmpstr)) > 0 ) {
ledn = strtod(tmpstr,NULL);
}
if( mg_http_get_var(querystr, "bright", tmpstr, sizeof(tmpstr)) > 0 ) {
bright = strtod(tmpstr,NULL);
}
if( mg_http_get_var(querystr, "pattern", tmpstr, sizeof(tmpstr)) > 0 ) {
strcpy(pattstr, tmpstr);
}
if( mg_http_get_var(querystr, "pname", tmpstr, sizeof(tmpstr)) > 0 ) {
strcpy(pnamestr, tmpstr);
}
if( mg_vcmp( uri, "/blink1") == 0 ||
mg_vcmp( uri, "/blink1/") == 0 ) {
sprintf(status, "blink1 status");
blink1_device* dev = cache_getDeviceById(id);
if( dev ) {
uint16_t msecs;
int rc = blink1_readRGB(dev, &msecs, &rgb.r,&rgb.g,&rgb.b, 0 );
if( rc==-1 ) {
printf("error on readRGB\n");
}
cache_return(dev);
}
}
else if( mg_vcmp( uri, "/blink1/id") == 0 ||
mg_vcmp( uri, "/blink1/id/") == 0 ||
mg_vcmp( uri, "/blink1/enumerate") == 0 ) {
sprintf(status, "blink1 id");
cache_flush(0);
int c = blink1_enumerate();
sprintf(tmpstr,"[");
for( int i=0; i< c; i++ ) {
sprintf(tmpstr+strlen(tmpstr), "\"%s\"", blink1_getCachedSerial(i));
if( i!=c-1 ) { sprintf(tmpstr+strlen(tmpstr), ","); } // ugh
}
sprintf(tmpstr+strlen(tmpstr), "]");
DictionaryInsert(resultsdict, "blink1_serialnums", tmpstr);
const char* blink1_serialnum = blink1_getCachedSerial(0);
if( blink1_serialnum ) {
sprintf(tmpstr, "%s00000000", blink1_serialnum);
DictionaryInsert(resultsdict, "blink1_id", tmpstr);
}
}
else if( mg_vcmp( uri, "/blink1/off") == 0 ) {
sprintf(status, "blink1 off");
rgb.r = 0; rgb.g = 0; rgb.b = 0;
blink1_do_color(rgb, millis, id, ledn, bright, status);
}
else if( mg_vcmp( uri, "/blink1/on") == 0 ) {
sprintf(status, "blink1 on");
rgb.r = 255; rgb.g = 255; rgb.b = 255;
blink1_do_color(rgb, millis, id, ledn, bright, status);
}
else if( mg_vcmp( uri, "/blink1/red") == 0 ) {
sprintf(status, "blink1 red");
rgb.r = 255; rgb.g = 0; rgb.b = 0;
blink1_do_color(rgb, millis, id, ledn, bright, status);
}
else if( mg_vcmp( uri, "/blink1/green") == 0 ) {
sprintf(status, "blink1 green");
rgb.r = 0; rgb.g = 255; rgb.b = 0;
blink1_do_color(rgb, millis, id, ledn, bright, status);
}
else if( mg_vcmp( uri, "/blink1/blue") == 0 ) {
sprintf(status, "blink1 blue");
rgb.r = 0; rgb.g = 0; rgb.b = 255;
blink1_do_color(rgb, millis, id, ledn, bright, status);
}
else if( mg_vcmp( uri, "/blink1/cyan") == 0 ) {
sprintf(status, "blink1 cyan");
rgb.r = 0; rgb.g = 255; rgb.b = 255;
blink1_do_color(rgb, millis, id, ledn, bright, status);
}
else if( mg_vcmp( uri, "/blink1/yellow") == 0 ) {
sprintf(status, "blink1 yellow");
rgb.r = 255; rgb.g = 255; rgb.b = 0;
blink1_do_color(rgb, millis, id, ledn, bright, status);
}
else if( mg_vcmp( uri, "/blink1/magenta") == 0 ) {
sprintf(status, "blink1 magenta");
rgb.r = 255; rgb.g = 0; rgb.b = 255;
blink1_do_color(rgb, millis, id, ledn, bright, status);
}
else if( mg_vcmp( uri, "/blink1/fadeToRGB") == 0 ) {
sprintf(status, "blink1 fadeToRGB");
blink1_do_color(rgb, millis, id, ledn, bright, status);
}
else if( mg_vcmp(uri, "/blink1/blink") == 0 ) {
sprintf(status, "blink1 blink");
if( rgb.r==0 && rgb.g==0 && rgb.b==0 ) { rgb.r=255;rgb.g=255;rgb.b=255; }
if( count==0 ) { count = 3; }
if( millis==0 ) { millis = 300; }
int repeats = -1;
patternline_t pattern[32];
blink1_adjustBrightness( bright, &rgb.r, &rgb.g, &rgb.b);
sprintf(tmpstr, "%d,#%2.2x%2.2x%2.2x,%f,%d,#000000,%f,0",
count, rgb.r,rgb.g,rgb.b, (float)millis/1000.0, ledn,
(float)millis/1000.0);
msg("pattstr:%s\n", tmpstr);
int pattlen = parsePattern( tmpstr, &repeats, pattern);
blink1_device* dev = cache_getDeviceById(id);
for( int i=0; i<pattlen; i++ ) {
patternline_t pat = pattern[i];
blink1_setLEDN(dev, pat.ledn);
msg(" writing line %d: %2.2x,%2.2x,%2.2x : %d : %d\n",
i, pat.color.r,pat.color.g,pat.color.b, pat.millis, pat.ledn );
blink1_writePatternLine(dev, pat.millis, pat.color.r, pat.color.g, pat.color.b, i);
}
blink1_playloop(dev, 1, 0/*startpos*/, pattlen-1/*endpos*/, count/*count*/);
cache_return(dev);
}
/*
else if( mg_vcmp(uri, "/blink1/pattern") == 0 ||
mg_vcmp(uri, "/blink1/pattern/") == 0 ) {
tmpstr
DictionaryInsert(statussdict, "patterns", tmpstr);
}
else if( mg_vcmp(uri, "/blink1/pattern/add") == 0 ) {
sprintf(result, "blink1 pattern add");
DictionaryInsert(patterndict, pnamestr, pattstr);
DictionaryInsert(resultsdict, "pattern", pattstr);
}
*/
else if( mg_vcmp(uri, "/blink1/pattern/play") == 0 ) {
sprintf(status, "blink1 pattern play");
/*
if( pnamestr[0] != 0 && pattstr[0] != 0 ) {
DictionaryInsert(patterndict, pnamestr, pattstr);
}
if( pnamestr[0] != 0 ) {
DictionaryGetValue(patterndict, pnamestr);
}
*/
if( pattstr[0] == 0 ) { // no pattern
}
patternline_t pattern[32];
int repeats = -1;
int pattlen = parsePattern( pattstr, &repeats, pattern);
if( !count ) { count = repeats; }
blink1_device* dev = cache_getDeviceById(id);
msg("pattlen:%d, repeats:%d\n", pattlen,repeats);
for( int i=0; i<pattlen; i++ ) {
patternline_t pat = pattern[i];
blink1_setLEDN(dev, pat.ledn);
msg(" writing line %d: %2.2x,%2.2x,%2.2x : %d : %d\n",
i, pat.color.r,pat.color.g,pat.color.b, pat.millis, pat.ledn );
blink1_writePatternLine(dev, pat.millis, pat.color.r, pat.color.g, pat.color.b, i);
}
blink1_playloop(dev, 1, 0/*startpos*/, pattlen-1/*endpos*/, count/*count*/);
cache_return(dev);
}
else if( mg_vcmp( uri, "/blink1/blinkserver") == 0 ) {
sprintf(status, "blink1 blinkserver");
//if( r==0 && g==0 && b==0 ) { r = 255; g = 255; b = 255; }
if( millis==0 ) { millis = 200; }
blink1_device* dev = cache_getDeviceById(id);
//blink1_adjustBrightness( bright, &r, &g, &b);
//msg("rgb:%d,%d,%d\n",r,g,b);
for( int i=0; i<count; i++ ) {
blink1_fadeToRGBN( dev, millis/2, rgb.r,rgb.g,rgb.b, ledn );
blink1_sleep( millis/2 ); // fixme
blink1_fadeToRGBN( dev, millis/2, 0,0,0, ledn );
blink1_sleep( millis/2 ); // fixme
}
cache_return(dev);
}
//else if( mg_http_match_uri(hm, "/blink1/servertickle/*")) {
else if( mg_vcmp( uri, "/blink1/servertickle/on") == 0 ||
mg_vcmp( uri, "/blink1/servertickle/off") == 0 ) {
bool st_on = (mg_vcmp(uri, "/blink1/servertickle/on") == 0);
if( millis==0 ) { millis = 2000; }
sprintf(status, "blink1 servertickle %s", st_on? "on":"off");
uint8_t start_pos = 0;
uint8_t end_pos = 0;
uint8_t st_off_state = 0;
blink1_device* dev = cache_getDeviceById(id);
blink1_serverdown( dev, st_on, millis, st_off_state, start_pos, end_pos );
cache_return(dev);
DictionaryInsert(resultsdict, "on", st_on? "1":"0");
}
else if( mg_vcmp( uri, "/blink1/random") == 0 ) {
sprintf(status, "blink1 random");
if( count==0 ) { count = 1; }
if( millis==0 ) { millis = 200; }
blink1_device* dev = cache_getDeviceById(id);
for( int i=0; i<count; i++ ) {
uint8_t r = rand() % 255;
uint8_t g = rand() % 255;
uint8_t b = rand() % 255 ;
blink1_adjustBrightness( bright, &r, &g, &b);
blink1_fadeToRGBN( dev, millis/2, r,g,b, ledn );
blink1_sleep( millis/2 ); // fixme
}
cache_return(dev);
}
else {
if( show_html ) {
if( mg_vcmp( uri, "/") == 0 ) {
resp_code = 302;
mg_http_reply(c, resp_code, "Location: /index.html\r\n", "");
}
else {
resp_code = 200; // I guess
struct mg_http_serve_opts opts = {
.root_dir = "/",
.fs = &mg_fs_packed
};
mg_http_serve_dir(c, ev_data, &opts);
}
}
else if ( mg_vcmp( uri, "/") == 0 ) {
sprintf(status, "Welcome to %s api server. All URIs start with '/blink1'.", blink1_server_name);
//sprintf(status, "%s. \nSupported URIs:\n", status);
//for( int i=0; i< sizeof(supported_urls)/sizeof(url_info); i++ ) {
// sprintf(status+strlen(status), " %s - %s\n",
// supported_urls[i].url, supported_urls[i].desc);
}
}
if( status[0] != '\0' ) {
resp_code = 200;
sprintf(tmpstr, "#%2.2x%2.2x%2.2x", rgb.r,rgb.g,rgb.b );
mg_printf(c, "HTTP/1.1 %d OK\r\n", resp_code);
mg_printf(c, "Content-type: application/json\r\n");
mg_printf(c, "X-Content-Type-Options: nosniff\r\n");
mg_printf(c, "Transfer-Encoding: chunked\r\n\r\n");
mg_http_printf_chunk(c,
"{\n");
DictionaryPrintAsJsonMg(c, resultsdict);
// these aren't in the resultsdict because storing numbers is annoying
mg_http_printf_chunk(c,
"\"millis\": %d,\n"
"\"time\": %g,\n"
"\"rgb\": \"%s\",\n"
"\"ledn\": %d,\n"
"\"bright\": %d,\n"
"\"count\": %d,\n"
"\"status\": \"%s\"\n",
millis,
(millis/1000.0),
tmpstr,
ledn,
bright,
count,
status
);
mg_http_printf_chunk(c,
"}\n"
);
mg_http_write_chunk(c, "", 0); /* Send empty chunk, the end of response */
}
else {
mg_http_reply(c, 404, NULL, "Not found\n");
}
// access logging
if( enable_logging ) {
log_access(c, uri_str, resp_code);
}
}
// ----------------------------------------------------------------------
// Handle interrupts, like Ctrl-C
static int s_signo;
static void signal_handler(int signo) {
s_signo = signo;
}
int main(int argc, char *argv[]) {
struct mg_mgr mgr;
struct mg_connection *c;
int port;
setbuf(stdout,NULL); // turn off stdout buffering for Windows
srand( time(NULL) * getpid() );
patterndictc = DictionaryStandardStringCallbacks();
patterndict = DictionaryCreate( 100, &patterndictc );
// parse options
int option_index = 0, opt;
char* opt_str = "qvhp:H:U:A:Nl";
static struct option loptions[] = {
//{"verbose", optional_argument, 0, 'v'},
//{"quiet", optional_argument, 0, 'q'},
//{"baseurl", required_argument, 0, 'U'},
{"host", required_argument, 0, 'H'},
{"port", required_argument, 0, 'p'},
{"no-html", no_argument, 0, 'N'},
{"logging", no_argument, 0, 'l'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{NULL, 0, 0, 0 },
};
while(1) {
opt = getopt_long_only(argc, argv, opt_str, loptions, &option_index);
if (opt==-1) break; // parsed all the args
switch (opt) {
case 'h':
usage();
exit(1);
break;
case 'V':
printf("%s version %s\n", blink1_server_name,blink1_server_version);
exit(1);
break;
case 'v':
break;
case 'N':
show_html = false;
break;
case 'l':
enable_logging = true;
break;
case 'H':
strncpy(http_listen_host, optarg, sizeof(http_listen_host));
break;
case 'p':
port = strtod(optarg,NULL);
if( port > 0 && port < 65535 ) {
http_listen_port = port;
}
else {
printf("bad port specified: %s\n", optarg);
}
break;
case 'd':
// s_http_server_opts.document_root = optarg;
// char path[MAX_PATH_SIZE];
// cs_stat_t st;
// for( int i=0; i< sizeof(index_files)/sizeof(char* const); i++ ) {
// snprintf(path, sizeof(path), "%s/%s", s_http_server_opts.document_root, index_files[i]);
// if( mg_stat(path, &st) == 0 ) {
// serve_index = true;
// break;
// }
// }
break;
}
} //while(1) arg parsing
printf("%s version %s: running on http://%s:%d/ (%s)\n",
blink1_server_name, blink1_server_version, http_listen_host,
http_listen_port, (show_html) ? "html help enabeld": "no html help");
snprintf(http_listen_url, sizeof(http_listen_url), "http://%s:%d/",
http_listen_host, http_listen_port);
// if( s_http_server_opts.document_root ) {
// printf(" serving static HTML %s (with%s root index)\n",
// //s_http_server_opts.document_root, serve_index ? "" : "out");
// s_http_server_opts.fs = &mg_fs_packed; // Set packed ds as a file system
// mg_http_serve_dir(c, ev_data, &opts);
// // }
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
mg_mgr_init(&mgr);
if ((c = mg_http_listen(&mgr, http_listen_url, ev_handler, &mgr)) == NULL) {
MG_LOG(MG_LL_ERROR, ("Cannot listen on %s.", http_listen_url));
exit(EXIT_FAILURE);
}
while (s_signo == 0) {
mg_mgr_poll(&mgr, 1000);
cache_flush(idle_atime);
}
mg_mgr_free(&mgr);
return 0;
}