From: Andre Noll Date: Fri, 2 Oct 2015 21:10:36 +0000 (+0000) Subject: server: Convert com_touch() to lopsub. X-Git-Tag: v0.6.0~2^2~61 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=fdf416e9af730a1df9eec8d7acb108d7ca881926 server: Convert com_touch() to lopsub. Another open-coded option parser bites the dust. This also gets rid of struct com_touch_options, along with the ugly convention of passing -1 to the action handler to indicate that the option was not given. The documentation was enhanced slightly and now explains in the [description] section the general concept of the touch command. --- diff --git a/afs.cmd b/afs.cmd index 74ad7df9..9ee51f17 100644 --- a/afs.cmd +++ b/afs.cmd @@ -59,47 +59,6 @@ U: addatt attribute1... H: This adds new attributes to the attribute table. At most 64 H: attributes may be defined. --- -N: touch -P: AFS_READ | AFS_WRITE -D: Manipulate the afs entry of audio files. -U: touch [-n=numplayed] [-l=lastplayed] [-y=lyrics_id] [-i=image_id] [-a=amp] [-v] [-p] pattern -H: If no option is given, the lastplayed field is set to the current time -H: and the value of the numplayed field is increased by one. Otherwise, -H: only the given options are taken into account. -H: -H: Options: -H: -H: -n Set the numplayed count, i.e. the number of times this audio -H: file was selected for streaming so far. -H: -H: -l Set the lastplayed time, i.e. the last time this audio file was -H: selected for streaming. The argument must be a number of seconds -H: since the epoch. Example: -H: -H: touch -l=$(date +%s) file -H: -H: sets the lastplayed time of 'file' to the current time. -H: -H: -y Set the lyrics ID which specifies the lyrics data file associated -H: with the audio file. -H: -H: -i Like -y, but sets the image ID. -H: -H: -a Set the amplification value (0-255). This determines a scaling -H: factor by which the amplitude should be multiplied in order to -H: normalize the volume of the audio file. A value of zero means -H: no amplification, 64 means the amplitude should be multiplied -H: by a factor of two, 128 by three and so on. -H: -H: This value is used by the amp filter. -H: -H: -v Verbose mode. Explain what is being done. -H: -H: -p Pathname match. Match a slash in the path only with a slash -H: in pattern and not by an asterisk (*) or a question mark -H: (?) metacharacter, nor by a bracket expression ([]) containing -H: a slash (see fnmatch(3)). ---- T: add N: add@member@ O: int com_add@member@(struct command_context *cc); diff --git a/aft.c b/aft.c index 7141e3fa..841e00b8 100644 --- a/aft.c +++ b/aft.c @@ -1956,33 +1956,26 @@ enum touch_flags { TOUCH_FLAG_VERBOSE = 2 }; -/** Options used by com_touch(). */ -struct com_touch_options { - /** New num_played value. */ - int32_t num_played; - /** New last played count. */ - int64_t last_played; - /** New lyrics id. */ - int32_t lyrics_id; - /** New image id. */ - int32_t image_id; - /** New amplification value. */ - int32_t amp; - /** Command line flags (see \ref touch_flags). */ - unsigned flags; -}; - static int touch_audio_file(__a_unused struct osl_table *table, struct osl_row *row, const char *name, void *data) { struct afs_callback_arg *aca = data; - struct com_touch_options *cto = aca->query.data; + bool v_given = SERVER_CMD_OPT_GIVEN(TOUCH, VERBOSE, aca->lpr); + const struct lls_opt_result *r_n, *r_l, *r_i, *r_y, *r_a; + int ret; struct osl_object obj; struct afs_info old_afsi, new_afsi; - int ret, no_options = cto->num_played < 0 && cto->last_played < 0 && - cto->lyrics_id < 0 && cto->image_id < 0 && cto->amp < 0; + bool no_options; struct afsi_change_event_data aced; + r_n = SERVER_CMD_OPT_RESULT(TOUCH, NUMPLAYED, aca->lpr); + r_l = SERVER_CMD_OPT_RESULT(TOUCH, LASTPLAYED, aca->lpr); + r_i = SERVER_CMD_OPT_RESULT(TOUCH, IMAGE_ID, aca->lpr); + r_y = SERVER_CMD_OPT_RESULT(TOUCH, LYRICS_ID, aca->lpr); + r_a = SERVER_CMD_OPT_RESULT(TOUCH, AMP, aca->lpr); + no_options = !lls_opt_given(r_n) && !lls_opt_given(r_l) && !lls_opt_given(r_i) + && !lls_opt_given(r_y) && !lls_opt_given(r_a); + ret = get_afsi_object_of_row(row, &obj); if (ret < 0) { para_printf(&aca->pbout, "cannot touch %s\n", name); @@ -1997,23 +1990,23 @@ static int touch_audio_file(__a_unused struct osl_table *table, if (no_options) { new_afsi.num_played++; new_afsi.last_played = time(NULL); - if (cto->flags & TOUCH_FLAG_VERBOSE) + if (v_given) para_printf(&aca->pbout, "%s: num_played = %u, " "last_played = now()\n", name, new_afsi.num_played); } else { - if (cto->flags & TOUCH_FLAG_VERBOSE) + if (lls_opt_given(r_l)) + new_afsi.last_played = lls_uint64_val(0, r_l); + if (lls_opt_given(r_n)) + new_afsi.num_played = lls_uint32_val(0, r_n); + if (lls_opt_given(r_i)) + new_afsi.image_id = lls_uint32_val(0, r_i); + if (lls_opt_given(r_y)) + new_afsi.lyrics_id = lls_uint32_val(0, r_y); + if (lls_opt_given(r_a)) + new_afsi.amp = lls_uint32_val(0, r_a); + if (v_given) para_printf(&aca->pbout, "touching %s\n", name); - if (cto->lyrics_id >= 0) - new_afsi.lyrics_id = cto->lyrics_id; - if (cto->image_id >= 0) - new_afsi.image_id = cto->image_id; - if (cto->num_played >= 0) - new_afsi.num_played = cto->num_played; - if (cto->last_played >= 0) - new_afsi.last_played = cto->last_played; - if (cto->amp >= 0) - new_afsi.amp = cto->amp; } save_afsi(&new_afsi, &obj); /* in-place update */ aced.aft_row = row; @@ -2023,115 +2016,64 @@ static int touch_audio_file(__a_unused struct osl_table *table, static int com_touch_callback(struct afs_callback_arg *aca) { + const struct lls_command *cmd = SERVER_CMD_CMD_PTR(TOUCH); + bool p_given; + const struct lls_opt_result *r_i, *r_y; int ret; - struct com_touch_options *cto = aca->query.data; struct pattern_match_data pmd = { .table = audio_file_table, .loop_col_num = AFTCOL_HASH, .match_col_num = AFTCOL_PATH, - .patterns = { - .data = (char *)aca->query.data - + sizeof(struct com_touch_options), - .size = aca->query.size - - sizeof(struct com_touch_options) - }, .data = aca, .action = touch_audio_file }; - if (cto->image_id >= 0) { - ret = img_get_name_by_id(cto->image_id, NULL); + + ret = lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr); + assert(ret >= 0); + pmd.lpr = aca->lpr; + + r_i = SERVER_CMD_OPT_RESULT(TOUCH, IMAGE_ID, aca->lpr); + if (lls_opt_given(r_i)) { + uint32_t id = lls_uint32_val(0, r_i); + ret = img_get_name_by_id(id, NULL); if (ret < 0) { - para_printf(&aca->pbout, "invalid image ID: %d\n", - cto->image_id); + para_printf(&aca->pbout, "invalid image ID: %u\n", id); return ret; } } - if (cto->lyrics_id >= 0) { - ret = lyr_get_name_by_id(cto->lyrics_id, NULL); + r_y = SERVER_CMD_OPT_RESULT(TOUCH, LYRICS_ID, aca->lpr); + if (lls_opt_given(r_y)) { + uint32_t id = lls_uint32_val(0, r_y); + ret = lyr_get_name_by_id(id, NULL); if (ret < 0) { - para_printf(&aca->pbout, "invalid lyrics ID: %d\n", - cto->lyrics_id); + para_printf(&aca->pbout, "invalid lyrics ID: %u\n", id); return ret; } } - if (cto->flags & TOUCH_FLAG_FNM_PATHNAME) + p_given = SERVER_CMD_OPT_GIVEN(TOUCH, PATHNAME_MATCH, aca->lpr); + if (p_given) pmd.fnmatch_flags |= FNM_PATHNAME; ret = for_each_matching_row(&pmd); if (ret >= 0 && pmd.num_matches == 0) ret = -E_NO_MATCH; + lls_free_parse_result(aca->lpr, cmd); return ret; } -int com_touch(struct command_context *cc) +static int com_touch(struct command_context *cc, struct lls_parse_result *lpr) { - struct com_touch_options cto = { - .num_played = -1, - .last_played = -1, - .lyrics_id = -1, - .image_id = -1, - .amp = -1, - }; - struct osl_object query = {.data = &cto, .size = sizeof(cto)}; - int i, ret; - + const struct lls_command *cmd = SERVER_CMD_CMD_PTR(TOUCH); + int ret; + char *errctx; - for (i = 1; i < cc->argc; i++) { - const char *arg = cc->argv[i]; - if (arg[0] != '-') - break; - if (!strcmp(arg, "--")) { - i++; - break; - } - if (!strncmp(arg, "-n=", 3)) { - ret = para_atoi32(arg + 3, &cto.num_played); - if (ret < 0) - return ret; - continue; - } - if (!strncmp(arg, "-l=", 3)) { - ret = para_atoi64(arg + 3, &cto.last_played); - if (ret < 0) - return ret; - continue; - } - if (!strncmp(arg, "-y=", 3)) { - ret = para_atoi32(arg + 3, &cto.lyrics_id); - if (ret < 0) - return ret; - continue; - } - if (!strncmp(arg, "-i=", 3)) { - ret = para_atoi32(arg + 3, &cto.image_id); - if (ret < 0) - return ret; - continue; - } - if (!strncmp(arg, "-a=", 3)) { - int32_t val; - ret = para_atoi32(arg + 3, &val); - if (ret < 0) - return ret; - if (val < 0 || val > 255) - return -ERRNO_TO_PARA_ERROR(EINVAL); - cto.amp = val; - continue; - } - if (!strcmp(arg, "-p")) { - cto.flags |= TOUCH_FLAG_FNM_PATHNAME; - continue; - } - if (!strcmp(arg, "-v")) { - cto.flags |= TOUCH_FLAG_VERBOSE; - continue; - } - break; /* non-option starting with dash */ + ret = lls(lls_check_arg_count(lpr, 1, INT_MAX, &errctx)); + if (ret < 0) { + send_errctx(cc, errctx); + return ret; } - if (i >= cc->argc) - return -E_AFT_SYNTAX; - return send_option_arg_callback_request(&query, cc->argc - i, - cc->argv + i, com_touch_callback, afs_cb_result_handler, cc); + return send_lls_callback_request(com_touch_callback, cmd, lpr, cc); } +EXPORT_SERVER_CMD_HANDLER(touch); static int remove_audio_file(__a_unused struct osl_table *table, struct osl_row *row, const char *name, void *data) diff --git a/m4/lls/server_cmd.suite.m4 b/m4/lls/server_cmd.suite.m4 index eda1ba61..2ddc53dc 100644 --- a/m4/lls/server_cmd.suite.m4 +++ b/m4/lls/server_cmd.suite.m4 @@ -378,6 +378,119 @@ aux_info_prefix = Permissions: necessary to send SIGKILL. [/description] +[subcommand touch] + purpose = manipulate the afs information of audio files + non-opts-name = pattern... + aux_info = AFS_READ | AFS_WRITE + [description] + This command modifies the afs info structure of all rows of the audio + file table whose path matches at least one of the given patters. + + If at least one option is given which takes a number as its argument, + only those fields of the afs info structure are updated which + correspond to the given options while all other fields stay unmodified. + + If no such option is given, the lastplayed field is set to the current + time and the value of the numplayed field is increased by one while + all other fields are left unchanged. This mimics what happens when + the virtual streaming system selects the file for streaming. + + If the file is admissible for the current mood (or contained in the + current playlist), its score is recomputed according to the changed + values. + [/description] + [option numplayed] + short_opt = n + summary = set the numplayed count manually + arg_type = uint32 + arg_info = required_arg + typestr = num + [help] + The numplayed count of an audio file is the number of times the file + was selected for streaming. It is one of the inputs to the scoring + function which determines the order in which admissible files are + streamed. + + The virtual streaming system increases this number automatically each + time it opens the file for streaming. + [/help] + [option lastplayed] + short_opt = l + summary = set the lastplayed time manually + arg_type = uint64 + arg_info = required_arg + typestr = num + [help] + The lastplayed time of an audio file is the time when the file was + last opened for streaming. + + Like the numplayed count, it is an input for the scoring function + and is updated automatically by the virtual streaming system. + + The argument must be a number of seconds since the epoch. Example: + + touch -l=$(date +%s) file + + sets the lastplayed time of 'file' to the current time. + [/help] + [option image-id] + short_opt = i + summary = set the image id + arg_type = uint32 + arg_info = required_arg + typestr = num + [help] + The afs info structure of each row of the audio file table contains + a slot for the image id of the audio file that corresponds to the + row. The image id stored in this slot refers to the key in the image + table that identifies the blob. + + When a new audio file is added to the audio file table, its image + id starts out as zero, indicating that there is no image associated + with the file. Setting the image id to a non-zero number associates + the file with a particular blob of the image table, for example the + cover art of the album in jpg format. + [/help] + [option lyrics-id] + short_opt = y + summary = set the lyrics id + arg_type = uint32 + arg_info = required_arg + typestr = num + [help] + This option works just like --image-id, but sets the lyrics ID rather + than the image id. + [/help] + [option amp] + short_opt = a + summary = set the amplification value (0-255) + arg_type = uint32 + arg_info = required_arg + typestr = num + [help] + The amplification value of an audio file is a number which is stored + in the afs info structure. + + The value determines the scaling factor by which the amplitude of + the decoded samples should be multiplied in order to normalize the + volume. A value of zero means no amplification, 64 means the amplitude + should be multiplied by a factor of two, 128 by three and so on. + + The amp filter of para_audiod amplifies the volume according to + this value. + [/help] + [option verbose] + short_opt = v + summary = explain what is being done + [option pathname-match] + short_opt = p + summary = modify matching behaviour + [help] + Match a slash in the path only with a slash in pattern and not by an + asterisk (*) or a question mark (?) metacharacter, nor by a bracket + expression ([]) containing a slash (see fnmatch(3)). + [/help] + [subcommand version] purpose = print the git version string of para_server aux_info = NO_PERMISSION_REQUIRED