mirror of
https://github.com/SuperBFG7/ympd
synced 2024-09-28 06:18:13 +00:00
Feat: mympd_api handler for non mpd api requests
This commit is contained in:
parent
dffe9b17d7
commit
a7d07fbcc9
@ -42,6 +42,7 @@ set(SOURCES
|
|||||||
src/global.c
|
src/global.c
|
||||||
src/mpd_client.c
|
src/mpd_client.c
|
||||||
src/web_server.c
|
src/web_server.c
|
||||||
|
src/mympd_api.c
|
||||||
src/list.c
|
src/list.c
|
||||||
src/tiny_queue.c
|
src/tiny_queue.c
|
||||||
dist/src/mongoose/mongoose.c
|
dist/src/mongoose/mongoose.c
|
||||||
|
@ -2232,7 +2232,7 @@ function parseSongDetails(obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function execSyscmd(cmd) {
|
function execSyscmd(cmd) {
|
||||||
sendAPI({"cmd": "MPD_API_SYSCMD", "data": {"cmd": cmd}});
|
sendAPI({"cmd": "MYMPD_API_SYSCMD", "data": {"cmd": cmd}});
|
||||||
}
|
}
|
||||||
|
|
||||||
function playlistDetails(uri) {
|
function playlistDetails(uri) {
|
||||||
|
26
src/global.c
26
src/global.c
@ -25,6 +25,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "tiny_queue.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
int randrange(int n) {
|
int randrange(int n) {
|
||||||
@ -41,6 +45,18 @@ void sanitize_string(const char *data) {
|
|||||||
*cp = '_';
|
*cp = '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool validate_string(const char *data) {
|
||||||
|
static char ok_chars[] = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
"1234567890_-. ";
|
||||||
|
const char *cp = data;
|
||||||
|
const char *end = data + strlen(data);
|
||||||
|
for (cp += strspn(cp, ok_chars); cp != end; cp += strspn(cp, ok_chars))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int copy_string(char * const dest, char const * const src, size_t const dst_len, size_t const src_len) {
|
int copy_string(char * const dest, char const * const src, size_t const dst_len, size_t const src_len) {
|
||||||
if (dst_len == 0 || src_len == 0)
|
if (dst_len == 0 || src_len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -49,3 +65,13 @@ int copy_string(char * const dest, char const * const src, size_t const dst_len,
|
|||||||
dest[max] = '\0';
|
dest[max] = '\0';
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum mypd_cmd_ids get_cmd_id(const char *cmd) {
|
||||||
|
const char * mympd_cmd_strs[] = { MYMPD_CMDS(GEN_STR) };
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < sizeof(mympd_cmd_strs) / sizeof(mympd_cmd_strs[0]); i++)
|
||||||
|
if (!strncmp(cmd, mympd_cmd_strs[i], strlen(mympd_cmd_strs[i])))
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
#ifndef __GLOBAL_H__
|
#ifndef __GLOBAL_H__
|
||||||
#define __GLOBAL_H__
|
#define __GLOBAL_H__
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
//architecture
|
//architecture
|
||||||
@ -62,6 +60,91 @@
|
|||||||
return len; \
|
return len; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
//API cmds
|
||||||
|
#define MYMPD_CMDS(X) \
|
||||||
|
X(MPD_API_UNKNOWN) \
|
||||||
|
X(MPD_API_QUEUE_CLEAR) \
|
||||||
|
X(MPD_API_QUEUE_CROP) \
|
||||||
|
X(MPD_API_QUEUE_SAVE) \
|
||||||
|
X(MPD_API_QUEUE_LIST) \
|
||||||
|
X(MPD_API_QUEUE_SEARCH) \
|
||||||
|
X(MPD_API_QUEUE_RM_TRACK) \
|
||||||
|
X(MPD_API_QUEUE_RM_RANGE) \
|
||||||
|
X(MPD_API_QUEUE_MOVE_TRACK) \
|
||||||
|
X(MPD_API_QUEUE_ADD_TRACK_AFTER) \
|
||||||
|
X(MPD_API_QUEUE_ADD_TRACK) \
|
||||||
|
X(MPD_API_QUEUE_ADD_PLAY_TRACK) \
|
||||||
|
X(MPD_API_QUEUE_REPLACE_TRACK) \
|
||||||
|
X(MPD_API_QUEUE_ADD_PLAYLIST) \
|
||||||
|
X(MPD_API_QUEUE_REPLACE_PLAYLIST) \
|
||||||
|
X(MPD_API_QUEUE_SHUFFLE) \
|
||||||
|
X(MPD_API_QUEUE_LAST_PLAYED) \
|
||||||
|
X(MPD_API_PLAYLIST_CLEAR) \
|
||||||
|
X(MPD_API_PLAYLIST_RENAME) \
|
||||||
|
X(MPD_API_PLAYLIST_MOVE_TRACK) \
|
||||||
|
X(MPD_API_PLAYLIST_ADD_TRACK) \
|
||||||
|
X(MPD_API_PLAYLIST_RM_TRACK) \
|
||||||
|
X(MPD_API_PLAYLIST_RM) \
|
||||||
|
X(MPD_API_PLAYLIST_LIST) \
|
||||||
|
X(MPD_API_PLAYLIST_CONTENT_LIST) \
|
||||||
|
X(MPD_API_SMARTPLS_UPDATE_ALL) \
|
||||||
|
X(MPD_API_SMARTPLS_SAVE) \
|
||||||
|
X(MPD_API_SMARTPLS_GET) \
|
||||||
|
X(MPD_API_DATABASE_SEARCH_ADV) \
|
||||||
|
X(MPD_API_DATABASE_SEARCH) \
|
||||||
|
X(MPD_API_DATABASE_UPDATE) \
|
||||||
|
X(MPD_API_DATABASE_RESCAN) \
|
||||||
|
X(MPD_API_DATABASE_FILESYSTEM_LIST) \
|
||||||
|
X(MPD_API_DATABASE_TAG_LIST) \
|
||||||
|
X(MPD_API_DATABASE_TAG_ALBUM_LIST) \
|
||||||
|
X(MPD_API_DATABASE_TAG_ALBUM_TITLE_LIST) \
|
||||||
|
X(MPD_API_DATABASE_STATS) \
|
||||||
|
X(MPD_API_DATABASE_SONGDETAILS) \
|
||||||
|
X(MPD_API_PLAYER_PLAY_TRACK) \
|
||||||
|
X(MPD_API_PLAYER_VOLUME_SET) \
|
||||||
|
X(MPD_API_PLAYER_VOLUME_GET) \
|
||||||
|
X(MPD_API_PLAYER_PAUSE) \
|
||||||
|
X(MPD_API_PLAYER_PLAY) \
|
||||||
|
X(MPD_API_PLAYER_STOP) \
|
||||||
|
X(MPD_API_PLAYER_SEEK) \
|
||||||
|
X(MPD_API_PLAYER_NEXT) \
|
||||||
|
X(MPD_API_PLAYER_PREV) \
|
||||||
|
X(MPD_API_PLAYER_OUTPUT_LIST) \
|
||||||
|
X(MPD_API_PLAYER_TOGGLE_OUTPUT) \
|
||||||
|
X(MPD_API_PLAYER_CURRENT_SONG) \
|
||||||
|
X(MPD_API_PLAYER_STATE) \
|
||||||
|
X(MPD_API_SETTINGS_GET) \
|
||||||
|
X(MPD_API_SETTINGS_SET) \
|
||||||
|
X(MPD_API_LIKE) \
|
||||||
|
X(MPD_API_COLS_SAVE) \
|
||||||
|
X(MYMPD_API_SYSCMD)
|
||||||
|
|
||||||
|
#define GEN_ENUM(X) X,
|
||||||
|
#define GEN_STR(X) #X,
|
||||||
|
|
||||||
|
enum mypd_cmd_ids {
|
||||||
|
MYMPD_CMDS(GEN_ENUM)
|
||||||
|
};
|
||||||
|
|
||||||
|
//message queue
|
||||||
|
tiny_queue_t *web_server_queue;
|
||||||
|
tiny_queue_t *mpd_client_queue;
|
||||||
|
tiny_queue_t *mympd_api_queue;
|
||||||
|
|
||||||
|
struct work_request_t {
|
||||||
|
long conn_id; // needed to identify the connection where to send the reply
|
||||||
|
char data[1000];
|
||||||
|
int length;
|
||||||
|
enum mypd_cmd_ids cmd_id;
|
||||||
|
} work_request_t;
|
||||||
|
|
||||||
|
struct work_result_t {
|
||||||
|
long conn_id; // needed to identify the connection where to send the reply
|
||||||
|
char data[MAX_SIZE];
|
||||||
|
int length;
|
||||||
|
} work_result_t;
|
||||||
|
|
||||||
|
|
||||||
//signal handler
|
//signal handler
|
||||||
sig_atomic_t s_signal_received;
|
sig_atomic_t s_signal_received;
|
||||||
|
|
||||||
@ -94,6 +177,7 @@ typedef struct {
|
|||||||
const char *streamurl;
|
const char *streamurl;
|
||||||
unsigned long last_played_count;
|
unsigned long last_played_count;
|
||||||
long loglevel;
|
long loglevel;
|
||||||
|
void *syscmd_list;
|
||||||
} t_config;
|
} t_config;
|
||||||
|
|
||||||
t_config config;
|
t_config config;
|
||||||
@ -101,5 +185,7 @@ t_config config;
|
|||||||
//global functions
|
//global functions
|
||||||
int randrange(int n);
|
int randrange(int n);
|
||||||
void sanitize_string(const char *data);
|
void sanitize_string(const char *data);
|
||||||
|
bool validate_string(const char *data);
|
||||||
int copy_string(char * const dest, char const * const src, size_t const dst_len, size_t const src_len);
|
int copy_string(char * const dest, char const * const src, size_t const dst_len, size_t const src_len);
|
||||||
|
enum mypd_cmd_ids get_cmd_id(const char *cmd);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* myMPD
|
/* myMPD
|
||||||
(c) 2018 Juergen Mang <mail@jcgames.de>
|
(c) 2018-2019 Juergen Mang <mail@jcgames.de>
|
||||||
This project's homepage is: https://github.com/jcorporation/mympd
|
This project's homepage is: https://github.com/jcorporation/mympd
|
||||||
|
|
||||||
This linked list implementation is based on: https://github.com/joshkunz/ashuffle
|
This linked list implementation is based on: https://github.com/joshkunz/ashuffle
|
||||||
@ -27,13 +27,11 @@ struct node {
|
|||||||
struct node *next;
|
struct node *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct list {
|
struct list {
|
||||||
unsigned length;
|
unsigned length;
|
||||||
struct node *list;
|
struct node *list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int list_init(struct list *l);
|
int list_init(struct list *l);
|
||||||
int list_push(struct list *l, const char *data, int value);
|
int list_push(struct list *l, const char *data, int value);
|
||||||
int list_insert(struct list *l, const char *data, int value);
|
int list_insert(struct list *l, const char *data, int value);
|
||||||
|
38
src/main.c
38
src/main.c
@ -33,11 +33,15 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <mpd/client.h>
|
#include <mpd/client.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "../dist/src/inih/ini.h"
|
#include "list.h"
|
||||||
|
#include "tiny_queue.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "mpd_client.h"
|
#include "mpd_client.h"
|
||||||
#include "web_server.h"
|
#include "web_server.h"
|
||||||
|
#include "mympd_api.h"
|
||||||
|
#include "../dist/src/inih/ini.h"
|
||||||
#include "../dist/src/mongoose/mongoose.h"
|
#include "../dist/src/mongoose/mongoose.h"
|
||||||
|
|
||||||
static void signal_handler(int sig_num) {
|
static void signal_handler(int sig_num) {
|
||||||
@ -137,28 +141,31 @@ static int inihandler(void* user, const char* section, const char* name, const c
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_syscmds() {
|
void read_syscmds(void *arg_config) {
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
char dirname[400];
|
char dirname[400];
|
||||||
char *cmd;
|
char *cmd;
|
||||||
long order;
|
long order;
|
||||||
if (config.syscmds == true) {
|
t_config *config = (t_config *) arg_config;
|
||||||
snprintf(dirname, 400, "%s/syscmds", config.etcdir);
|
|
||||||
LOG_INFO() printf("Reading syscmds: %s\n", dirname);
|
if (config->syscmds == true) {
|
||||||
|
snprintf(dirname, 400, "%s/syscmds", config->etcdir);
|
||||||
|
LOG_INFO2() printf("Reading syscmds: %s\n", dirname);
|
||||||
if ((dir = opendir (dirname)) != NULL) {
|
if ((dir = opendir (dirname)) != NULL) {
|
||||||
while ((ent = readdir(dir)) != NULL) {
|
while ((ent = readdir(dir)) != NULL) {
|
||||||
if (strncmp(ent->d_name, ".", 1) == 0)
|
if (strncmp(ent->d_name, ".", 1) == 0)
|
||||||
continue;
|
continue;
|
||||||
order = strtol(ent->d_name, &cmd, 10);
|
order = strtol(ent->d_name, &cmd, 10);
|
||||||
if (strcmp(cmd, "") != 0)
|
if (strcmp(cmd, "") != 0)
|
||||||
list_push(&syscmds, strdup(cmd), order);
|
list_push(config->syscmd_list, strdup(cmd), order);
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
LOG_INFO() printf("Syscmds are disabled\n");
|
LOG_INFO2() printf("Syscmds are disabled\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_statefiles() {
|
void read_statefiles() {
|
||||||
@ -310,6 +317,7 @@ int main(int argc, char **argv) {
|
|||||||
s_signal_received = 0;
|
s_signal_received = 0;
|
||||||
char testdirname[400];
|
char testdirname[400];
|
||||||
mpd_client_queue = tiny_queue_create();
|
mpd_client_queue = tiny_queue_create();
|
||||||
|
mympd_api_queue = tiny_queue_create();
|
||||||
web_server_queue = tiny_queue_create();
|
web_server_queue = tiny_queue_create();
|
||||||
|
|
||||||
srand((unsigned int)time(NULL));
|
srand((unsigned int)time(NULL));
|
||||||
@ -387,6 +395,7 @@ int main(int argc, char **argv) {
|
|||||||
if (!web_server_init(&mgr, &config)) {
|
if (!web_server_init(&mgr, &config)) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//drop privileges
|
//drop privileges
|
||||||
if (config.user != NULL) {
|
if (config.user != NULL) {
|
||||||
LOG_INFO() printf("Droping privileges to %s\n", config.user);
|
LOG_INFO() printf("Droping privileges to %s\n", config.user);
|
||||||
@ -446,9 +455,10 @@ int main(int argc, char **argv) {
|
|||||||
read_statefiles();
|
read_statefiles();
|
||||||
|
|
||||||
//read system command files
|
//read system command files
|
||||||
list_init(&syscmds);
|
config.syscmd_list = malloc(sizeof(struct list));
|
||||||
read_syscmds();
|
list_init(config.syscmd_list);
|
||||||
list_sort_by_value(&syscmds, true);
|
read_syscmds(&config);
|
||||||
|
list_sort_by_value(config.syscmd_list, true);
|
||||||
|
|
||||||
//init lists for tag handling
|
//init lists for tag handling
|
||||||
list_init(&mpd_tags);
|
list_init(&mpd_tags);
|
||||||
@ -459,11 +469,13 @@ int main(int argc, char **argv) {
|
|||||||
LOG_INFO() printf("Reading last played songs: %d\n", read_last_played());
|
LOG_INFO() printf("Reading last played songs: %d\n", read_last_played());
|
||||||
|
|
||||||
//Create working threads
|
//Create working threads
|
||||||
pthread_t mpd_client_thread, web_server_thread;
|
pthread_t mpd_client_thread, web_server_thread, mympd_api_thread;
|
||||||
//mpd connection
|
//mpd connection
|
||||||
pthread_create(&mpd_client_thread, NULL, mpd_client_loop, NULL);
|
pthread_create(&mpd_client_thread, NULL, mpd_client_loop, NULL);
|
||||||
//webserver
|
//webserver
|
||||||
pthread_create(&web_server_thread, NULL, web_server_loop, &mgr);
|
pthread_create(&web_server_thread, NULL, web_server_loop, &mgr);
|
||||||
|
//mympd api
|
||||||
|
pthread_create(&mympd_api_thread, NULL, mympd_api_loop, &config);
|
||||||
|
|
||||||
//Do nothing...
|
//Do nothing...
|
||||||
|
|
||||||
@ -473,7 +485,9 @@ int main(int argc, char **argv) {
|
|||||||
pthread_join(web_server_thread, NULL);
|
pthread_join(web_server_thread, NULL);
|
||||||
list_free(&mpd_tags);
|
list_free(&mpd_tags);
|
||||||
list_free(&mympd_tags);
|
list_free(&mympd_tags);
|
||||||
|
list_free(config.syscmd_list);
|
||||||
tiny_queue_free(web_server_queue);
|
tiny_queue_free(web_server_queue);
|
||||||
tiny_queue_free(mpd_client_queue);
|
tiny_queue_free(mpd_client_queue);
|
||||||
|
tiny_queue_free(mympd_api_queue);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
429
src/mpd_client.c
429
src/mpd_client.c
File diff suppressed because it is too large
Load Diff
@ -25,11 +25,6 @@
|
|||||||
#ifndef __MPD_CLIENT_H__
|
#ifndef __MPD_CLIENT_H__
|
||||||
#define __MPD_CLIENT_H__
|
#define __MPD_CLIENT_H__
|
||||||
|
|
||||||
#include "global.h"
|
|
||||||
#include "web_server.h"
|
|
||||||
#include "list.h"
|
|
||||||
#include "tiny_queue.h"
|
|
||||||
|
|
||||||
#define RETURN_ERROR_AND_RECOVER(X) do { \
|
#define RETURN_ERROR_AND_RECOVER(X) do { \
|
||||||
printf("MPD %s: %s\n", X, mpd_connection_get_error_message(mpd.conn)); \
|
printf("MPD %s: %s\n", X, mpd_connection_get_error_message(mpd.conn)); \
|
||||||
len = json_printf(&out, "{type: error, data: %Q}", mpd_connection_get_error_message(mpd.conn)); \
|
len = json_printf(&out, "{type: error, data: %Q}", mpd_connection_get_error_message(mpd.conn)); \
|
||||||
@ -61,71 +56,6 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
#define MPD_CMDS(X) \
|
|
||||||
X(MPD_API_UNKNOWN) \
|
|
||||||
X(MPD_API_QUEUE_CLEAR) \
|
|
||||||
X(MPD_API_QUEUE_CROP) \
|
|
||||||
X(MPD_API_QUEUE_SAVE) \
|
|
||||||
X(MPD_API_QUEUE_LIST) \
|
|
||||||
X(MPD_API_QUEUE_SEARCH) \
|
|
||||||
X(MPD_API_QUEUE_RM_TRACK) \
|
|
||||||
X(MPD_API_QUEUE_RM_RANGE) \
|
|
||||||
X(MPD_API_QUEUE_MOVE_TRACK) \
|
|
||||||
X(MPD_API_QUEUE_ADD_TRACK_AFTER) \
|
|
||||||
X(MPD_API_QUEUE_ADD_TRACK) \
|
|
||||||
X(MPD_API_QUEUE_ADD_PLAY_TRACK) \
|
|
||||||
X(MPD_API_QUEUE_REPLACE_TRACK) \
|
|
||||||
X(MPD_API_QUEUE_ADD_PLAYLIST) \
|
|
||||||
X(MPD_API_QUEUE_REPLACE_PLAYLIST) \
|
|
||||||
X(MPD_API_QUEUE_SHUFFLE) \
|
|
||||||
X(MPD_API_QUEUE_LAST_PLAYED) \
|
|
||||||
X(MPD_API_PLAYLIST_CLEAR) \
|
|
||||||
X(MPD_API_PLAYLIST_RENAME) \
|
|
||||||
X(MPD_API_PLAYLIST_MOVE_TRACK) \
|
|
||||||
X(MPD_API_PLAYLIST_ADD_TRACK) \
|
|
||||||
X(MPD_API_PLAYLIST_RM_TRACK) \
|
|
||||||
X(MPD_API_PLAYLIST_RM) \
|
|
||||||
X(MPD_API_PLAYLIST_LIST) \
|
|
||||||
X(MPD_API_PLAYLIST_CONTENT_LIST) \
|
|
||||||
X(MPD_API_SMARTPLS_UPDATE_ALL) \
|
|
||||||
X(MPD_API_SMARTPLS_SAVE) \
|
|
||||||
X(MPD_API_SMARTPLS_GET) \
|
|
||||||
X(MPD_API_DATABASE_SEARCH_ADV) \
|
|
||||||
X(MPD_API_DATABASE_SEARCH) \
|
|
||||||
X(MPD_API_DATABASE_UPDATE) \
|
|
||||||
X(MPD_API_DATABASE_RESCAN) \
|
|
||||||
X(MPD_API_DATABASE_FILESYSTEM_LIST) \
|
|
||||||
X(MPD_API_DATABASE_TAG_LIST) \
|
|
||||||
X(MPD_API_DATABASE_TAG_ALBUM_LIST) \
|
|
||||||
X(MPD_API_DATABASE_TAG_ALBUM_TITLE_LIST) \
|
|
||||||
X(MPD_API_DATABASE_STATS) \
|
|
||||||
X(MPD_API_DATABASE_SONGDETAILS) \
|
|
||||||
X(MPD_API_PLAYER_PLAY_TRACK) \
|
|
||||||
X(MPD_API_PLAYER_VOLUME_SET) \
|
|
||||||
X(MPD_API_PLAYER_VOLUME_GET) \
|
|
||||||
X(MPD_API_PLAYER_PAUSE) \
|
|
||||||
X(MPD_API_PLAYER_PLAY) \
|
|
||||||
X(MPD_API_PLAYER_STOP) \
|
|
||||||
X(MPD_API_PLAYER_SEEK) \
|
|
||||||
X(MPD_API_PLAYER_NEXT) \
|
|
||||||
X(MPD_API_PLAYER_PREV) \
|
|
||||||
X(MPD_API_PLAYER_OUTPUT_LIST) \
|
|
||||||
X(MPD_API_PLAYER_TOGGLE_OUTPUT) \
|
|
||||||
X(MPD_API_PLAYER_CURRENT_SONG) \
|
|
||||||
X(MPD_API_PLAYER_STATE) \
|
|
||||||
X(MPD_API_SETTINGS_GET) \
|
|
||||||
X(MPD_API_SETTINGS_SET) \
|
|
||||||
X(MPD_API_LIKE) \
|
|
||||||
X(MPD_API_COLS_SAVE) \
|
|
||||||
X(MPD_API_SYSCMD)
|
|
||||||
|
|
||||||
#define GEN_ENUM(X) X,
|
|
||||||
#define GEN_STR(X) #X,
|
|
||||||
|
|
||||||
enum mpd_cmd_ids {
|
|
||||||
MPD_CMDS(GEN_ENUM)
|
|
||||||
};
|
|
||||||
|
|
||||||
enum mpd_conn_states {
|
enum mpd_conn_states {
|
||||||
MPD_DISCONNECTED,
|
MPD_DISCONNECTED,
|
||||||
MPD_FAILURE,
|
MPD_FAILURE,
|
||||||
@ -167,7 +97,6 @@ struct list mympd_tags;
|
|||||||
struct list mympd_searchtags;
|
struct list mympd_searchtags;
|
||||||
struct list mympd_browsetags;
|
struct list mympd_browsetags;
|
||||||
struct list last_played;
|
struct list last_played;
|
||||||
struct list syscmds;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
long playCount;
|
long playCount;
|
||||||
@ -192,11 +121,10 @@ typedef struct {
|
|||||||
} t_mympd_state;
|
} t_mympd_state;
|
||||||
|
|
||||||
t_mympd_state mympd_state;
|
t_mympd_state mympd_state;
|
||||||
tiny_queue_t *mpd_client_queue;
|
|
||||||
|
|
||||||
void mpd_client_idle(int timeout);
|
void mpd_client_idle(int timeout);
|
||||||
void mpd_client_parse_idle(int idle_bitmask);
|
void mpd_client_parse_idle(int idle_bitmask);
|
||||||
void mpd_client_api(struct work_request_t *request);
|
void mpd_client_api(void *arg_request);
|
||||||
void mpd_client_notify(size_t n);
|
void mpd_client_notify(size_t n);
|
||||||
bool mpd_client_count_song_id(int song_id, char *name, int value);
|
bool mpd_client_count_song_id(int song_id, char *name, int value);
|
||||||
bool mpd_client_count_song_uri(const char *uri, char *name, int value);
|
bool mpd_client_count_song_uri(const char *uri, char *name, int value);
|
||||||
@ -208,7 +136,6 @@ bool mpd_client_last_played_list(int song_id);
|
|||||||
bool mpd_client_jukebox();
|
bool mpd_client_jukebox();
|
||||||
bool mpd_client_state_get(char *name, char *value);
|
bool mpd_client_state_get(char *name, char *value);
|
||||||
bool mpd_client_state_set(const char *name, const char *value);
|
bool mpd_client_state_set(const char *name, const char *value);
|
||||||
int mpd_client_syscmd(char *buffer, char *cmd, int order);
|
|
||||||
int mpd_client_smartpls_save(char *smartpltype, char *playlist, char *tag, char *searchstr, int maxentries, int timerange);
|
int mpd_client_smartpls_save(char *smartpltype, char *playlist, char *tag, char *searchstr, int maxentries, int timerange);
|
||||||
int mpd_client_smartpls_put(char *buffer, char *playlist);
|
int mpd_client_smartpls_put(char *buffer, char *playlist);
|
||||||
int mpd_client_smartpls_update_all();
|
int mpd_client_smartpls_update_all();
|
||||||
@ -228,7 +155,7 @@ int mpd_client_search_queue(char *buffer, char *mpdtagtype, unsigned int offset,
|
|||||||
int mpd_client_put_welcome(char *buffer);
|
int mpd_client_put_welcome(char *buffer);
|
||||||
int mpd_client_put_volume(char *buffer);
|
int mpd_client_put_volume(char *buffer);
|
||||||
int mpd_client_put_stats(char *buffer);
|
int mpd_client_put_stats(char *buffer);
|
||||||
int mpd_client_put_settings(char *buffer);
|
int mpd_client_put_settings(char *buffer, void *arg_config);
|
||||||
int mpd_client_put_db_tag(char *buffer, unsigned int offset, char *mpdtagtype, char *mpdsearchtagtype, char *searchstr, char *filter);
|
int mpd_client_put_db_tag(char *buffer, unsigned int offset, char *mpdtagtype, char *mpdsearchtagtype, char *searchstr, char *filter);
|
||||||
int mpd_client_put_songs_in_album(char *buffer, char *album, char *search, char *tag);
|
int mpd_client_put_songs_in_album(char *buffer, char *album, char *search, char *tag);
|
||||||
int mpd_client_put_playlists(char *buffer, unsigned int offset, char *filter);
|
int mpd_client_put_playlists(char *buffer, unsigned int offset, char *filter);
|
||||||
|
135
src/mympd_api.c
Normal file
135
src/mympd_api.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/* myMPD
|
||||||
|
(c) 2018-2019 Juergen Mang <mail@jcgames.de>
|
||||||
|
This project's homepage is: https://github.com/jcorporation/mympd
|
||||||
|
|
||||||
|
myMPD ist fork of:
|
||||||
|
|
||||||
|
ympd
|
||||||
|
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
|
||||||
|
This project's homepage is: http://www.ympd.org
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 of the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
#include "tiny_queue.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include "mympd_api.h"
|
||||||
|
#include "../dist/src/frozen/frozen.h"
|
||||||
|
|
||||||
|
//private definitions
|
||||||
|
static void mympd_api(void *arg_request, void *arg_config);
|
||||||
|
static int mympd_api_syscmd(char *buffer, const char *cmd, void *arg_config);
|
||||||
|
|
||||||
|
//public functions
|
||||||
|
void *mympd_api_loop(void *arg_config) {
|
||||||
|
while (s_signal_received == 0) {
|
||||||
|
struct work_request_t *req = tiny_queue_shift(mympd_api_queue);
|
||||||
|
mympd_api(req, arg_config);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//private functions
|
||||||
|
static void mympd_api(void *arg_request, void *arg_config) {
|
||||||
|
struct work_request_t *request = (struct work_request_t*) arg_request;
|
||||||
|
size_t len = 0;
|
||||||
|
char buffer[MAX_SIZE];
|
||||||
|
int je;
|
||||||
|
char *p_charbuf1;
|
||||||
|
LOG_VERBOSE() printf("MYMPD API request: %.*s\n", request->length, request->data);
|
||||||
|
|
||||||
|
if (request->cmd_id == MYMPD_API_SYSCMD) {
|
||||||
|
if (config.syscmds == true) {
|
||||||
|
je = json_scanf(request->data, request->length, "{data: {cmd: %Q}}", &p_charbuf1);
|
||||||
|
if (je == 1) {
|
||||||
|
len = mympd_api_syscmd(buffer, p_charbuf1, arg_config);
|
||||||
|
free(p_charbuf1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"System commands are disabled.\"}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Unknown cmd_id %u.\"}", request->cmd_id);
|
||||||
|
printf("ERROR: Unknown cmd_id %u\n", request->cmd_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"No response for cmd_id %u.\"}", request->cmd_id);
|
||||||
|
printf("ERROR: No response for cmd_id %u\n", request->cmd_id);
|
||||||
|
}
|
||||||
|
LOG_DEBUG() fprintf(stderr, "DEBUG: Send http response to connection %lu (first 800 chars):\n%*.*s\n", request->conn_id, 0, 800, buffer);
|
||||||
|
|
||||||
|
struct work_result_t *response = (struct work_result_t*)malloc(sizeof(struct work_result_t));
|
||||||
|
response->conn_id = request->conn_id;
|
||||||
|
response->length = copy_string(response->data, buffer, MAX_SIZE, len);
|
||||||
|
tiny_queue_push(web_server_queue, response);
|
||||||
|
|
||||||
|
free(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mympd_api_syscmd(char *buffer, const char *cmd, void *arg_config) {
|
||||||
|
int len;
|
||||||
|
char filename[400];
|
||||||
|
char *line;
|
||||||
|
char *crap;
|
||||||
|
size_t n = 0;
|
||||||
|
ssize_t read;
|
||||||
|
t_config *config = (t_config *) arg_config;
|
||||||
|
|
||||||
|
const int order = list_get_value(config->syscmd_list, cmd);
|
||||||
|
if (order == -1) {
|
||||||
|
printf("ERROR: Syscmd not defined: %s\n", cmd);
|
||||||
|
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"System command not defined\"}");
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(filename, 400, "%s/syscmds/%d%s", config->etcdir, order, cmd);
|
||||||
|
FILE *fp = fopen(filename, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't execute cmd %s.\"}", cmd);
|
||||||
|
printf("ERROR: Can't execute syscmd \"%s\"\n", cmd);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
read = getline(&line, &n, fp);
|
||||||
|
fclose(fp);
|
||||||
|
if (read > 0) {
|
||||||
|
strtok_r(line, "\n", &crap);
|
||||||
|
if (system(line) == 0) {
|
||||||
|
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Executed cmd %s.\"}", cmd);
|
||||||
|
LOG_VERBOSE2() printf("Executed syscmd: \"%s\"\n", line);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Executing cmd %s failed.\"}", cmd);
|
||||||
|
printf("ERROR: Executing syscmd \"%s\" failed.\n", cmd);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't execute cmd %s.\"}", cmd);
|
||||||
|
printf("ERROR: Can't execute syscmd \"%s\"\n", cmd);
|
||||||
|
}
|
||||||
|
CHECK_RETURN_LEN();
|
||||||
|
}
|
||||||
|
|
30
src/mympd_api.h
Normal file
30
src/mympd_api.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/* myMPD
|
||||||
|
(c) 2018-2019 Juergen Mang <mail@jcgames.de>
|
||||||
|
This project's homepage is: https://github.com/jcorporation/mympd
|
||||||
|
|
||||||
|
myMPD ist fork of:
|
||||||
|
|
||||||
|
ympd
|
||||||
|
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
|
||||||
|
This project's homepage is: http://www.ympd.org
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 of the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __MYMPD_API_H__
|
||||||
|
#define __MYMPD_API_H__
|
||||||
|
|
||||||
|
void *mympd_api_loop(void *arg_config);
|
||||||
|
|
||||||
|
#endif
|
@ -23,25 +23,31 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
#include "tiny_queue.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "web_server.h"
|
#include "web_server.h"
|
||||||
#include "mpd_client.h"
|
#include "mpd_client.h"
|
||||||
#include "../dist/src/mongoose/mongoose.h"
|
#include "../dist/src/mongoose/mongoose.h"
|
||||||
|
#include "../dist/src/frozen/frozen.h"
|
||||||
|
|
||||||
//non-api definitions
|
//private definitions
|
||||||
static int is_websocket(const struct mg_connection *nc);
|
static int is_websocket(const struct mg_connection *nc);
|
||||||
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data);
|
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data);
|
||||||
static void ev_handler_redirect(struct mg_connection *nc_http, int ev, void *ev_data);
|
static void ev_handler_redirect(struct mg_connection *nc_http, int ev, void *ev_data);
|
||||||
static void send_ws_notify(struct mg_mgr *mgr, struct work_result_t *response);
|
static void send_ws_notify(struct mg_mgr *mgr, struct work_result_t *response);
|
||||||
static void send_api_response(struct mg_mgr *mgr, struct work_result_t *response);
|
static void send_api_response(struct mg_mgr *mgr, struct work_result_t *response);
|
||||||
|
static bool handle_api(long conn_id, const char *request, int request_len);
|
||||||
|
|
||||||
typedef struct t_user_data {
|
typedef struct t_user_data {
|
||||||
void *config; //pointer to mympd config
|
void *config; //pointer to mympd config
|
||||||
long conn_id;
|
long conn_id;
|
||||||
} t_user_data;
|
} t_user_data;
|
||||||
|
|
||||||
//api functions
|
//public functions
|
||||||
bool web_server_init(void *arg_mgr, void *arg_config) {
|
bool web_server_init(void *arg_mgr, void *arg_config) {
|
||||||
struct mg_mgr *mgr = (struct mg_mgr *) arg_mgr;
|
struct mg_mgr *mgr = (struct mg_mgr *) arg_mgr;
|
||||||
t_config *config = (t_config *) arg_config;
|
t_config *config = (t_config *) arg_config;
|
||||||
@ -93,13 +99,13 @@ bool web_server_init(void *arg_mgr, void *arg_config) {
|
|||||||
return mgr;
|
return mgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void web_server_free(void *arg) {
|
void web_server_free(void *arg_mgr) {
|
||||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
struct mg_mgr *mgr = (struct mg_mgr *) arg_mgr;
|
||||||
mg_mgr_free(mgr);
|
mg_mgr_free(mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *web_server_loop(void *arg) {
|
void *web_server_loop(void *arg_mgr) {
|
||||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
struct mg_mgr *mgr = (struct mg_mgr *) arg_mgr;
|
||||||
while (s_signal_received == 0) {
|
while (s_signal_received == 0) {
|
||||||
mg_mgr_poll(mgr, 100);
|
mg_mgr_poll(mgr, 100);
|
||||||
unsigned web_server_queue_length = tiny_queue_length(web_server_queue);
|
unsigned web_server_queue_length = tiny_queue_length(web_server_queue);
|
||||||
@ -119,7 +125,7 @@ void *web_server_loop(void *arg) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//non-api functions
|
//private functions
|
||||||
static int is_websocket(const struct mg_connection *nc) {
|
static int is_websocket(const struct mg_connection *nc) {
|
||||||
return nc->flags & MG_F_IS_WEBSOCKET;
|
return nc->flags & MG_F_IS_WEBSOCKET;
|
||||||
}
|
}
|
||||||
@ -160,7 +166,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
|||||||
else
|
else
|
||||||
user_data->conn_id = 1;
|
user_data->conn_id = 1;
|
||||||
|
|
||||||
//remove mgr user_data and set connection specific user_data
|
//replace mgr user_data with connection specific user_data
|
||||||
t_user_data *nc_user_data = (t_user_data*)malloc(sizeof(t_user_data));
|
t_user_data *nc_user_data = (t_user_data*)malloc(sizeof(t_user_data));
|
||||||
nc_user_data->config = config;
|
nc_user_data->config = config;
|
||||||
nc_user_data->conn_id = user_data->conn_id;
|
nc_user_data->conn_id = user_data->conn_id;
|
||||||
@ -188,10 +194,13 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
|||||||
struct http_message *hm = (struct http_message *) ev_data;
|
struct http_message *hm = (struct http_message *) ev_data;
|
||||||
LOG_VERBOSE2() printf("HTTP request (%ld): %.*s\n", user_data->conn_id, hm->uri.len, hm->uri.p);
|
LOG_VERBOSE2() printf("HTTP request (%ld): %.*s\n", user_data->conn_id, hm->uri.len, hm->uri.p);
|
||||||
if (mg_vcmp(&hm->uri, "/api") == 0) {
|
if (mg_vcmp(&hm->uri, "/api") == 0) {
|
||||||
struct work_request_t *request = (struct work_request_t*)malloc(sizeof(struct work_request_t));
|
bool rc = handle_api(user_data->conn_id, hm->body.p, hm->body.len);
|
||||||
request->conn_id = user_data->conn_id;
|
if (rc == false) {
|
||||||
request->length = copy_string(request->data, hm->body.p, 1000, hm->body.len);
|
printf("ERROR: Invalid API request.\n");
|
||||||
tiny_queue_push(mpd_client_queue, request);
|
char *response = "{\"type\": \"error\", \"data\": \"Invalid API request\"}";
|
||||||
|
mg_send_head(nc, 200, strlen(response), "Content-Type: application/json");
|
||||||
|
mg_printf(nc, "%s", response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
static struct mg_serve_http_opts s_http_server_opts;
|
static struct mg_serve_http_opts s_http_server_opts;
|
||||||
@ -239,3 +248,28 @@ static void ev_handler_redirect(struct mg_connection *nc, int ev, void *ev_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool handle_api(long conn_id, const char *request_body, int request_len) {
|
||||||
|
char *cmd;
|
||||||
|
|
||||||
|
LOG_VERBOSE() printf("API request: %.*s\n", request_len, request_body);
|
||||||
|
const int je = json_scanf(request_body, request_len, "{cmd: %Q}", &cmd);
|
||||||
|
if (je < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
enum mypd_cmd_ids cmd_id = get_cmd_id(cmd);
|
||||||
|
if (cmd_id == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct work_request_t *request = (struct work_request_t*)malloc(sizeof(struct work_request_t));
|
||||||
|
request->conn_id = conn_id;
|
||||||
|
request->cmd_id = cmd_id;
|
||||||
|
request->length = copy_string(request->data, request_body, 1000, request_len);
|
||||||
|
|
||||||
|
if (strncmp(cmd, "MYMPD_API_", 10) == 0)
|
||||||
|
tiny_queue_push(mympd_api_queue, request);
|
||||||
|
else
|
||||||
|
tiny_queue_push(mpd_client_queue, request);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -25,24 +25,8 @@
|
|||||||
#ifndef __WEB_SERVER_H__
|
#ifndef __WEB_SERVER_H__
|
||||||
#define __WEB_SERVER_H__
|
#define __WEB_SERVER_H__
|
||||||
|
|
||||||
#include "tiny_queue.h"
|
void *web_server_loop(void *arg_mgr);
|
||||||
|
|
||||||
tiny_queue_t *web_server_queue;
|
|
||||||
|
|
||||||
struct work_request_t {
|
|
||||||
long conn_id; // needed to identify the connection where to send the reply
|
|
||||||
char data[1000];
|
|
||||||
int length;
|
|
||||||
} work_request_t;
|
|
||||||
|
|
||||||
struct work_result_t {
|
|
||||||
long conn_id; // needed to identify the connection where to send the reply
|
|
||||||
char data[MAX_SIZE];
|
|
||||||
int length;
|
|
||||||
} work_result_t;
|
|
||||||
|
|
||||||
void *web_server_loop(void *arg);
|
|
||||||
bool web_server_init(void *arg_mgr, void *arg_config);
|
bool web_server_init(void *arg_mgr, void *arg_config);
|
||||||
void web_server_free(void *arg);
|
void web_server_free(void *arg_mgr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user