diff options
Diffstat (limited to 'sources')
-rw-r--r-- | sources/ogAdmServer.c | 428 | ||||
-rw-r--r-- | sources/schedule.c | 394 | ||||
-rw-r--r-- | sources/schedule.h | 37 |
3 files changed, 847 insertions, 12 deletions
diff --git a/sources/ogAdmServer.c b/sources/ogAdmServer.c index b6fb375..116852c 100644 --- a/sources/ogAdmServer.c +++ b/sources/ogAdmServer.c @@ -10,6 +10,7 @@ #include "ogAdmLib.c" #include "dbi.h" #include "list.h" +#include "schedule.h" #include <ev.h> #include <syslog.h> #include <sys/ioctl.h> @@ -18,6 +19,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <jansson.h> +#include <time.h> static char usuario[LONPRM]; // Usuario de acceso a la base de datos static char pasguor[LONPRM]; // Password del usuario @@ -3028,6 +3030,7 @@ struct og_msg_params { bool echo; struct og_partition partition_setup[OG_PARTITION_MAX]; struct og_sync_params sync_setup; + struct og_schedule_time time; const char *task_id; uint64_t flags; }; @@ -3073,6 +3076,12 @@ struct og_computer { #define OG_REST_PARAM_SYNC_METHOD (1UL << 29) #define OG_REST_PARAM_ECHO (1UL << 30) #define OG_REST_PARAM_TASK (1UL << 31) +#define OG_REST_PARAM_TIME_YEARS (1UL << 32) +#define OG_REST_PARAM_TIME_MONTHS (1UL << 33) +#define OG_REST_PARAM_TIME_DAYS (1UL << 34) +#define OG_REST_PARAM_TIME_HOURS (1UL << 35) +#define OG_REST_PARAM_TIME_AM_PM (1UL << 36) +#define OG_REST_PARAM_TIME_MINUTES (1UL << 37) enum og_rest_method { OG_METHOD_GET = 0, @@ -3190,6 +3199,15 @@ static int og_json_parse_string(json_t *element, const char **str) return 0; } +static int og_json_parse_uint(json_t *element, uint32_t *integer) +{ + if (json_typeof(element) != JSON_INTEGER) + return -1; + + *integer = json_integer_value(element); + return 0; +} + static int og_json_parse_bool(json_t *element, bool *value) { if (json_typeof(element) == JSON_TRUE) @@ -3337,6 +3355,40 @@ static int og_json_parse_partition_setup(json_t *element, return 0; } +static int og_json_parse_time_params(json_t *element, + struct og_msg_params *params) +{ + const char *key; + json_t *value; + int err = 0; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "years")) { + err = og_json_parse_uint(value, ¶ms->time.years); + params->flags |= OG_REST_PARAM_TIME_YEARS; + } else if (!strcmp(key, "months")) { + err = og_json_parse_uint(value, ¶ms->time.months); + params->flags |= OG_REST_PARAM_TIME_MONTHS; + } else if (!strcmp(key, "days")) { + err = og_json_parse_uint(value, ¶ms->time.days); + params->flags |= OG_REST_PARAM_TIME_DAYS; + } else if (!strcmp(key, "hours")) { + err = og_json_parse_uint(value, ¶ms->time.hours); + params->flags |= OG_REST_PARAM_TIME_HOURS; + } else if (!strcmp(key, "am_pm")) { + err = og_json_parse_uint(value, ¶ms->time.am_pm); + params->flags |= OG_REST_PARAM_TIME_AM_PM; + } else if (!strcmp(key, "minutes")) { + err = og_json_parse_uint(value, ¶ms->time.minutes); + params->flags |= OG_REST_PARAM_TIME_MINUTES; + } + if (err != 0) + return err; + } + + return err; +} + static int og_cmd_post_clients(json_t *element, struct og_msg_params *params) { const char *key; @@ -4571,7 +4623,7 @@ static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task) return 0; } -static int og_queue_procedure(struct og_dbi *dbi, struct og_task *task) +static int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task) { uint32_t procedure_id; const char *msglog; @@ -4592,7 +4644,7 @@ static int og_queue_procedure(struct og_dbi *dbi, struct og_task *task) procedure_id = dbi_result_get_uint(result, "procedimientoid"); if (procedure_id > 0) { task->procedure_id = procedure_id; - if (og_queue_procedure(dbi, task)) + if (og_dbi_queue_procedure(dbi, task)) return -1; continue; } @@ -4607,7 +4659,7 @@ static int og_queue_procedure(struct og_dbi *dbi, struct og_task *task) return 0; } -static int og_queue_task(struct og_dbi *dbi, uint32_t task_id) +static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id) { struct og_task task = {}; uint32_t task_id_next; @@ -4635,7 +4687,7 @@ static int og_queue_task(struct og_dbi *dbi, uint32_t task_id) task_id_next = dbi_result_get_uint(result, "procedimientoid"); if (task_id_next > 0) { - if (og_queue_task(dbi, task_id_next)) + if (og_dbi_queue_task(dbi, task_id_next)) return -1; continue; @@ -4645,8 +4697,7 @@ static int og_queue_task(struct og_dbi *dbi, uint32_t task_id) task.scope = dbi_result_get_uint(result, "idambito"); task.filtered_scope = dbi_result_get_string(result, "restrambito"); - og_queue_procedure(dbi, &task); - + og_dbi_queue_procedure(dbi, &task); } dbi_result_free(result); @@ -4654,6 +4705,41 @@ static int og_queue_task(struct og_dbi *dbi, uint32_t task_id) return 0; } +void og_dbi_schedule_task(unsigned int task_id) +{ + struct og_msg_params params = {}; + bool duplicated = false; + struct og_cmd *cmd; + struct og_dbi *dbi; + unsigned int i; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return; + } + og_dbi_queue_task(dbi, task_id); + og_dbi_close(dbi); + + list_for_each_entry(cmd, &cmd_list, list) { + for (i = 0; i < params.ips_array_len; i++) { + if (!strncmp(cmd->ip, params.ips_array[i], + OG_DB_IP_MAXLEN)) { + duplicated = true; + break; + } + } + + if (!duplicated) + params.ips_array[params.ips_array_len++] = cmd->ip; + else + duplicated = false; + } + + og_send_request("run/schedule", OG_METHOD_GET, ¶ms, NULL); +} + static int og_cmd_task_post(json_t *element, struct og_msg_params *params) { struct og_cmd *cmd; @@ -4685,7 +4771,7 @@ static int og_cmd_task_post(json_t *element, struct og_msg_params *params) return -1; } - og_queue_task(dbi, atoi(params->task_id)); + og_dbi_queue_task(dbi, atoi(params->task_id)); og_dbi_close(dbi); list_for_each_entry(cmd, &cmd_list, list) @@ -4694,6 +4780,288 @@ static int og_cmd_task_post(json_t *element, struct og_msg_params *params) return og_send_request("run/schedule", OG_METHOD_GET, params, NULL); } +static int og_dbi_schedule_get(void) +{ + uint32_t schedule_id, task_id; + struct og_schedule_time time; + struct og_dbi *dbi; + const char *msglog; + dbi_result result; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + + result = dbi_conn_queryf(dbi->conn, + "SELECT idprogramacion, tipoaccion, identificador, " + "sesion, annos, meses, diario, dias, semanas, horas, " + "ampm, minutos FROM programaciones " + "WHERE suspendida = 0"); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return -1; + } + + while (dbi_result_next_row(result)) { + memset(&time, 0, sizeof(time)); + schedule_id = dbi_result_get_uint(result, "idprogramacion"); + task_id = dbi_result_get_uint(result, "identificador"); + time.years = dbi_result_get_uint(result, "annos"); + time.months = dbi_result_get_uint(result, "meses"); + time.weeks = dbi_result_get_uint(result, "semanas"); + time.week_days = dbi_result_get_uint(result, "dias"); + time.days = dbi_result_get_uint(result, "diario"); + time.hours = dbi_result_get_uint(result, "horas"); + time.am_pm = dbi_result_get_uint(result, "ampm"); + time.minutes = dbi_result_get_uint(result, "minutos"); + + og_schedule_create(schedule_id, task_id, &time); + } + + dbi_result_free(result); + + return 0; +} + +static int og_dbi_schedule_create(struct og_dbi *dbi, + struct og_msg_params *params, + uint32_t *schedule_id) +{ + const char *msglog; + dbi_result result; + uint8_t suspended = 0; + uint8_t type = 3; + + result = dbi_conn_queryf(dbi->conn, + "INSERT INTO programaciones (tipoaccion," + " identificador, nombrebloque, annos, meses," + " diario, horas, ampm, minutos, suspendida) VALUES (%d," + " %s, '%s', %d, %d, %d, %d, %d, %d, %d)", type, + params->task_id, params->name, params->time.years, + params->time.months, params->time.days, + params->time.hours, params->time.am_pm, + params->time.minutes, suspended); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return -1; + } + dbi_result_free(result); + + *schedule_id = dbi_conn_sequence_last(dbi->conn, NULL); + + return 0; +} + +static int og_dbi_schedule_update(struct og_dbi *dbi, + struct og_msg_params *params) +{ + const char *msglog; + dbi_result result; + uint8_t type = 3; + + result = dbi_conn_queryf(dbi->conn, + "UPDATE programaciones SET tipoaccion=%d, " + "identificador='%s', nombrebloque='%s', " + "annos=%d, meses=%d, " + "diario=%d, horas=%d, ampm=%d, minutos=%d " + "WHERE idprogramacion='%s'", + type, params->task_id, params->name, + params->time.years, params->time.months, + params->time.days, params->time.hours, + params->time.am_pm, params->time.minutes, + params->id); + + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return -1; + } + dbi_result_free(result); + + return 0; +} + +static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id) +{ + const char *msglog; + dbi_result result; + + result = dbi_conn_queryf(dbi->conn, + "DELETE FROM programaciones WHERE idprogramacion=%d", + id); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return -1; + } + dbi_result_free(result); + + return 0; +} + +static struct ev_loop *og_loop; + +static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params) +{ + uint32_t schedule_id; + struct og_dbi *dbi; + const char *key; + json_t *value; + int err; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "task")) { + err = og_json_parse_string(value, ¶ms->task_id); + params->flags |= OG_REST_PARAM_TASK; + } else if (!strcmp(key, "name")) { + err = og_json_parse_string(value, ¶ms->name); + params->flags |= OG_REST_PARAM_NAME; + } else if (!strcmp(key, "time_params")) + err = og_json_parse_time_params(value, params); + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_TASK | + OG_REST_PARAM_NAME | + OG_REST_PARAM_TIME_YEARS | + OG_REST_PARAM_TIME_MONTHS | + OG_REST_PARAM_TIME_DAYS | + OG_REST_PARAM_TIME_HOURS | + OG_REST_PARAM_TIME_MINUTES | + OG_REST_PARAM_TIME_AM_PM)) + return -1; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + + err = og_dbi_schedule_create(dbi, params, &schedule_id); + og_dbi_close(dbi); + + if (err < 0) + return -1; + + og_schedule_create(schedule_id, atoi(params->task_id), ¶ms->time); + og_schedule_refresh(og_loop); + + return err; +} + +static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params) +{ + struct og_dbi *dbi; + const char *key; + json_t *value; + int err; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "id")) { + err = og_json_parse_string(value, ¶ms->id); + params->flags |= OG_REST_PARAM_ID; + } else if (!strcmp(key, "task")) { + err = og_json_parse_string(value, ¶ms->task_id); + params->flags |= OG_REST_PARAM_TASK; + } else if (!strcmp(key, "name")) { + err = og_json_parse_string(value, ¶ms->name); + params->flags |= OG_REST_PARAM_NAME; + } else if (!strcmp(key, "time_params")) + err = og_json_parse_time_params(value, params); + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ID | + OG_REST_PARAM_TASK | + OG_REST_PARAM_NAME | + OG_REST_PARAM_TIME_YEARS | + OG_REST_PARAM_TIME_MONTHS | + OG_REST_PARAM_TIME_DAYS | + OG_REST_PARAM_TIME_HOURS | + OG_REST_PARAM_TIME_MINUTES | + OG_REST_PARAM_TIME_AM_PM)) + return -1; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + + err = og_dbi_schedule_update(dbi, params); + og_dbi_close(dbi); + + if (err < 0) + return err; + + og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id), + ¶ms->time); + og_schedule_refresh(og_loop); + + return err; +} + +static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params) +{ + struct og_dbi *dbi; + const char *key; + json_t *value; + int err; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "id")) { + err = og_json_parse_string(value, ¶ms->id); + params->flags |= OG_REST_PARAM_ID; + } else { + return -1; + } + + if (err < 0) + break; + } + + if (!og_msg_params_validate(params, OG_REST_PARAM_ID)) + return -1; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + + err = og_dbi_schedule_delete(dbi, atoi(params->id)); + og_dbi_close(dbi); + + og_schedule_delete(og_loop, atoi(params->id)); + + return err; +} + static int og_client_method_not_found(struct og_client *cli) { /* To meet RFC 7231, this function MUST generate an Allow header field @@ -5007,6 +5375,36 @@ static int og_client_state_process_payload_rest(struct og_client *cli) return og_client_bad_request(cli); } err = og_cmd_task_post(root, ¶ms); + } else if (!strncmp(cmd, "schedule/create", + strlen("schedule/create"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command task with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_schedule_create(root, ¶ms); + } else if (!strncmp(cmd, "schedule/delete", + strlen("schedule/delete"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command task with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_schedule_delete(root, ¶ms); + } else if (!strncmp(cmd, "schedule/update", + strlen("schedule/update"))) { + if (method != OG_METHOD_POST) + return og_client_method_not_found(cli); + + if (!root) { + syslog(LOG_ERR, "command task with no payload\n"); + return og_client_bad_request(cli); + } + err = og_cmd_schedule_update(root, ¶ms); } else { syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd); err = og_client_not_found(cli); @@ -6015,9 +6413,10 @@ static int og_socket_server_init(const char *port) int main(int argc, char *argv[]) { struct ev_io ev_io_server, ev_io_server_rest, ev_io_agent_rest; - struct ev_loop *loop = ev_default_loop(0); int i; + og_loop = ev_default_loop(0); + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) exit(EXIT_FAILURE); @@ -6048,21 +6447,26 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); ev_io_init(&ev_io_server, og_server_accept_cb, socket_s, EV_READ); - ev_io_start(loop, &ev_io_server); + ev_io_start(og_loop, &ev_io_server); socket_rest = og_socket_server_init("8888"); if (socket_rest < 0) exit(EXIT_FAILURE); ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ); - ev_io_start(loop, &ev_io_server_rest); + ev_io_start(og_loop, &ev_io_server_rest); socket_agent_rest = og_socket_server_init("8889"); if (socket_agent_rest < 0) exit(EXIT_FAILURE); ev_io_init(&ev_io_agent_rest, og_server_accept_cb, socket_agent_rest, EV_READ); - ev_io_start(loop, &ev_io_agent_rest); + ev_io_start(og_loop, &ev_io_agent_rest); + + if (og_dbi_schedule_get() < 0) + exit(EXIT_FAILURE); + + og_schedule_next(og_loop); infoLog(1); // Inicio de sesiĆ³n @@ -6072,7 +6476,7 @@ int main(int argc, char *argv[]) syslog(LOG_INFO, "Waiting for connections\n"); while (1) - ev_loop(loop, 0); + ev_loop(og_loop, 0); exit(EXIT_SUCCESS); } diff --git a/sources/schedule.c b/sources/schedule.c new file mode 100644 index 0000000..21db921 --- /dev/null +++ b/sources/schedule.c @@ -0,0 +1,394 @@ +#include "schedule.h" +#include "list.h" +#include <sys/types.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <syslog.h> +#include <time.h> +#include <ev.h> + +struct og_schedule *current_schedule = NULL; +static LIST_HEAD(schedule_list); + +static void og_schedule_add(struct og_schedule *new) +{ + struct og_schedule *schedule, *next; + time_t now; + + now = time(NULL); + if (new->seconds < now) { + free(new); + return; + } + list_for_each_entry_safe(schedule, next, &schedule_list, list) { + if (new->seconds < schedule->seconds) { + list_add_tail(&new->list, &schedule->list); + return; + } + } + list_add_tail(&new->list, &schedule_list); +} + +/* Returns the days in a month from the weekday. */ +static void get_days_from_weekday(struct tm *tm, int wday, int *days, int *j) +{ + int i, mday = 0; + + tm->tm_mday = 1; + + //Shift week to start on Sunday instead of Monday + if (wday == 6) + wday = 0; + else + wday++; + + /* A bit bruteforce, but simple. */ + for (i = 0; i <= 30; i++) { + mktime(tm); + /* Not this weekday, skip. */ + if (tm->tm_wday != wday) { + tm->tm_mday++; + continue; + } + /* Not interested in next month. */ + if (tm->tm_mday < mday) + break; + + /* Found a matching. */ + mday = tm->tm_mday; + days[(*j)++] = tm->tm_mday; + tm->tm_mday++; + } +} + +/* Returns the days in the given week. */ +static void get_days_from_week(struct tm *tm, int week, int *days, int *k) +{ + int i, j, week_counter = 0; + bool week_over = false; + + tm->tm_mday = 1; + + /* Remaining days of this month. */ + for (i = 0; i <= 30; i++) { + mktime(tm); + + /* Last day of this week? */ + if (tm->tm_wday == 6) + week_over = true; + + /* Not the week we are searching for. */ + if (week != week_counter) { + tm->tm_mday++; + if (week_over) { + week_counter++; + week_over = false; + } + continue; + } + + /* Found matching. */ + for (j = tm->tm_wday; j <= 6; j++) { + days[(*k)++] = tm->tm_mday++; + mktime(tm); + } + break; + } +} + +static int monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +static int last_month_day(struct tm *tm) +{ + /* Leap year? Adjust it. */ + if (tm->tm_mon == 1) { + tm->tm_mday = 29; + mktime(tm); + if (tm->tm_mday == 29) + return 29; + + tm->tm_mon = 1; + } + + return monthdays[tm->tm_mon]; +} + +/* Returns the days in the given week. */ +static void get_last_week(struct tm *tm, int *days, int *j) +{ + int i, last_day; + + last_day = last_month_day(tm); + tm->tm_mday = last_day; + + for (i = last_day; i >= last_day - 6; i--) { + mktime(tm); + + days[(*j)++] = tm->tm_mday; + + + syslog(LOG_ERR, "TM_WDAY: %d", tm->tm_wday);//XXX + syslog(LOG_ERR, "TM_MDAY: %d", tm->tm_mday);//XXX + /* Last day of this week? */ + if (tm->tm_wday == 1) { + syslog(LOG_ERR, "break week");//XXX + break; + } + + tm->tm_mday--; + } +} + +static void og_parse_years(uint16_t years_mask, int years[]) +{ + int i, j = 0; + + for (i = 0; i < 16; i++) { + if ((1 << i) & years_mask) + years[j++] = 2010 + i - 1900; + } +} + +static void og_parse_months(uint16_t months_mask, int months[]) +{ + int i, j = 0; + + for (i = 0; i < 12; i++) { + if ((1 << i) & months_mask) + months[j++] = i + 1; + } +} + +static void og_parse_days(uint32_t days_mask, int *days) +{ + int i, j = 0; + + for (i = 0; i < 31; i++) { + if ((1 << i) & days_mask) + days[j++] = i + 1; + } +} + +static void og_parse_hours(uint16_t hours_mask, uint8_t am_pm, int hours[]) +{ + int pm = 12 * am_pm; + int i, j = 0; + + for (i = 0; i < 12; i++) { + if ((1 << i) & hours_mask) + hours[j++] = i + pm + 1; + } +} + +static void og_schedule_remove_duplicates() +{ + struct og_schedule *schedule, *next, *prev = NULL; + + list_for_each_entry_safe(schedule, next, &schedule_list, list) { + if (!prev) { + prev = schedule; + continue; + } + if (prev->seconds == schedule->seconds && + prev->task_id == schedule->task_id) { + list_del(&prev->list); + free(prev); + } + prev = schedule; + } +} + +void og_schedule_create(unsigned int schedule_id, unsigned int task_id, + struct og_schedule_time *time) +{ + struct og_schedule *schedule; + int months[12] = {}; + int years[12] = {}; + int hours[12] = {}; + int days[31] = {}; + struct tm tm = {}; + int i, j, k, l = 0; + int minutes; + + og_parse_years(time->years, years); + og_parse_months(time->months, months); + og_parse_days(time->days, days); + og_parse_hours(time->hours, time->am_pm, hours); + minutes = time->minutes; + + for (i = 0; years[i] != 0 && i < 12; i++) { + for (j = 0; months[j] != 0 && j < 12; j++) { + memset(&tm, 0, sizeof(tm)); + tm.tm_year = years[i]; + tm.tm_mon = months[j] - 1; + if (time->week_days) { + for (int wday = 0; wday < 7; wday++) { + if ((1 << wday) & time->week_days) { + int specific_month_days[5] = {}; + int n_month_days = 0; + get_days_from_weekday(&tm, + wday, + specific_month_days, + &n_month_days); + + for (k = 0; specific_month_days[k] != 0 && k < n_month_days; k++) { + for (l = 0; hours[l] != 0 && l < 31; l++) { + schedule = (struct og_schedule *) + calloc(1, sizeof(struct og_schedule)); + if (!schedule) + return; + + memset(&tm, 0, sizeof(tm)); + tm.tm_year = years[i]; + tm.tm_mon = months[j] - 1; + tm.tm_mday = specific_month_days[k]; + tm.tm_hour = hours[l] - 1; + tm.tm_min = minutes; + + schedule->seconds = mktime(&tm); + schedule->task_id = task_id; + schedule->schedule_id = schedule_id; + og_schedule_add(schedule); + } + } + } + } + } + + if (time->weeks) { + for (int week = 0; week < 5; week++) { + if ((1 << week) & time->weeks) { + int specific_month_days[7] = {}; + int n_month_days = 0; + + if (week == 5) + get_last_week(&tm, + specific_month_days, + &n_month_days); + else + get_days_from_week(&tm, + week, + specific_month_days, + &n_month_days); + + for (k = 0; specific_month_days[k] != 0 && k < n_month_days; k++) { + for (l = 0; hours[l] != 0 && l < 31; l++) { + schedule = (struct og_schedule *) + calloc(1, sizeof(struct og_schedule)); + if (!schedule) + return; + + memset(&tm, 0, sizeof(tm)); + tm.tm_year = years[i]; + tm.tm_mon = months[j] - 1; + tm.tm_mday = specific_month_days[k]; + tm.tm_hour = hours[l] - 1; + tm.tm_min = minutes; + + schedule->seconds = mktime(&tm); + schedule->task_id = task_id; + schedule->schedule_id = schedule_id; + og_schedule_add(schedule); + } + } + } + } + } + + if (time->days) { + for (k = 0; days[k] != 0 && k < 31; k++) { + for (l = 0; hours[l] != 0 && l < 31; l++) { + schedule = (struct og_schedule *) + calloc(1, sizeof(struct og_schedule)); + if (!schedule) + return; + + memset(&tm, 0, sizeof(tm)); + tm.tm_year = years[i]; + tm.tm_mon = months[j] - 1; + tm.tm_mday = days[k]; + tm.tm_hour = hours[l] - 1; + tm.tm_min = minutes; + + schedule->seconds = mktime(&tm); + schedule->task_id = task_id; + schedule->schedule_id = schedule_id; + og_schedule_add(schedule); + } + } + } + } + } + + og_schedule_remove_duplicates(); +} + +void og_schedule_delete(struct ev_loop *loop, uint32_t schedule_id) +{ + struct og_schedule *schedule, *next; + + list_for_each_entry_safe(schedule, next, &schedule_list, list) { + if (schedule->schedule_id != schedule_id) + continue; + + list_del(&schedule->list); + if (current_schedule == schedule) { + ev_timer_stop(loop, &schedule->timer); + current_schedule = NULL; + og_schedule_refresh(loop); + } + free(schedule); + } +} + +void og_schedule_update(struct ev_loop *loop, unsigned int schedule_id, + unsigned int task_id, struct og_schedule_time *time) +{ + og_schedule_delete(loop, schedule_id); + og_schedule_create(schedule_id, task_id, time); +} + +static void og_agent_timer_cb(struct ev_loop *loop, ev_timer *timer, int events) +{ + struct og_schedule *current; + + current = container_of(timer, struct og_schedule, timer); + og_dbi_schedule_task(current->task_id); + + ev_timer_stop(loop, timer); + list_del(¤t->list); + free(current); + + og_schedule_next(loop); +} + +void og_schedule_next(struct ev_loop *loop) +{ + struct og_schedule *schedule; + time_t now, seconds; + + if (list_empty(&schedule_list)) { + current_schedule = NULL; + return; + } + + schedule = list_first_entry(&schedule_list, struct og_schedule, list); + now = time(NULL); + if (schedule->seconds <= now) + seconds = 0; + else + seconds = schedule->seconds - now; + + ev_timer_init(&schedule->timer, og_agent_timer_cb, seconds, 0.); + ev_timer_start(loop, &schedule->timer); + current_schedule = schedule; +} + +void og_schedule_refresh(struct ev_loop *loop) +{ + if (current_schedule) + ev_timer_stop(loop, ¤t_schedule->timer); + + og_schedule_next(loop); +} diff --git a/sources/schedule.h b/sources/schedule.h new file mode 100644 index 0000000..7195a05 --- /dev/null +++ b/sources/schedule.h @@ -0,0 +1,37 @@ +#ifndef _OG_SCHEDULE_H_ +#define _OG_SCHEDULE_H_ + +#include <stdint.h> +#include "dbi.h" +#include "list.h" +#include <ev.h> + +struct og_schedule_time { + uint32_t years; + uint32_t months; + uint32_t weeks; + uint32_t week_days; + uint32_t days; + uint32_t hours; + uint32_t am_pm; + uint32_t minutes; +}; + +struct og_schedule { + struct list_head list; + struct ev_timer timer; + time_t seconds; + unsigned int task_id; + unsigned int schedule_id; +}; + +void og_schedule_create(unsigned int schedule_id, unsigned int task_id, + struct og_schedule_time *time); +void og_schedule_update(struct ev_loop *loop, unsigned int schedule_id, + unsigned int task_id, struct og_schedule_time *time); +void og_schedule_delete(struct ev_loop *loop, uint32_t schedule_id); +void og_schedule_next(struct ev_loop *loop); +void og_schedule_refresh(struct ev_loop *loop); +void og_dbi_schedule_task(unsigned int task_id); + +#endif |