cron, internal epggrab: add multi-line cron support for internal epggrab

This commit is contained in:
Jaroslav Kysela 2014-06-29 22:26:52 +02:00
parent 4b993e3ef1
commit 80209a4aff
6 changed files with 160 additions and 87 deletions

View file

@ -21,7 +21,9 @@
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloca.h>
/*
* Parse value
@ -148,6 +150,43 @@ cron_set ( cron_t *c, const char *str )
return 0;
}
/*
* Set value
*/
cron_multi_t *
cron_multi_set ( const char *str )
{
char *s = str ? alloca(strlen(str) + 1) : NULL;
char *line, *sptr;
cron_t cron;
cron_multi_t *cm = NULL, *cm2;
int count = 0;
if (s == NULL)
return NULL;
strcpy(s, str);
line = strtok_r(s, "\n", &sptr);
while (line) {
while (*line && *line <= ' ')
line++;
if (line[0] != '#')
if (!cron_set(&cron, line)) {
count++;
cm2 = realloc(cm, sizeof(cm) + sizeof(cron) * count);
if (cm2 == NULL) {
free(cm);
return NULL;
}
cm = cm2;
cm->cm_crons[count - 1] = cron;
}
line = strtok_r(NULL, "\n", &sptr);
}
if (count)
cm->cm_count = count;
return cm;
}
/*
* Check for leap year
*/
@ -182,7 +221,7 @@ int
cron_next ( cron_t *c, const time_t now, time_t *ret )
{
struct tm nxt, tmp;
int endyear;
int endyear, loops = 1000;
localtime_r(&now, &nxt);
endyear = nxt.tm_year + 10;
@ -239,6 +278,10 @@ cron_next ( cron_t *c, const time_t now, time_t *ret )
!(c->c_wday & (0x1LL << (nxt.tm_wday))) ||
!(c->c_mon & (0x1LL << (nxt.tm_mon))) ) {
/* Endless loop protection */
if (loops-- == 0)
return -1;
/* Stop possible infinite loop on invalid request */
if (nxt.tm_year >= endyear)
return -1;
@ -277,6 +320,27 @@ cron_next ( cron_t *c, const time_t now, time_t *ret )
return 0;
}
/*
* Find the next time (starting from now) that the cron should fire
*/
int
cron_multi_next ( cron_multi_t *cm, const time_t now, time_t *ret )
{
uint32_t i;
time_t r = (time_t)-1, t;
if (cm == NULL)
return -1;
for (i = 0; i < cm->cm_count; i++)
if (!cron_next(&cm->cm_crons[i], now, &t))
if (r == (time_t)-1 || t < r)
r = t;
if (r == (time_t)-1)
return -1;
*ret = r;
return 0;
}
/*
* Testing
*/

View file

@ -38,6 +38,12 @@ typedef struct cron
uint8_t c_wday; ///< Day of the Week mask
} cron_t;
typedef struct cron_multi
{
uint32_t cm_count; ///< Count of multiple crons
cron_t cm_crons[0]; ///< Allocated cron structures
} cron_multi_t;
/**
* Initialise from a string
*
@ -59,6 +65,26 @@ int cron_set ( cron_t *c, const char *str );
*/
int cron_next ( cron_t *c, const time_t cur, time_t *nxt );
/**
* Initialise from a string
*
* @param str String representation of the mutiple cron entries ('\n' delimiter)
*
* @return cron_multi_t pointer if OK, NULL if failed to parse
*/
cron_multi_t *cron_multi_set ( const char *str );
/**
* Determine the next time a cron will run (from cur)
*
* @param c The cron to check
* @param now The current time
* @param nxt The next time to execute
*
* @return 0 if next time was found
*/
int cron_multi_next ( cron_multi_t *cm, const time_t cur, time_t *nxt );
#endif /* __TVH_CRON_H__ */
/******************************************************************************

View file

@ -36,6 +36,7 @@
#include "htsmsg_xml.h"
#include "file.h"
#include "service.h"
#include "cron.h"
/* Thread protection */
static int epggrab_confver;
@ -44,7 +45,7 @@ static pthread_cond_t epggrab_cond;
int epggrab_running;
/* Config */
uint32_t epggrab_interval;
char *epggrab_cron;
epggrab_module_int_t* epggrab_module;
epggrab_module_list_t epggrab_modules;
uint32_t epggrab_channel_rename;
@ -54,6 +55,8 @@ uint32_t epggrab_epgdb_periodicsave;
gtimer_t epggrab_save_timer;
static cron_multi_t *epggrab_cron_multi;
/* **************************************************************************
* Internal Grab Thread
* *************************************************************************/
@ -88,6 +91,7 @@ static void* _epggrab_internal_thread ( void* p )
int err, confver = -1; // force first run
struct timespec ts;
epggrab_module_int_t *mod;
time_t t;
/* Setup timeout */
ts.tv_nsec = 0;
@ -107,7 +111,10 @@ static void* _epggrab_internal_thread ( void* p )
}
confver = epggrab_confver;
mod = epggrab_module;
ts.tv_sec += epggrab_interval;
if (!cron_multi_next(epggrab_cron_multi, time(NULL), &t))
ts.tv_sec = t;
else
ts.tv_sec += 60;
pthread_mutex_unlock(&epggrab_mutex);
if ( !epggrab_running)
@ -129,8 +136,9 @@ static void _epggrab_load ( void )
epggrab_module_t *mod;
htsmsg_field_t *f;
htsmsg_t *m, *a;
uint32_t enabled = 1;
uint32_t enabled = 1, interval;
const char *str;
char buf[32];
int old = 0;
/* Load settings */
@ -149,10 +157,33 @@ static void _epggrab_load ( void )
if (epggrab_epgdb_periodicsave)
gtimer_arm(&epggrab_save_timer, epg_save_callback, NULL,
epggrab_epgdb_periodicsave);
if (!htsmsg_get_u32(m, old ? "grab-interval" : "interval",
&epggrab_interval)) {
if (old) epggrab_interval *= 3600;
if ((str = htsmsg_get_str(m, "cron")) == NULL) {
if (!htsmsg_get_u32(m, old ? "grab-interval" : "interval",
&interval)) {
if (old) interval *= 3600;
str = buf;
if (interval <= 600)
strcpy(buf, "*/10 * * * *");
else if (interval <= 900)
strcpy(buf, "*/15 * * * *");
else if (interval <= 1200)
strcpy(buf, "*/30 * * * *");
else if (interval <= 3600)
strcpy(buf, "4 * * * *");
else if (interval <= 7200)
strcpy(buf, "4 */2 * * *");
else if (interval <= 14400)
strcpy(buf, "4 */4 * * *");
else if (interval <= 28800)
strcpy(buf, "4 */8 * * *");
else if (interval <= 43200)
strcpy(buf, "4 */12 * * *");
else
strcpy(buf, "4 0 * * *");
} else
strcpy(buf, "4 */12 * * *");
}
epggrab_set_cron(str);
htsmsg_get_u32(m, "grab-enabled", &enabled);
if (enabled) {
if ( (str = htsmsg_get_str(m, old ? "current-grabber" : "module")) ) {
@ -215,7 +246,8 @@ static void _epggrab_load ( void )
/* Defaults */
} else {
epggrab_interval = 12 * 3600; // hours
free(epggrab_cron);
epggrab_cron = strdup("4 */12 * * *"); // each 12 hours (noon)
epggrab_module = NULL; // disabled
LIST_FOREACH(mod, &epggrab_modules, link) // enable all OTA by default
if (mod->type == EPGGRAB_OTA)
@ -244,9 +276,8 @@ void epggrab_save ( void )
m = htsmsg_create_map();
htsmsg_add_u32(m, "channel_rename", epggrab_channel_rename);
htsmsg_add_u32(m, "channel_renumber", epggrab_channel_renumber);
htsmsg_add_u32(m, "channel_reicon", epggrab_channel_reicon);
htsmsg_add_u32(m, "epgdb_periodicsave", epggrab_epgdb_periodicsave);
htsmsg_add_u32(m, "interval", epggrab_interval);
htsmsg_add_str(m, "cron", epggrab_cron);
if ( epggrab_module )
htsmsg_add_str(m, "module", epggrab_module->id);
a = NULL;
@ -261,12 +292,15 @@ void epggrab_save ( void )
htsmsg_destroy(m);
}
int epggrab_set_interval ( uint32_t interval )
int epggrab_set_cron ( const char *cron )
{
int save = 0;
if ( epggrab_interval != interval ) {
if ( epggrab_cron == NULL || strcmp(epggrab_cron, cron) ) {
save = 1;
epggrab_interval = interval;
free(epggrab_cron);
epggrab_cron = strdup(cron);
free(epggrab_cron_multi);
epggrab_cron_multi = cron_multi_set(cron);
}
return save;
}
@ -377,13 +411,15 @@ pthread_t epggrab_tid;
void epggrab_init ( void )
{
/* Defaults */
epggrab_interval = 0;
epggrab_cron = NULL;
epggrab_module = NULL;
epggrab_channel_rename = 0;
epggrab_channel_renumber = 0;
epggrab_channel_reicon = 0;
epggrab_epgdb_periodicsave = 0;
epggrab_cron_multi = NULL;
pthread_mutex_init(&epggrab_mutex, NULL);
pthread_cond_init(&epggrab_cond, NULL);
@ -432,4 +468,8 @@ void epggrab_done ( void )
epggrab_ota_shutdown();
eit_done();
opentv_done();
free(epggrab_cron);
epggrab_cron = NULL;
free(epggrab_cron_multi);
epggrab_cron_multi = NULL;
}

View file

@ -199,8 +199,6 @@ struct epggrab_ota_mux
int om_complete; ///< Has completed a scan
int om_active;
int om_timeout; ///< User configurable
int om_interval;
time_t om_when; ///< Next event time
LIST_ENTRY(epggrab_ota_mux) om_q_link;
@ -214,8 +212,6 @@ struct epggrab_ota_map
{
LIST_ENTRY(epggrab_ota_map) om_link;
epggrab_module_ota_t *om_module;
int om_timeout;
int om_interval;
int om_complete;
int om_first;
uint64_t om_tune_count;
@ -254,7 +250,7 @@ htsmsg_t* epggrab_module_list ( void );
extern epggrab_module_list_t epggrab_modules;
extern pthread_mutex_t epggrab_mutex;
extern int epggrab_running;
extern uint32_t epggrab_interval;
extern char *epggrab_cron;
extern epggrab_module_int_t* epggrab_module;
extern uint32_t epggrab_channel_rename;
extern uint32_t epggrab_channel_renumber;
@ -264,7 +260,7 @@ extern uint32_t epggrab_epgdb_periodicsave;
/*
* Set configuration
*/
int epggrab_set_interval ( uint32_t interval );
int epggrab_set_cron ( const char *cron );
int epggrab_set_module ( epggrab_module_t *mod );
int epggrab_set_module_by_id ( const char *id );
int epggrab_set_channel_rename ( uint32_t e );

View file

@ -432,7 +432,7 @@ extjs_epggrab(http_connection_t *hc, const char *remain, void *opaque)
r = htsmsg_create_map();
if (epggrab_module)
htsmsg_add_str(r, "module", epggrab_module->id);
htsmsg_add_u32(r, "interval", epggrab_interval);
htsmsg_add_str(r, "cron", epggrab_cron);
htsmsg_add_u32(r, "channel_rename", epggrab_channel_rename);
htsmsg_add_u32(r, "channel_renumber", epggrab_channel_renumber);
htsmsg_add_u32(r, "channel_reicon", epggrab_channel_reicon);
@ -461,8 +461,8 @@ extjs_epggrab(http_connection_t *hc, const char *remain, void *opaque)
save |= epggrab_set_channel_reicon(str ? 1 : 0);
if ( (str = http_arg_get(&hc->hc_req_args, "epgdb_periodicsave")) )
save |= epggrab_set_periodicsave(atoi(str) * 3600);
if ( (str = http_arg_get(&hc->hc_req_args, "interval")) )
save |= epggrab_set_interval(atoi(str));
if ( (str = http_arg_get(&hc->hc_req_args, "cron")) )
save |= epggrab_set_cron(str);
if ( (str = http_arg_get(&hc->hc_req_args, "module")) )
save |= epggrab_set_module_by_id(str);
if ( (str = http_arg_get(&hc->hc_req_args, "external")) ) {

View file

@ -82,13 +82,22 @@ tvheadend.epggrab = function() {
var confreader = new Ext.data.JsonReader({
root: 'epggrabSettings'
}, ['module', 'interval', 'channel_rename', 'channel_renumber',
}, ['module', 'cron', 'channel_rename', 'channel_renumber',
'channel_reicon', 'epgdb_periodicsave']);
/* ****************************************************************
* Basic Fields
* ***************************************************************/
/*
* Cron setup
*/
var internalCron = new Ext.form.TextArea({
fieldLabel: 'Cron multi-line',
name: 'cron',
width: 300,
});
/*
* Module selector
*/
@ -105,68 +114,6 @@ tvheadend.epggrab = function() {
store: internalModuleStore
});
/*
* Interval selector
*/
var intervalUnits = [[86400, 'Days'], [3600, 'Hours'],
[60, 'Minutes'], [1, 'Seconds']];
var intervalValue = new Ext.form.NumberField({
width: 300,
allowNegative: false,
allowDecimals: false,
minValue: 1,
maxValue: 7,
value: 1,
fieldLabel: 'Grab interval',
name: 'intervalValue',
listeners: {
'valid': function(e) {
v = e.getValue() * intervalUnit.getValue();
interval.setValue(v);
}
}
});
var intervalUnit = new Ext.form.ComboBox({
name: 'intervalUnit',
width: 300,
valueField: 'key',
displayField: 'value',
value: 86400,
forceSelection: true,
editable: false,
triggerAction: 'all',
mode: 'local',
store: new Ext.data.SimpleStore({
fields: ['key', 'value'],
data: intervalUnits
}),
listeners: {
'change': function(e, n, o) {
intervalValue.maxValue = (7 * 86400) / n;
intervalValue.validate();
}
}
});
var interval = new Ext.form.Hidden({
name: 'interval',
value: 86400,
listeners: {
'enable': function(e) {
v = e.getValue();
for (i = 0; i < intervalUnits.length; i++) {
u = intervalUnits[i][0];
if ((v % u) === 0) {
intervalUnit.setValue(u);
intervalValue.maxValue = (7 * 86400) / u;
intervalValue.setValue(v / u);
intervalValue.validate();
break;
}
}
}
}
});
/*
* Channel handling
*/
@ -215,7 +162,7 @@ tvheadend.epggrab = function() {
width: 700,
autoHeight: true,
collapsible: true,
items: [interval, internalModule, intervalValue, intervalUnit]
items: [internalCron, internalModule]
});
/* ****************************************************************