From 4dcf6137081625d87ffdaedd0a3e9695cd15761f Mon Sep 17 00:00:00 2001 From: jcorporation Date: Sun, 17 Jun 2018 23:42:22 +0100 Subject: [PATCH] Output json with frozen --- CMakeLists.txt | 16 ++---- README.md | 17 +----- src/mpd_client.c | 141 +++++++++++++++++++++++------------------------ src/mpd_client.h | 1 + src/mympd.c | 4 +- 5 files changed, 79 insertions(+), 100 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b4a0985..1b38331 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,13 +7,13 @@ set(CPACK_PACKAGE_VERSION_MINOR "0") set(CPACK_PACKAGE_VERSION_PATCH "0") if(CMAKE_BUILD_TYPE MATCHES RELEASE) set(ASSETS_PATH "${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/htdocs") + set(DEBUG "OFF") else() set(ASSETS_PATH "${PROJECT_SOURCE_DIR}/htdocs") - set(DEBUG ON) + set(DEBUG "ON") endif() option(WITH_IPV6 "enable IPv6 support" ON) -option(WITH_SSL "enable SSL support" ON) find_package(LibMPDClient REQUIRED) find_package(Threads REQUIRED) @@ -23,17 +23,11 @@ include_directories(${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} ${LIBMPDCLIENT_I include(CheckCSourceCompiles) -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -pedantic") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -pedantic -D_FORTIFY_SOURCE=2 -fstack-protector -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=shift -fsanitize=integer-divide-by-zero -fsanitize=unreachable -fsanitize=vla-bound -fsanitize=null -fsanitize=return -fsanitize=signed-integer-overflow -fsanitize=bounds -fsanitize=bounds-strict -fsanitize=alignment -fsanitize=object-size -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=nonnull-attribute -fsanitize=returns-nonnull-attribute -fsanitize=bool -fsanitize=enum -fsanitize=vptr -static-libasan") -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -pedantic ") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -D_FORTIFY_SOURCE=2 -fstack-protector -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=shift -fsanitize=integer-divide-by-zero -fsanitize=unreachable -fsanitize=vla-bound -fsanitize=null -fsanitize=return -fsanitize=signed-integer-overflow -fsanitize=bounds -fsanitize=bounds-strict -fsanitize=alignment -fsanitize=object-size -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=nonnull-attribute -fsanitize=returns-nonnull-attribute -fsanitize=bool -fsanitize=enum -fsanitize=vptr -static-libasan") if(WITH_IPV6) set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS NS_ENABLE_IPV6) endif() -if(WITH_SSL) - find_package(OpenSSL REQUIRED) - include_directories(${OPENSSL_INCLUDE_DIR}) - set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS NS_ENABLE_SSL) -endif() file(GLOB RESOURCES RELATIVE ${PROJECT_SOURCE_DIR} @@ -54,7 +48,7 @@ set(SOURCES ) add_executable(mympd ${SOURCES}) -target_link_libraries(mympd ${LIBMPDCLIENT_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}) +target_link_libraries(mympd ${LIBMPDCLIENT_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS mympd DESTINATION bin) install(FILES mympd.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1) diff --git a/README.md b/README.md index 53df1db..1e43c5a 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,11 @@ Dependencies ------------ - libmpdclient 2: http://www.musicpd.org/libs/libmpdclient/ - cmake 2.6: http://cmake.org/ - - OpenSSL: https://www.openssl.org/ Unix Build Instructions ----------------------- -1. install dependencies. cmake, libmpdclient (dev), and OpenSSL (dev) are available from all major distributions. +1. install dependencies. cmake and libmpdclient (dev) are available from all major distributions. 2. create build directory ```cd /path/to/src; mkdir build; cd build``` 3. create makefile ```cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_BUILD_TYPE=RELEASE``` 4. build ```make``` @@ -56,20 +55,6 @@ Usage: ./mympd [OPTION]... --help this help ``` -SSL Support ------------ -To run myMPD with SSL support: - -- create a certificate (key and cert in the same file), example: -``` -# openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 1000 -nodes -sha256 -# cat key.pem cert.pem > ssl.pem -``` -- tell myMPD to use a webport using SSL and where to find the certificate: -``` -# ./mympd -w "ssl://8081:/path/to/ssl.pem" -``` - Copyright --------- ympd: 2013-2014 diff --git a/src/mpd_client.c b/src/mpd_client.c index d015922..5c1dd49 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -754,9 +754,10 @@ int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, unsi { struct mpd_status *status; const struct mpd_audio_format *audioformat; - struct mpd_output *out; - char *cur = buffer; - const char *end = buffer + MAX_SIZE; + struct mpd_output *output; + int len; + int nr; + struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); status = mpd_run_status(mpd.conn); if (!status) { @@ -767,79 +768,74 @@ int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, unsi if (status) { audioformat = mpd_status_get_audio_format(status); } - - cur += json_emit_raw_str(cur, end - cur, "{\"type\": \"state\", \"data\":{\"state\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_state(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"volume\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_volume(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"songpos\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_song_pos(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"elapsedTime\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_elapsed_time(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"totalTime\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_total_time(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"currentsongid\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_song_id(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"kbitrate\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_kbit_rate(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"audioformat\": {"); - cur += json_emit_raw_str(cur, end - cur, "\"sample_rate\":"); - cur += json_emit_int(cur, end - cur, audioformat ? audioformat->sample_rate : 0); - cur += json_emit_raw_str(cur, end - cur, ",\"bits\":"); - cur += json_emit_int(cur, end - cur, audioformat ? audioformat->bits : 0); - cur += json_emit_raw_str(cur, end - cur, ",\"channels\":"); - cur += json_emit_int(cur, end - cur, audioformat ? audioformat->channels : 0); - cur += json_emit_raw_str(cur, end - cur, "},\"queue_length\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_queue_length(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"nextsongpos\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_next_song_pos(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"nextsongid\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_next_song_id(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"queue_version\":"); - cur += json_emit_int(cur, end - cur, mpd_status_get_queue_version(status)); - cur += json_emit_raw_str(cur, end - cur, ",\"outputs\": {"); + + len = json_printf(&out,"{type:state, data:{" + "state:%d, volume:%d, songpos: %d, elapsedTime: %d, " + "totalTime:%d, currentsongid: %d, kbitrate: %d, " + "audioformat: { sample_rate: %d, bits: %d, channels: %d}, " + "queue_length: %d, nextsongpos: %d, nextsongid: %d, " + "queue_version: %d", + mpd_status_get_state(status), + mpd_status_get_volume(status), + mpd_status_get_song_pos(status), + mpd_status_get_elapsed_time(status), + mpd_status_get_total_time(status), + mpd_status_get_song_id(status), + mpd_status_get_kbit_rate(status), + audioformat ? audioformat->sample_rate : 0, + audioformat ? audioformat->bits : 0, + audioformat ? audioformat->channels : 0, + mpd_status_get_queue_length(status), + mpd_status_get_next_song_pos(status), + mpd_status_get_next_song_id(status), + mpd_status_get_queue_version(status) + ); + + len += json_printf(&out, ",outputs: {"); mpd_send_outputs(mpd.conn); - while ((out = mpd_recv_output(mpd.conn)) != NULL) { - cur += json_emit_raw_str(cur, end - cur, "\""); - cur += json_emit_int(cur, end - cur, mpd_output_get_id(out)); - cur += json_emit_raw_str(cur, end - cur, "\":"); - cur += json_emit_int(cur, end - cur, mpd_output_get_enabled(out)); - cur += json_emit_raw_str(cur, end - cur, ","); - mpd_output_free(out); + nr=0; + while ((output = mpd_recv_output(mpd.conn)) != NULL) { + if (nr++) len += json_printf(&out, ","); + len += json_printf(&out, "\"%d\":%d", + mpd_output_get_id(output), + mpd_output_get_enabled(output) + ); + mpd_output_free(output); } if (!mpd_response_finish(mpd.conn)) { fprintf(stderr, "MPD outputs: %s\n", mpd_connection_get_error_message(mpd.conn)); mpd_connection_clear_error(mpd.conn); } - cur --; - cur += json_emit_raw_str(cur, end - cur, "}}}"); + len += json_printf(&out, "}}}"); *current_song_id = mpd_status_get_song_id(status); *next_song_id = mpd_status_get_next_song_id(status); *queue_version = mpd_status_get_queue_version(status); mpd_status_free(status); - return cur - buffer; + + if (len > MAX_SIZE) fprintf(stderr,"Buffer truncated\n"); + return len; } int mympd_put_welcome(char *buffer) { int len; - len = snprintf(buffer, MAX_SIZE, - "{\"type\":\"welcome\", \"data\":{" - "\"version\":\"%s\"}}", - MYMPD_VERSION - ); + struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); + len = json_printf(&out, "{type: %Q, data: { version: %Q}}", "welcome", MYMPD_VERSION); + + if (len > MAX_SIZE) fprintf(stderr,"Buffer truncated\n"); return len; } int mympd_put_settings(char *buffer) { struct mpd_status *status; - int len; char *replaygain; + int len; + struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); status = mpd_run_status(mpd.conn); if (!status) { @@ -855,11 +851,11 @@ int mympd_put_settings(char *buffer) mpd_return_pair(mpd.conn, pair); } - len = snprintf(buffer, MAX_SIZE, - "{\"type\":\"settings\", \"data\":{" - "\"repeat\":%d, \"single\":%d, \"crossfade\":%d, \"consume\":%d, \"random\":%d, " - "\"mixrampdb\": %f, \"mixrampdelay\": %f, \"mpdhost\" : \"%s\", \"mpdport\": \"%d\", \"passwort_set\": %s, " - "\"streamport\": \"%d\",\"coverimage\": \"%s\", \"max_elements_per_page\": %d, \"replaygain\": \"%s\"" + len = json_printf(&out, + "{type:settings, data:{" + "repeat:%d, single:%d, crossfade:%d, consume:%d, random:%d, " + "mixrampdb: %f, mixrampdelay: %f, mpdhost : %Q, mpdport: %d, passwort_set: %B, " + "streamport: %d, coverimage: %Q, max_elements_per_page: %d, replaygain: %Q" "}}", mpd_status_get_repeat(status), mpd_status_get_single(status), @@ -875,37 +871,40 @@ int mympd_put_settings(char *buffer) replaygain ); mpd_status_free(status); + + if (len > MAX_SIZE) fprintf(stderr,"Buffer truncated\n"); return len; } int mympd_put_outputnames(char *buffer) { - char *cur = buffer; - const char *end = buffer + MAX_SIZE; - struct mpd_output *out; + struct mpd_output *output; + int len; + int nr; + struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); + + len = json_printf(&out,"{type: outputnames, data:{"); - cur += json_emit_raw_str(cur, end - cur, "{\"type\": \"outputnames\", \"data\":{"); - mpd_send_outputs(mpd.conn); - - while ((out = mpd_recv_output(mpd.conn)) != NULL) { - cur += json_emit_raw_str(cur, end - cur, "\""); - cur += json_emit_int(cur, end - cur, mpd_output_get_id(out)); - cur += json_emit_raw_str(cur, end - cur, "\":"); - cur += json_emit_quoted_str(cur, end - cur, mpd_output_get_name(out)); - cur += json_emit_raw_str(cur, end - cur, ","); - mpd_output_free(out); + nr=0; + while ((output = mpd_recv_output(mpd.conn)) != NULL) { + if (nr++) len += json_printf(&out, ","); + len += json_printf(&out,"\"%d\":%Q", + mpd_output_get_id(output), + mpd_output_get_name(output) + ); + mpd_output_free(output); } if (!mpd_response_finish(mpd.conn)) { fprintf(stderr, "MPD outputs: %s\n", mpd_connection_get_error_message(mpd.conn)); mpd_connection_clear_error(mpd.conn); } - cur --; - cur += json_emit_raw_str(cur, end - cur, "}}"); + len += json_printf(&out,"}}"); - return cur - buffer; + if (len > MAX_SIZE) fprintf(stderr,"Buffer truncated\n"); + return len; } int mympd_put_current_song(char *buffer) diff --git a/src/mpd_client.h b/src/mpd_client.h index de1db40..bd2694d 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -132,6 +132,7 @@ struct t_mpd_client_session { }; void mympd_poll(struct mg_mgr *s); +void callback_mympd_jsonrpc(struct mg_connection *nc, const struct mg_str msg); void callback_mympd(struct mg_connection *nc, const struct mg_str msg); int mympd_close_handler(struct mg_connection *c); int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, unsigned *queue_version); diff --git a/src/mympd.c b/src/mympd.c index 72deb5b..27fb3ee 100644 --- a/src/mympd.c +++ b/src/mympd.c @@ -142,7 +142,7 @@ int main(int argc, char **argv) {0, 0, 0, 0 } }; - while((n = getopt_long(argc, argv, "D:h:p:w:u:vm:s:i:", + while((n = getopt_long(argc, argv, "D:h:p:w:u:vm:s:i:c:", long_options, &option_index)) != -1) { switch (n) { case 'D': @@ -203,7 +203,7 @@ int main(int argc, char **argv) nc = mg_bind(&mgr, webport, ev_handler); if (nc == NULL) { - printf("myMPD can't bind to port %s\n", webport); + fprintf(stderr, "Error starting server on port %s\n", webport); return EXIT_FAILURE; }