#ifndef nullptr
|
#define nullptr NULL
|
#endif
|
|
#include <unistd.h>
|
#include <time.h>
|
#include <errno.h>
|
|
#include <stdlib.h>
|
#include <iostream>
|
#include <map>
|
#include <vector>
|
#include <string>
|
#include <sstream>
|
#include <algorithm>
|
#include <iterator>
|
#include <cctype>
|
|
using namespace std;
|
|
// http://www.fastcgi.com
|
#include <fcgi_stdio.h>
|
#include <fcgi_config.h>
|
|
// http://uriparser.sourceforge.net
|
#include <uriparser/Uri.h>
|
|
// http://www.postgresql.org
|
//#include <pgsql/libpq-fe.h>
|
#include <libpq-fe.h>
|
|
// https://github.com/open-source-parsers/jsoncpp
|
#include <json/json.h>
|
|
#define SOCK_TCP
|
#include <cmdhub/client.h>
|
|
#include "sqlmaker/sqlmaker.h"
|
|
my_id_t get_my_id()
|
{
|
static my_id_t myid = 0;
|
myid++;
|
return myid;
|
}
|
|
char to_upper(char c)
|
{
|
return toupper((int)c);
|
}
|
|
extern char **environ;
|
static char **g_initial_nv = nullptr;
|
static size_t g_req_count = 0;
|
|
stringstream g_log_msg;
|
stringstream g_http_res;
|
|
typedef void (*url_process_func_t)();
|
typedef map<string, url_process_func_t> upf_map_t;
|
static upf_map_t g_url_processors;
|
|
typedef map<string, string> str_map_t;
|
|
static void http_res_200(const char* msg)
|
{
|
FCGI_printf("Status: 20 OK\r\n" "Content-type: text/html\r\n" "\r\n" "%s", msg);
|
}
|
static void http_res_400()
|
{
|
FCGI_printf("Status: 400 Bad Request\r\n" "Content-type: text/html\r\n" "\r\n");
|
}
|
static void http_res_401()
|
{
|
FCGI_printf("Status: 401 Unauthorized\r\n" "Content-type: text/html\r\n" "\r\n");
|
}
|
static void http_res_404()
|
{
|
FCGI_printf("Status: 404 Not Found\r\n" "\r\n");
|
}
|
static void http_res_500()
|
{
|
FCGI_printf("Status: 500 Internal Server Error\r\n" "\r\n");
|
}
|
static void http_res_500(int problem_code = 0)
|
{
|
FCGI_printf("Status: 500 Internal Server Error\r\n" "Content-type: text/html\r\n" "\r\n" "Problem code = %d", problem_code);
|
}
|
static void http_res_500(const char* msg)
|
{
|
FCGI_printf("Status: 500 Internal Server Error\r\n" "Content-type: text/html\r\n" "\r\n" "Message = %s", msg);
|
}
|
|
size_t read_shell(const char* cmd, char* buffer, size_t buffer_size, int* exit_status = nullptr, int* exit_code = nullptr)
|
{
|
if (cmd == nullptr)
|
return 0;
|
|
FCGI_FILE* fcmd = FCGI_popen(cmd, "r");
|
if (fcmd == nullptr)
|
return 0;
|
|
size_t red = FCGI_fread(buffer, sizeof(char), buffer_size - 1, fcmd);
|
|
int es = FCGI_pclose(fcmd);
|
|
if (exit_status != nullptr)
|
*exit_status = es;
|
if (exit_code != nullptr)
|
*exit_code = WEXITSTATUS(es);
|
|
return red;
|
}
|
|
void run_in_bash(const char* cmd, int* exit_status = nullptr, int* exit_code = nullptr)
|
{
|
#define BASH_WRAPPER "su -s /bin/bash -c '%s' http"
|
|
char buffer[512];
|
snprintf(buffer, sizeof(buffer) - 1, BASH_WRAPPER, cmd);
|
|
int es = system(buffer);
|
|
if (exit_status != nullptr)
|
*exit_status = es;
|
if (exit_code != nullptr)
|
*exit_code = WEXITSTATUS(es);
|
}
|
|
static void print_env(const char *label, char **envp)
|
{
|
FCGI_printf("%s:<br>\n<pre>\n", label);
|
for ( ; *envp != NULL; envp++)
|
{
|
FCGI_printf("%s\n", *envp);
|
}
|
FCGI_printf("</pre><p>\n");
|
}
|
|
static void hpf_echo()
|
{
|
g_log_msg.flush();
|
|
char *contentLength = getenv("CONTENT_LENGTH");
|
int len;
|
|
FCGI_printf("Content-type: text/html\r\n"
|
"\r\n"
|
"<title>FastCGI echo</title>"
|
"<h1>FastCGI echo</h1>\n"
|
"Request number %d, Process ID: %d<p>\n", g_req_count, getpid());
|
|
if (contentLength != NULL)
|
len = strtol(contentLength, NULL, 10);
|
else
|
len = 0;
|
|
if (len <= 0)
|
{
|
FCGI_printf("No data from standard input.<p>\n");
|
}
|
else
|
{
|
int i, ch;
|
|
FCGI_printf("Standard input:<br>\n<pre>\n");
|
for (i = 0; i < len; i++)
|
{
|
if ((ch = getchar()) < 0)
|
{
|
FCGI_printf("Error: Not enough bytes received on standard input<p>\n");
|
break;
|
}
|
putchar(ch);
|
}
|
FCGI_printf("\n</pre><p>\n");
|
}
|
|
print_env("Request environment", environ);
|
print_env("Initial environment", g_initial_nv);
|
}
|
|
bool parse_query_items(str_map_t& query_items)
|
{
|
char* req_REQUEST_URI;
|
req_REQUEST_URI = getenv("REQUEST_URI");
|
if (req_REQUEST_URI == nullptr)
|
{
|
g_log_msg << "can not get REQUEST_URI" << endl;
|
goto error_ret;
|
}
|
|
char* req_QUERY_STRING;
|
req_QUERY_STRING = getenv("QUERY_STRING");
|
if (req_QUERY_STRING == nullptr)
|
{
|
g_log_msg << "can not get QUERY_STRING" << endl;
|
goto error_ret;
|
}
|
else if (req_QUERY_STRING[0] == '\0')
|
{
|
g_log_msg << "QUERY_STRING is empty" << endl;
|
return true;
|
}
|
|
UriParserStateA state;
|
UriUriA uri;
|
|
state.uri = &uri;
|
if (uriParseUriA(&state, req_REQUEST_URI) != URI_SUCCESS)
|
{
|
g_log_msg << "uriParseUriA not success" << endl;
|
goto error_ret_uri_1;
|
}
|
|
UriQueryListA * query_list;
|
query_list = nullptr;
|
int ql_item_count;
|
ql_item_count = 0;
|
if (uriDissectQueryMallocA(&query_list, &ql_item_count, uri.query.first, uri.query.afterLast) != URI_SUCCESS)
|
{
|
g_log_msg << "uriDissectQueryMallocA not success" << endl;
|
goto error_ret_uri_2;
|
}
|
|
//debug:
|
//FCGI_printf("Content-type: text/json\r\n" "\r\n");
|
|
UriQueryListA* iter_query_list;
|
iter_query_list = query_list;
|
while (iter_query_list != nullptr)
|
{
|
const char* qi_key = iter_query_list->key;
|
const char* qi_value = iter_query_list->value;
|
|
if(qi_key == nullptr || qi_value == nullptr)
|
{
|
g_log_msg << "query_list contains null key or value" << endl;
|
goto error_ret_uri_2;
|
}
|
|
query_items[string(qi_key)] = string(qi_value);
|
//debug:
|
//FCGI_printf("%s=%s\n", qi_key, qi_value);
|
iter_query_list = iter_query_list->next;
|
}
|
|
uriFreeQueryListA(query_list);
|
uriFreeUriMembersA(&uri);
|
return true;
|
|
error_ret_uri_2:
|
uriFreeQueryListA(query_list);
|
error_ret_uri_1:
|
uriFreeUriMembersA(&uri);
|
error_ret:
|
return false;
|
}
|
|
size_t get_post_content(char* buffer, size_t max_size, size_t offset_content = 0)
|
{
|
if (buffer == NULL || max_size == 0)
|
return 0;
|
|
const char* contentLength = getenv("CONTENT_LENGTH");
|
size_t len = 0;
|
if (contentLength != NULL)
|
len = strtol(contentLength, NULL, 10);
|
|
if (len == 0)
|
return 0;
|
|
if (offset_content > 0)
|
fseek(stdin, offset_content, SEEK_SET);
|
|
return fread(buffer, sizeof(char), min(max_size, len), stdin);
|
}
|
|
const string* try_get_str_from_map(const str_map_t& str_map, const string& key, const string* default_value = nullptr)
|
{
|
str_map_t::const_iterator iter = str_map.find(key);
|
if (iter == str_map.end())
|
return default_value;
|
else
|
return &(iter->second);
|
}
|
|
|
|
|
|
static void hpf_fishbowl_fish_count()
|
{
|
g_log_msg.flush();
|
|
str_map_t query_items;
|
if (! parse_query_items(query_items))
|
{
|
http_res_500(g_log_msg.str().c_str());
|
return;
|
}
|
|
Json::Value json_root;
|
|
bool json_ret = true;
|
const string* qi_cmd = try_get_str_from_map(query_items, string("cmd"));
|
if (qi_cmd == nullptr)
|
{
|
json_root["msg"] = "cmd not needed";
|
}
|
else
|
{
|
if (strcmp("list", qi_cmd->c_str()) == 0)
|
{
|
json_ret = hpf_fishbowl_fish_count_list(query_items, json_root);
|
}
|
else if (strcmp("variate", qi_cmd->c_str()) == 0)
|
{
|
json_ret = hpf_fishbowl_fish_count_variate(query_items, json_root);
|
}
|
else if (strcmp("summed", qi_cmd->c_str()) == 0)
|
{
|
json_ret = hpf_fishbowl_fish_count_summed(query_items, json_root);
|
}
|
else if (strcmp("graph", qi_cmd->c_str()) == 0)
|
{
|
}
|
else
|
{
|
json_root["msg"] = "cmd not supported";
|
}
|
}
|
|
if (json_ret)
|
{
|
printf("Content-type: application/json\r\n" "\r\n");
|
printf("%s", json_root.toStyledString().c_str());
|
}
|
}
|
|
static void hpf_fishbowl_load_v4l2grab()
|
{
|
g_log_msg.flush();
|
errno = 0;
|
bool ret = false;
|
int exit_code = 0;
|
const std::string cmd("exec/LOAD_V4L2GRAB");
|
std::string result;
|
|
CmdhubClientSession session;
|
session.recv_retry = 20;
|
if (ret = cmdhub_client_init(session))
|
{
|
if (ret = cmdhub_client_connect(session))
|
{
|
ret = cmdhub_client_command(session, cmd, result, exit_code);
|
cmdhub_client_destory(session);
|
}
|
}
|
|
Json::Value json_root;
|
json_root["return"] = ret;
|
if (ret)
|
{
|
json_root["exitcode"] = exit_code;
|
json_root["result"] = result;
|
}
|
else
|
{
|
json_root["errno"] = errno;
|
}
|
|
printf("Content-type: application/json\r\n" "\r\n");
|
printf("%s", json_root.toStyledString().c_str());
|
}
|
|
int main ()
|
{
|
g_initial_nv = environ;
|
|
g_url_processors["/echo"] = hpf_echo;
|
g_url_processors["/fishbowl-basic-data"] = hpf_fishbowl_basic_data;
|
g_url_processors["/fishbowl-bdtype"] = hpf_fishbowl_bdtype;
|
g_url_processors["/fishbowl-fish-count"] = hpf_fishbowl_fish_count;
|
g_url_processors["/fishbowl-fish-type"] = hpf_fishbowl_fish_type;
|
g_url_processors["/fishbowl-fish-diary"] = hpf_fishbowl_fish_diary;
|
g_url_processors["/fishbowl-load-v4l2grab"] = hpf_fishbowl_load_v4l2grab;
|
//g_url_processors["/fishbowl-reminder"] = hpf_fishbowl_reminder;
|
|
if(psql_conn() == nullptr)
|
{
|
cerr << g_log_msg.rdbuf();
|
exit(EXIT_FAILURE);
|
}
|
|
cerr << "begin accept access" << endl;
|
|
int fcgi_accept_status;
|
|
while ((fcgi_accept_status = FCGI_Accept()) >= 0)
|
{
|
g_req_count++;
|
g_log_msg.flush();
|
|
char* req_PATH_INFO = getenv("PATH_INFO");
|
if(req_PATH_INFO == nullptr)
|
{
|
cerr << "PATH_INFO is null" << endl;
|
exit(EXIT_FAILURE);
|
}
|
|
upf_map_t::iterator iter_upf = g_url_processors.find(req_PATH_INFO);
|
if (iter_upf == g_url_processors.end())
|
{
|
http_res_404();
|
}
|
else
|
{
|
url_process_func_t proc = iter_upf->second;
|
proc();
|
}
|
}
|
|
PGconn* conn = psql_conn();
|
if (conn != nullptr)
|
PQfinish(conn);
|
|
cerr << "exit gracefully, fcgi_accept_status=" << fcgi_accept_status << endl;
|
|
return 0;
|
}
|