173 lines
4.3 KiB
C
173 lines
4.3 KiB
C
|
#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;
|
||
|
}
|