Implement HTTP server for requests
This commit is contained in:
parent
fe1547b37d
commit
6e5b86c076
@ -157,13 +157,18 @@ struct dijkstra_path *dijkstra_path_dup_shallow(struct dijkstra_path *path)
|
|||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float dijkstra_position_get_distance(struct position *position_a,
|
||||||
|
struct position *position_b) {
|
||||||
|
return sqrt(pow(position_a->x - position_b->x, 2) +
|
||||||
|
pow(position_a->y - position_b->y, 2));
|
||||||
|
}
|
||||||
|
|
||||||
dijkstra_cost dijkstra_get_weight_from_distance(struct dijkstra_node *node_a,
|
dijkstra_cost dijkstra_get_weight_from_distance(struct dijkstra_node *node_a,
|
||||||
struct dijkstra_node *node_b)
|
struct dijkstra_node *node_b)
|
||||||
{
|
{
|
||||||
float dist;
|
float dist;
|
||||||
|
|
||||||
dist = sqrt(pow(node_a->position.x - node_b->position.x, 2) +
|
dist = dijkstra_position_get_distance(&node_a->position, &node_b->position);
|
||||||
pow(node_a->position.y - node_b->position.y, 2));
|
|
||||||
|
|
||||||
if (dist < DIJKSTRA_COST_MIN)
|
if (dist < DIJKSTRA_COST_MIN)
|
||||||
dist = DIJKSTRA_COST_MIN;
|
dist = DIJKSTRA_COST_MIN;
|
||||||
@ -408,3 +413,23 @@ inline struct dijkstra_node *dijkstra_node_get_connection(struct dijkstra_node *
|
|||||||
}
|
}
|
||||||
return (path->destination == node ? path->source : path->destination);
|
return (path->destination == node ? path->source : path->destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dijkstra_node *dijkstra_node_find_closest_node(struct dijkstra_solver *solver,
|
||||||
|
struct position *position) {
|
||||||
|
GList *l = NULL;
|
||||||
|
struct dijkstra_node *node = NULL;
|
||||||
|
struct dijkstra_node *closest_node = NULL;
|
||||||
|
float closest_distance;
|
||||||
|
float distance;
|
||||||
|
|
||||||
|
for (l = solver->nodes; l != NULL; l = l->next) {
|
||||||
|
node = (struct dijkstra_node*) l->data;
|
||||||
|
distance = dijkstra_position_get_distance(position, &node->position);
|
||||||
|
if (!closest_node || distance < closest_distance) {
|
||||||
|
closest_node = node;
|
||||||
|
closest_distance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest_node;
|
||||||
|
}
|
||||||
|
@ -49,6 +49,8 @@ void dijkstra_solver_free(struct dijkstra_solver *solver);
|
|||||||
/* Library functions */
|
/* Library functions */
|
||||||
struct dijkstra_node *dijkstra_node_get_connection(struct dijkstra_node *node,
|
struct dijkstra_node *dijkstra_node_get_connection(struct dijkstra_node *node,
|
||||||
struct dijkstra_path *path);
|
struct dijkstra_path *path);
|
||||||
|
struct dijkstra_node *dijkstra_node_find_closest_node(struct dijkstra_solver *solver,
|
||||||
|
struct position *position);
|
||||||
|
|
||||||
/* For debugging only */
|
/* For debugging only */
|
||||||
struct dijkstra_node *dijkstra_node_new_to_list(GList **list,
|
struct dijkstra_node *dijkstra_node_new_to_list(GList **list,
|
||||||
|
@ -203,8 +203,27 @@ GList *dijkstra_search_get_route(struct dijkstra_search *search,
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dijkstra_search_route_to_geojson(struct dijkstra_search *search,
|
int printb(char **buf, int *offset, const char *__restrict __format, ...)
|
||||||
GList *route)
|
{
|
||||||
|
va_list vargs;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
va_start(vargs, __format);
|
||||||
|
len = vsnprintf(NULL, 0, __format, vargs);
|
||||||
|
va_end(vargs);
|
||||||
|
*buf = realloc(*buf, *offset + len + 1);
|
||||||
|
va_start(vargs, __format);
|
||||||
|
len = vsprintf(*buf + *offset, __format, vargs);
|
||||||
|
va_end(vargs);
|
||||||
|
|
||||||
|
*offset += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Rewrite to use glib-json... On the other hand, this is probably faster.
|
||||||
|
int dijkstra_search_route_to_geojson(struct dijkstra_search *search,
|
||||||
|
GList *route,
|
||||||
|
char **buf)
|
||||||
{
|
{
|
||||||
GList *l = NULL;
|
GList *l = NULL;
|
||||||
struct dijkstra_node *node = NULL;
|
struct dijkstra_node *node = NULL;
|
||||||
@ -213,8 +232,11 @@ void dijkstra_search_route_to_geojson(struct dijkstra_search *search,
|
|||||||
float last_heading = 0;
|
float last_heading = 0;
|
||||||
char *relative_direction_str = NULL;
|
char *relative_direction_str = NULL;
|
||||||
char *format_str = NULL;
|
char *format_str = NULL;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
printf("[");
|
*buf = NULL;
|
||||||
|
|
||||||
|
printb(buf, &offset, "[");
|
||||||
|
|
||||||
for (l = route; l != NULL; l = l->next) {
|
for (l = route; l != NULL; l = l->next) {
|
||||||
node = (struct dijkstra_node*) l->data;
|
node = (struct dijkstra_node*) l->data;
|
||||||
@ -236,31 +258,33 @@ void dijkstra_search_route_to_geojson(struct dijkstra_search *search,
|
|||||||
format_str = "Go %s onto %s.";
|
format_str = "Go %s onto %s.";
|
||||||
|
|
||||||
if (node_last != search->start)
|
if (node_last != search->start)
|
||||||
printf(",");
|
printb(buf, &offset, ",");
|
||||||
printf("\n");
|
printb(buf, &offset, "\n");
|
||||||
printf("{\"type\": \"Feature\",\n"
|
printb(buf, &offset, "{\"type\": \"Feature\",\n"
|
||||||
" \"geometry\": {\n"
|
" \"geometry\": {\n"
|
||||||
" \"type\": \"LineString\", \"coordinates\": [[%f,%f],[%f,%f]]\n"
|
" \"type\": \"LineString\", \"coordinates\": [[%f,%f],[%f,%f]]\n"
|
||||||
" },\n",
|
" },\n",
|
||||||
node_last->position.x, node_last->position.y,
|
node_last->position.x, node_last->position.y,
|
||||||
node->position.x, node->position.y);
|
node->position.x, node->position.y);
|
||||||
printf(" \"properties\": {\n"
|
printb(buf, &offset, " \"properties\": {\n"
|
||||||
" \"heading\": \"%f\",\n"
|
" \"heading\": \"%f\",\n"
|
||||||
" \"through\": \"%s\",\n",
|
" \"through\": \"%s\",\n",
|
||||||
heading, search->states[node->uid]->cheapest_path->name);
|
heading, search->states[node->uid]->cheapest_path->name);
|
||||||
|
|
||||||
printf(" \"description\": \"");
|
printb(buf, &offset, " \"description\": \"");
|
||||||
printf(format_str, relative_direction_str, search->states[node->uid]->cheapest_path->name);
|
printb(buf, &offset, format_str, relative_direction_str, search->states[node->uid]->cheapest_path->name);
|
||||||
printf("\"\n");
|
printb(buf, &offset, "\"\n");
|
||||||
|
|
||||||
printf(" }\n");
|
printb(buf, &offset, " }\n");
|
||||||
printf("}");
|
printb(buf, &offset, "}");
|
||||||
last_heading = heading;
|
last_heading = heading;
|
||||||
}
|
}
|
||||||
node_last = node;
|
node_last = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("]\n");
|
printb(buf, &offset, "\n]\n");
|
||||||
|
|
||||||
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dijkstra_print_path(struct dijkstra_search *search,
|
void dijkstra_print_path(struct dijkstra_search *search,
|
||||||
|
@ -32,6 +32,7 @@ GList *dijkstra_search_get_route(struct dijkstra_search *search,
|
|||||||
void dijkstra_print_path(struct dijkstra_search *search,
|
void dijkstra_print_path(struct dijkstra_search *search,
|
||||||
struct dijkstra_node *destination);
|
struct dijkstra_node *destination);
|
||||||
void dijkstra_print_nodes(struct dijkstra_search *search);
|
void dijkstra_print_nodes(struct dijkstra_search *search);
|
||||||
void dijkstra_search_route_to_geojson(struct dijkstra_search *search,
|
int dijkstra_search_route_to_geojson(struct dijkstra_search *search,
|
||||||
GList *route);
|
GList *route,
|
||||||
|
char **buf);
|
||||||
#endif // DIJKSTRASEARCH_H
|
#endif // DIJKSTRASEARCH_H
|
||||||
|
172
src/dijkstraserv.c
Normal file
172
src/dijkstraserv.c
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
#include "dijkstraserv.h"
|
||||||
|
|
||||||
|
static int dijkstra_serv_perform_search(struct dijkstra_serv *serv,
|
||||||
|
struct position *pos_start,
|
||||||
|
struct position *pos_destination,
|
||||||
|
char **result) {
|
||||||
|
struct dijkstra_node *start = NULL;
|
||||||
|
struct dijkstra_node *destination = NULL;
|
||||||
|
|
||||||
|
struct dijkstra_search *search;
|
||||||
|
int iterations;
|
||||||
|
GList *route;
|
||||||
|
|
||||||
|
report(LL_INFO, "Requested route from %f,%f to %f,%f.",
|
||||||
|
pos_start->x, pos_start->y,
|
||||||
|
pos_destination->x, pos_destination->y);
|
||||||
|
|
||||||
|
/* Find closest node */ // TODO: This should be closest point on path, but for now this'll do.
|
||||||
|
start = dijkstra_node_find_closest_node(serv->solver, pos_start);
|
||||||
|
if (!start)
|
||||||
|
return 0;
|
||||||
|
destination = dijkstra_node_find_closest_node(serv->solver, pos_destination);
|
||||||
|
if (!destination)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
report(LL_DEBUG, "Searching route from %f,%f to %f,%f.",
|
||||||
|
start->position.x, start->position.y,
|
||||||
|
destination->position.x, destination->position.y);
|
||||||
|
|
||||||
|
search = dijkstra_search_new(serv->solver);
|
||||||
|
if (!search) {
|
||||||
|
report(LL_CRITICAL, "Error allocating dijkstra_search");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dijkstra_search_set_start(search, start);
|
||||||
|
if ((iterations = dijkstra_search_find_path(search, destination)) > 0) {
|
||||||
|
report(LL_INFO, " Found path from %d to %d after %d iterations.", start->uid, destination->uid, iterations);
|
||||||
|
route = dijkstra_search_get_route(search, destination);
|
||||||
|
return dijkstra_search_route_to_geojson(search, route, result);
|
||||||
|
} else {
|
||||||
|
report(LL_INFO, " Couldn't find path.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dijkstra_serv_soup_callback (SoupServer *server,
|
||||||
|
SoupMessage *msg,
|
||||||
|
const char *path,
|
||||||
|
GHashTable *query,
|
||||||
|
SoupClientContext *client,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct dijkstra_serv *serv = (struct dijkstra_serv *) user_data;
|
||||||
|
GError *err = NULL;
|
||||||
|
GMatchInfo *matchInfo;
|
||||||
|
GRegex *regex;
|
||||||
|
char *body;
|
||||||
|
int body_len;
|
||||||
|
int i = 0;
|
||||||
|
struct position pos_start, pos_destination;
|
||||||
|
|
||||||
|
report(LL_INFO, "New request: %s", path);
|
||||||
|
if (msg->method != SOUP_METHOD_GET) {
|
||||||
|
soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(path) > 20) {
|
||||||
|
soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
regex = g_regex_new("([\\-0-9]+)", 0, 0, &err);
|
||||||
|
g_regex_match (regex, path, 0, &matchInfo);
|
||||||
|
|
||||||
|
while (g_match_info_matches(matchInfo)) {
|
||||||
|
float result_num;
|
||||||
|
gchar *result;
|
||||||
|
result = g_match_info_fetch(matchInfo, 0);
|
||||||
|
if (!result)
|
||||||
|
break;
|
||||||
|
|
||||||
|
result_num = atof(result);
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
pos_start.x = result_num;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
pos_start.y = result_num;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pos_destination.x = result_num;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
pos_destination.y = result_num;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_match_info_next(matchInfo, &err);
|
||||||
|
g_free(result);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if (i >= 4)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_regex_unref(regex);
|
||||||
|
|
||||||
|
if (i == 4) {
|
||||||
|
body_len = dijkstra_serv_perform_search(serv, &pos_start, &pos_destination, &body);
|
||||||
|
if (!body_len) {
|
||||||
|
body = strdup("Not found.");
|
||||||
|
body_len = 9;
|
||||||
|
soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
|
||||||
|
} else {
|
||||||
|
soup_message_set_status (msg, SOUP_STATUS_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
soup_message_set_response (msg, "application/json", SOUP_MEMORY_COPY,
|
||||||
|
body, body_len);
|
||||||
|
free(body);
|
||||||
|
} else {
|
||||||
|
report(LL_WARNING, " Invalid request.");
|
||||||
|
soup_message_set_status (msg, SOUP_STATUS_MALFORMED);
|
||||||
|
soup_message_set_response (msg, "text/plain", SOUP_MEMORY_COPY,
|
||||||
|
"Invalid request", 15);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dijkstra_serv *dijkstra_serv_new(
|
||||||
|
struct dijkstra_solver *solver,
|
||||||
|
int port)
|
||||||
|
{
|
||||||
|
struct dijkstra_serv *serv;
|
||||||
|
|
||||||
|
serv = (struct dijkstra_serv*) malloc(sizeof(*serv));
|
||||||
|
if (serv) {
|
||||||
|
serv->solver = solver;
|
||||||
|
serv->port = port;
|
||||||
|
serv->soupserver = soup_server_new(NULL, NULL);
|
||||||
|
if (!serv->soupserver) {
|
||||||
|
free(serv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
soup_server_add_handler (serv->soupserver,
|
||||||
|
"/", dijkstra_serv_soup_callback,
|
||||||
|
serv, NULL); // TODO: The last arg here should probably not be NULL...
|
||||||
|
}
|
||||||
|
|
||||||
|
return serv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dijkstra_serv_run(struct dijkstra_serv *serv)
|
||||||
|
{
|
||||||
|
GError *err = NULL;
|
||||||
|
|
||||||
|
if (!soup_server_listen_all(serv->soupserver, serv->port, 0, &err)) {
|
||||||
|
report(LL_CRITICAL, "Couldn't start server: %s", err->message);
|
||||||
|
g_error_free(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
report(LL_INFO, "Listening on port %d.", serv->port);
|
||||||
|
|
||||||
|
GMainLoop *loop;
|
||||||
|
loop = g_main_loop_new(NULL, TRUE);
|
||||||
|
g_main_loop_run(loop); // TODO: Add way to gracefully exit loop
|
||||||
|
return 0;
|
||||||
|
}
|
22
src/dijkstraserv.h
Normal file
22
src/dijkstraserv.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef DIJKSTRASERV_H
|
||||||
|
#define DIJKSTRASERV_H
|
||||||
|
|
||||||
|
#include "dijkstragraph.h"
|
||||||
|
#include "dijkstrasearch.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
#include <libsoup/soup.h>
|
||||||
|
|
||||||
|
struct dijkstra_serv {
|
||||||
|
struct dijkstra_solver *solver;
|
||||||
|
int port;
|
||||||
|
|
||||||
|
SoupServer *soupserver;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dijkstra_serv *dijkstra_serv_new(
|
||||||
|
struct dijkstra_solver *solver,
|
||||||
|
int port);
|
||||||
|
int dijkstra_serv_run(struct dijkstra_serv *serv);
|
||||||
|
|
||||||
|
#endif // DIJKSTRASERV_H
|
40
src/main.c
40
src/main.c
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "dijkstragraph.h"
|
#include "dijkstragraph.h"
|
||||||
#include "dijkstrasearch.h"
|
#include "dijkstrasearch.h"
|
||||||
|
#include "dijkstraserv.h"
|
||||||
#include "geojson.h"
|
#include "geojson.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
|
||||||
@ -48,16 +49,14 @@ int main(int argc, char *argv[])
|
|||||||
struct dijkstra_node *node;
|
struct dijkstra_node *node;
|
||||||
struct dijkstra_path *path;
|
struct dijkstra_path *path;
|
||||||
|
|
||||||
struct dijkstra_search *search;
|
int port = 6802;
|
||||||
int iterations;
|
struct dijkstra_serv *serv;
|
||||||
|
|
||||||
GList *route = NULL;
|
|
||||||
|
|
||||||
/* Init stuff */
|
/* Init stuff */
|
||||||
set_log_level(LL_DEBUG);
|
set_log_level(LL_DEBUG);
|
||||||
|
|
||||||
/* Process arguments */
|
/* Process arguments */
|
||||||
while((opt = getopt(argc, argv, "vs")) != -1) {
|
while((opt = getopt(argc, argv, "vsp")) != -1) {
|
||||||
switch(opt)
|
switch(opt)
|
||||||
{
|
{
|
||||||
case 'v':
|
case 'v':
|
||||||
@ -66,6 +65,9 @@ int main(int argc, char *argv[])
|
|||||||
case 's':
|
case 's':
|
||||||
set_log_level(0);
|
set_log_level(0);
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
port = atoi(argv[i]);
|
||||||
|
break;
|
||||||
case ':':
|
case ':':
|
||||||
case '?':
|
case '?':
|
||||||
help(argv[0]);
|
help(argv[0]);
|
||||||
@ -92,13 +94,6 @@ int main(int argc, char *argv[])
|
|||||||
add_geojson_to_dijkstra(solver, argv[i]);
|
add_geojson_to_dijkstra(solver, argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add_test_map(solver);
|
|
||||||
// TODO: This start / end coordinates are only for testing
|
|
||||||
start = dijkstra_node_new_to_list(&solver->nodes, -856, -393);
|
|
||||||
dest = dijkstra_node_new_to_list(&solver->nodes, 388, 99);
|
|
||||||
//start = dijkstra_node_new_to_list(&solver->nodes, -957, -467);
|
|
||||||
//dest = dijkstra_node_new_to_list(&solver->nodes, -712, -467);
|
|
||||||
|
|
||||||
if (should_report(LL_NOISY)) {
|
if (should_report(LL_NOISY)) {
|
||||||
for (l = solver->nodes; l != NULL; l = l->next) {
|
for (l = solver->nodes; l != NULL; l = l->next) {
|
||||||
node = (struct dijkstra_node*) l->data;
|
node = (struct dijkstra_node*) l->data;
|
||||||
@ -121,25 +116,14 @@ int main(int argc, char *argv[])
|
|||||||
g_list_length(solver->nodes),
|
g_list_length(solver->nodes),
|
||||||
g_list_length(solver->paths));
|
g_list_length(solver->paths));
|
||||||
|
|
||||||
/* Perform search */
|
/* Start server */
|
||||||
search = dijkstra_search_new(solver);
|
serv = dijkstra_serv_new(solver, port);
|
||||||
if (!search) {
|
if (!serv) {
|
||||||
report(LL_ERROR, "Error allocating dijkstra_search");
|
|
||||||
dijkstra_solver_free(solver);
|
dijkstra_solver_free(solver);
|
||||||
return -3;
|
return -4;
|
||||||
}
|
|
||||||
dijkstra_search_set_start(search, start);
|
|
||||||
if ((iterations = dijkstra_search_find_path(search, dest)) > 0) {
|
|
||||||
report(LL_INFO, "Found path from %d to %d after %d iterations.", start->uid, dest->uid, iterations);
|
|
||||||
route = dijkstra_search_get_route(search, dest);
|
|
||||||
dijkstra_search_route_to_geojson(search, route);
|
|
||||||
// dijkstra_print_path(search, dest);
|
|
||||||
// dijkstra_print_nodes(search);
|
|
||||||
} else {
|
|
||||||
report(LL_WARNING, "Couldn't find path.");
|
|
||||||
}
|
}
|
||||||
|
dijkstra_serv_run(serv);
|
||||||
|
|
||||||
dijkstra_search_free(search);
|
|
||||||
dijkstra_solver_free(solver);
|
dijkstra_solver_free(solver);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user