cron, internal epggrab: add multi-line cron support for internal epggrab
This commit is contained in:
parent
4b993e3ef1
commit
80209a4aff
6 changed files with 160 additions and 87 deletions
66
src/cron.c
66
src/cron.c
|
@ -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
|
||||
*/
|
||||
|
|
26
src/cron.h
26
src/cron.h
|
@ -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__ */
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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")) ) {
|
||||
|
|
|
@ -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]
|
||||
});
|
||||
|
||||
/* ****************************************************************
|
||||
|
|
Loading…
Add table
Reference in a new issue