[jsonapi] Rework outputs endpoint and strictly match uris by request

method
This commit is contained in:
chme 2018-02-11 08:53:51 +01:00
parent 83bb06225b
commit 0e9feac829

View File

@ -64,13 +64,13 @@
* }
*/
static int
pairing_kickoff(struct evhttp_request *req)
jsonapi_reply_pairing_kickoff(struct httpd_request *hreq)
{
struct evbuffer *evbuf;
json_object* request;
const char* message;
evbuf = evhttp_request_get_input_buffer(req);
evbuf = evhttp_request_get_input_buffer(hreq->req);
request = jparse_obj_from_evbuffer(evbuf);
if (!request)
{
@ -102,7 +102,7 @@ pairing_kickoff(struct evhttp_request *req)
* }
*/
static int
pairing_get(struct evbuffer *evbuf)
jsonapi_reply_pairing_get(struct httpd_request *hreq)
{
char *remote_name;
json_object *jreply;
@ -121,7 +121,7 @@ pairing_get(struct evbuffer *evbuf)
json_object_object_add(jreply, "active", json_object_new_boolean(false));
}
CHECK_ERRNO(L_WEB, evbuffer_add_printf(evbuf, "%s", json_object_to_json_string(jreply)));
CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply)));
jparse_free(jreply);
free(remote_name);
@ -371,23 +371,6 @@ jsonapi_reply_spotify_login(struct httpd_request *hreq)
return HTTP_OK;
}
/*
* Endpoint to pair daap/dacp client
*
* If request is a GET request, returns information about active pairing remote.
* If request is a POST request, tries to pair the active remote with the given pin.
*/
static int
jsonapi_reply_pairing(struct httpd_request *hreq)
{
if (evhttp_request_get_command(hreq->req) == EVHTTP_REQ_POST)
{
return pairing_kickoff(hreq->req);
}
return pairing_get(hreq->reply);
}
static int
jsonapi_reply_lastfm(struct httpd_request *hreq)
{
@ -494,14 +477,18 @@ jsonapi_reply_lastfm_logout(struct httpd_request *hreq)
return HTTP_NOCONTENT;
}
static void
speaker_enum_cb(struct spk_info *spk, void *arg)
struct outputs_param
{
json_object *output;
uint64_t output_id;
};
static json_object *
speaker_to_json(struct spk_info *spk)
{
json_object *outputs;
json_object *output;
char output_id[21];
outputs = arg;
output = json_object_new_object();
snprintf(output_id, sizeof(output_id), "%" PRIu64, spk->id);
@ -514,14 +501,132 @@ speaker_enum_cb(struct spk_info *spk, void *arg)
json_object_object_add(output, "needs_auth_key", json_object_new_boolean(spk->needs_auth_key));
json_object_object_add(output, "volume", json_object_new_int(spk->absvol));
return output;
}
static void
speaker_enum_cb(struct spk_info *spk, void *arg)
{
json_object *outputs;
json_object *output;
outputs = arg;
output = speaker_to_json(spk);
json_object_array_add(outputs, output);
}
static void
speaker_get_cb(struct spk_info *spk, void *arg)
{
struct outputs_param *outputs_param = arg;
if (outputs_param->output_id == spk->id)
{
outputs_param->output = speaker_to_json(spk);
}
}
/*
* GET /api/outputs/[output_id]
*/
static int
jsonapi_reply_outputs_get_byid(struct httpd_request *hreq)
{
struct outputs_param outputs_param;
uint64_t output_id;
int ret;
ret = safe_atou64(hreq->uri_parsed->path_parts[2], &output_id);
if (ret < 0)
{
DPRINTF(E_LOG, L_WEB, "No valid output id given to outputs endpoint '%s'\n", hreq->uri_parsed->path);
return HTTP_BADREQUEST;
}
outputs_param.output_id = output_id;
outputs_param.output = NULL;
player_speaker_enumerate(speaker_get_cb, &outputs_param);
if (!outputs_param.output)
{
DPRINTF(E_LOG, L_WEB, "No output found for '%s'\n", hreq->uri_parsed->path);
return HTTP_BADREQUEST;
}
CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(outputs_param.output)));
jparse_free(outputs_param.output);
return HTTP_OK;
}
/*
* PUT /api/outputs/[output_id]
*/
static int
jsonapi_reply_outputs_put_byid(struct httpd_request *hreq)
{
uint64_t output_id;
struct evbuffer *in_evbuf;
json_object* request;
bool selected;
int volume;
int ret;
ret = safe_atou64(hreq->uri_parsed->path_parts[2], &output_id);
if (ret < 0)
{
DPRINTF(E_LOG, L_WEB, "No valid output id given to outputs endpoint '%s'\n", hreq->uri_parsed->path);
return HTTP_BADREQUEST;
}
in_evbuf = evhttp_request_get_input_buffer(hreq->req);
request = jparse_obj_from_evbuffer(in_evbuf);
if (!request)
{
DPRINTF(E_LOG, L_WEB, "Failed to parse incoming request\n");
return HTTP_BADREQUEST;
}
ret = 0;
if (jparse_contains_key(request, "selected", json_type_boolean))
{
selected = jparse_bool_from_obj(request, "selected");
if (selected)
ret = player_speaker_enable(output_id);
else
ret = player_speaker_disable(output_id);
}
if (ret == 0 && jparse_contains_key(request, "volume", json_type_int))
{
volume = jparse_int_from_obj(request, "volume");
ret = player_volume_setabs_speaker(output_id, volume);
}
jparse_free(request);
if (ret < 0)
return HTTP_INTERNAL;
return HTTP_NOCONTENT;
}
/*
* Endpoint "/api/outputs"
*/
static int
jsonapi_reply_outputs(struct httpd_request *hreq)
{
json_object *jreply;
json_object *outputs;
json_object *jreply;
outputs = json_object_new_array();
@ -544,12 +649,6 @@ jsonapi_reply_verification(struct httpd_request *hreq)
json_object* request;
const char* message;
if (evhttp_request_get_command(hreq->req) != EVHTTP_REQ_POST)
{
DPRINTF(E_LOG, L_WEB, "Verification: request is not a POST request\n");
return HTTP_BADREQUEST;
}
in_evbuf = evhttp_request_get_input_buffer(hreq->req);
request = jparse_obj_from_evbuffer(in_evbuf);
if (!request)
@ -572,7 +671,7 @@ jsonapi_reply_verification(struct httpd_request *hreq)
}
static int
jsonapi_reply_select_outputs(struct httpd_request *hreq)
jsonapi_reply_outputs_set(struct httpd_request *hreq)
{
struct evbuffer *in_evbuf;
json_object *request;
@ -581,12 +680,6 @@ jsonapi_reply_select_outputs(struct httpd_request *hreq)
int nspk, i, ret;
uint64_t *ids;
if (evhttp_request_get_command(hreq->req) != EVHTTP_REQ_POST)
{
DPRINTF(E_LOG, L_WEB, "Select outputs: request is not a POST request\n");
return HTTP_BADREQUEST;
}
in_evbuf = evhttp_request_get_input_buffer(hreq->req);
request = jparse_obj_from_evbuffer(in_evbuf);
if (!request)
@ -986,30 +1079,38 @@ jsonapi_reply_player_volume(struct httpd_request *hreq)
static struct httpd_uri_map adm_handlers[] =
{
{ .regexp = "^/api/config", .handler = jsonapi_reply_config },
{ .regexp = "^/api/library", .handler = jsonapi_reply_library },
{ .regexp = "^/api/update", .handler = jsonapi_reply_update },
{ .regexp = "^/api/spotify-login", .handler = jsonapi_reply_spotify_login },
{ .regexp = "^/api/spotify", .handler = jsonapi_reply_spotify },
{ .regexp = "^/api/pairing", .handler = jsonapi_reply_pairing },
{ .regexp = "^/api/lastfm-login", .handler = jsonapi_reply_lastfm_login },
{ .regexp = "^/api/lastfm-logout", .handler = jsonapi_reply_lastfm_logout },
{ .regexp = "^/api/lastfm", .handler = jsonapi_reply_lastfm },
{ .regexp = "^/api/outputs", .handler = jsonapi_reply_outputs },
{ .regexp = "^/api/select-outputs", .handler = jsonapi_reply_select_outputs },
{ .regexp = "^/api/verification", .handler = jsonapi_reply_verification },
{ .regexp = "^/api/player/play", .handler = jsonapi_reply_player_play },
{ .regexp = "^/api/player/pause", .handler = jsonapi_reply_player_pause },
{ .regexp = "^/api/player/stop", .handler = jsonapi_reply_player_stop },
{ .regexp = "^/api/player/next", .handler = jsonapi_reply_player_next },
{ .regexp = "^/api/player/previous", .handler = jsonapi_reply_player_previous },
{ .regexp = "^/api/player/shuffle", .handler = jsonapi_reply_player_shuffle },
{ .regexp = "^/api/player/repeat", .handler = jsonapi_reply_player_repeat },
{ .regexp = "^/api/player/consume", .handler = jsonapi_reply_player_consume },
{ .regexp = "^/api/player/volume", .handler = jsonapi_reply_player_volume },
{ .regexp = "^/api/player", .handler = jsonapi_reply_player },
{ .regexp = "^/api/queue", .handler = jsonapi_reply_queue },
{ .regexp = NULL, .handler = NULL }
{ EVHTTP_REQ_GET, "^/api/config$", jsonapi_reply_config },
{ EVHTTP_REQ_GET, "^/api/library$", jsonapi_reply_library },
{ EVHTTP_REQ_GET, "^/api/update$", jsonapi_reply_update },
{ EVHTTP_REQ_POST, "^/api/spotify-login$", jsonapi_reply_spotify_login },
{ EVHTTP_REQ_GET, "^/api/spotify$", jsonapi_reply_spotify },
{ EVHTTP_REQ_GET, "^/api/pairing$", jsonapi_reply_pairing_get },
{ EVHTTP_REQ_POST, "^/api/pairing$", jsonapi_reply_pairing_kickoff },
{ EVHTTP_REQ_POST, "^/api/lastfm-login$", jsonapi_reply_lastfm_login },
{ EVHTTP_REQ_GET, "^/api/lastfm-logout$", jsonapi_reply_lastfm_logout },
{ EVHTTP_REQ_GET, "^/api/lastfm$", jsonapi_reply_lastfm },
{ EVHTTP_REQ_POST, "^/api/verification$", jsonapi_reply_verification },
{ EVHTTP_REQ_GET, "^/api/outputs$", jsonapi_reply_outputs },
{ EVHTTP_REQ_PUT, "^/api/outputs/set$", jsonapi_reply_outputs_set },
{ EVHTTP_REQ_POST, "^/api/select-outputs$", jsonapi_reply_outputs_set }, // deprecated: use "/api/outputs/set"
{ EVHTTP_REQ_GET, "^/api/outputs/[[:digit:]]+$", jsonapi_reply_outputs_get_byid },
{ EVHTTP_REQ_PUT, "^/api/outputs/[[:digit:]]+$", jsonapi_reply_outputs_put_byid },
{ EVHTTP_REQ_PUT, "^/api/player/play$", jsonapi_reply_player_play },
{ EVHTTP_REQ_PUT, "^/api/player/pause$", jsonapi_reply_player_pause },
{ EVHTTP_REQ_PUT, "^/api/player/stop$", jsonapi_reply_player_stop },
{ EVHTTP_REQ_PUT, "^/api/player/next$", jsonapi_reply_player_next },
{ EVHTTP_REQ_PUT, "^/api/player/previous$", jsonapi_reply_player_previous },
{ EVHTTP_REQ_PUT, "^/api/player/shuffle$", jsonapi_reply_player_shuffle },
{ EVHTTP_REQ_PUT, "^/api/player/repeat$", jsonapi_reply_player_repeat },
{ EVHTTP_REQ_PUT, "^/api/player/consume$", jsonapi_reply_player_consume },
{ EVHTTP_REQ_PUT, "^/api/player/volume$", jsonapi_reply_player_volume },
{ EVHTTP_REQ_GET, "^/api/player$", jsonapi_reply_player },
{ EVHTTP_REQ_GET, "^/api/queue$", jsonapi_reply_queue },
{ 0, NULL, NULL }
};