#define AL_LOG_SECTION "cmsrv" #include #include #define CMSRV_LOCAL_SOCKET #ifdef CMSRV_LOCAL_SOCKET #include #endif #include #include "../../server/server.h" #include "../../server/common.h" #include "../../codec/ffmpeg/common.h" #if CACHE_HAVE_CDIO #include "../../cache/handlers/cdio.h" #endif #ifdef CMSRV_USE_UI #include "ui.h" #endif struct cmsrv { struct nn_event_loop loop; struct nn_signal quit_signal; struct camu_server server; #ifdef CMSRV_LOCAL_SOCKET struct { struct nn_socket sock; struct nn_line_processor cli; } local; #endif #ifdef CMSRV_USE_UI struct cmsrv_ui ui; struct nn_poll input_poll; struct nn_timer render_timer; #endif }; static void close_cmsrv(struct cmsrv *s) { #ifdef CMSRV_LOCAL_SOCKET nn_line_processor_stop(&s->local.cli); #endif #ifdef CMSRV_USE_UI nn_poll_stop(&s->input_poll); nn_timer_stop(&s->render_timer); #endif camu_server_close(&s->server); nn_signal_stop(&s->quit_signal); } #ifdef CMSRV_LOCAL_SOCKET static u8 server_line_callback(void *userdata, str *line) { struct cmsrv *s = (struct cmsrv *)userdata; struct lia_list *list = al_array_at(s->server.lists, 0); if (al_str_eq(line, &al_str_c(";PAUSE"))) { lia_list_toggle_pause(list, LIANA_SEQUENCE_ANY, -1.0); } else if (al_str_cmp(line, &al_str_c(";NEXT"), 0, 5) == 0) { s32 n = 1; if (line->length > 6) { str arg = al_str_substr(line, 6, line->length); bool error; s64 i = al_str_to_long(&arg, 10, &error); if (!error) n = CLAMP(i, (s64)INT32_MIN, (s64)INT32_MAX); } lia_list_skip(list, LIANA_SEQUENCE_ANY, n); } else if (al_str_cmp(line, &al_str_c(";PREV"), 0, 5) == 0) { s32 n = -1; if (line->length > 6) { str arg = al_str_substr(line, 6, line->length); bool error; s64 i = -al_str_to_long(&arg, 10, &error); if (!error) n = CLAMP(i, (s64)INT32_MIN, (s64)INT32_MAX); } lia_list_skip(list, LIANA_SEQUENCE_ANY, n); } else if (al_str_cmp(line, &al_str_c(";SEEK"), 0, 5) == 0) { if (line->length > 6) { str arg = al_str_substr(line, 6, line->length); bool error; s64 i = al_str_to_long(&arg, 10, &error); if (!error) { i *= 1000000; lia_list_seek(list, LIANA_SEQUENCE_ANY, 0, CLAMP(i, (s64)0, (s64)INT64_MAX)); } } } else if (al_str_eq(line, &al_str_c(";SHUFFLE"))) { lia_list_shuffle(list); } else if (al_str_eq(line, &al_str_c(";SORT"))) { lia_list_sort(list); } else if (al_str_eq(line, &al_str_c(";REVERSE"))) { lia_list_reverse(list); } else if (al_str_eq(line, &al_str_c(";CLEAR"))) { lia_list_clear(list); } else { struct nn_packet *packet = nn_packet_create(); nn_packet_write_str(packet, line); camu_server_local_add(&s->server, packet); nn_packet_free(packet); } return NNWT_LINE_PROCESSOR_CONTINUE; } #endif #ifdef CMSRV_USE_UI static s32 log_callback(void *userdata, u8 level, char *message) { struct cmsrv *s = (struct cmsrv *)userdata; (void)level; cmsrv_ui_push_message(&s->ui, al_strndup(message, AL_LOG_MESSAGE_SIZE)); return al_strnlen(message, AL_LOG_MESSAGE_SIZE); } static void input_poll_callback(void *userdata, s32 revents) { struct cmsrv *s = (struct cmsrv *)userdata; (void)revents; struct ncinput input; for (;;) { if (!cmsrv_ui_read_input(&s->ui, &input)) break; if (input.evtype == NCTYPE_PRESS || input.evtype == NCTYPE_UNKNOWN) { switch (input.id) { case 'q': close_cmsrv(s); break; case '1': cmsrv_ui_set_pane(&s->ui, CMSRV_UI_LISTS); break; case '2': cmsrv_ui_set_pane(&s->ui, CMSRV_UI_RESOURCES); break; case '3': cmsrv_ui_set_pane(&s->ui, CMSRV_UI_NODES); break; } } } } static void render_timer_callback(void *userdata, struct nn_timer *timer) { struct cmsrv *s = (struct cmsrv *)userdata; (void)timer; cmsrv_ui_render(&s->ui); } #endif static void quit_signal_callback(void *userdata) { struct cmsrv *s = (struct cmsrv *)userdata; close_cmsrv(s); } static struct cmsrv s = { 0 }; static void sigint_handler(s32 signum) { (void)signum; nn_signal_send(&s.quit_signal); } #ifdef NAUNET_ON_WINDOWS s32 wmain(s32 argc, wchar_t **argv) #else s32 main(s32 argc, char *argv[]) #endif { if (!nn_common_init("cmsrv_main")) { return EXIT_FAILURE; } #ifdef CMSRV_USE_UI if (!cmsrv_ui_init(&s.ui, &s.server)) { return EXIT_FAILURE; } al_set_print(log_callback, &s); #endif #ifdef CAMU_HAVE_FFMPEG camu_ff_common_init(); #endif nn_event_loop_init(&s.loop); nn_signal_init(&s.quit_signal, &s.loop, quit_signal_callback, &s); nn_signal_start(&s.quit_signal); signal(SIGINT, sigint_handler); str addr = al_str_c("127.0.0.1"); char *CMSRV_IP = getenv("CMSRV_IP"); if (CMSRV_IP) addr = al_str_cr(CMSRV_IP); log_info("Serving from %.*s.", al_str_x(&addr)); camu_server_init(&s.server, &s.loop); if (!camu_server_listen(&s.server, NNWT_SOCKET_TCP, &addr, CAMU_PORT)) { return EXIT_FAILURE; } #ifdef CMSRV_LOCAL_SOCKET s.local.sock.type = NNWT_SOCKET_UNIX; nn_socket_init(&s.local.sock, NNWT_SOCKET_NONBLOCKING); s.local.cli.callback = server_line_callback; s.local.cli.userdata = &s; nn_line_processor_init(&s.local.cli, &al_str_c("\n")); nn_line_processor_open_socket(&s.local.cli, &s.local.sock); if (nn_socket_bind(&s.local.sock, &al_str_c("/tmp/camu_control"), 0) && nn_socket_listen(&s.local.sock)) { nn_line_processor_run(&s.local.cli, &s.loop); } #endif #ifdef CMSRV_USE_UI nn_poll_init(&s.input_poll, input_poll_callback, &s); nn_poll_set(&s.input_poll, cmsrv_ui_get_input_fd(&s.ui), NNWT_POLL_READ); nn_poll_start(&s.input_poll, &s.loop); nn_timer_init(&s.render_timer, &s.loop, render_timer_callback, &s); nn_timer_set_repeat(&s.render_timer, NNWT_TS_FROM_USEC(100000)); nn_timer_again(&s.render_timer); #endif nn_event_loop_run(&s.loop); #ifdef CMSRV_LOCAL_SOCKET nn_socket_close(&s.local.sock); #endif #ifdef CMSRV_USE_UI cmsrv_ui_close(&s.ui); #endif camu_server_free(&s.server); nn_event_loop_destroy(&s.loop); nn_common_close(); (void)argc; (void)argv; return EXIT_SUCCESS; }