From 10e41ca166f8dcb08c910004312cfab6f43bf1ad Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Thu, 7 May 2020 01:38:13 +0200
Subject: [PATCH] add: commands fix: timezone problem

---
 command.c                                     | 136 ++++++++++++++++++
 endpoints/api_v1_controllers_STR.c            |  13 +-
 endpoints/api_v1_controllers_STR_relays_INT.c |  22 ++-
 endpoints/api_v1_controllers_discover.c       |   1 +
 endpoints/api_v1_schedules_STR.c              |   3 +
 helpers/get_day_of_week.c                     |  12 --
 helpers/get_weekday.c                         |  11 ++
 include/command.h                             |  16 +++
 include/helpers.h                             |   3 +-
 models/controller.c                           |   9 +-
 models/relay.c                                |   4 +-
 11 files changed, 209 insertions(+), 21 deletions(-)
 create mode 100644 command.c
 delete mode 100644 helpers/get_day_of_week.c
 create mode 100644 helpers/get_weekday.c
 create mode 100644 include/command.h

diff --git a/command.c b/command.c
new file mode 100644
index 0000000..73cbaa5
--- /dev/null
+++ b/command.c
@@ -0,0 +1,136 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include <command.h>
+#include <mpack.h>
+#include <logger.h>
+#include <helpers.h>
+#include <enums.h>
+#include <models/controller.h>
+
+int
+command_set_relay_schedule(relay_t *relay)
+{
+    controller_t *controller = controller_get_by_id(relay->controller_id);
+    if(!controller)
+    {
+        LOG_ERROR("couldn't find controller\n");
+        return 1;
+    }
+
+    char* payload;
+    size_t payload_size;
+    mpack_writer_t writer;
+    mpack_writer_init_growable(&writer, &payload, &payload_size);
+
+    // 3 = code, relay num, relay name, schedules(array)
+    mpack_start_map(&writer, 3);
+
+    mpack_write_uint(&writer, COMMAND_MAPPING_CODE);
+    mpack_write_u8(&writer, COMMAND_CODE_SET_SCHEDULE);
+
+    mpack_write_uint(&writer, COMMAND_MAPPING_RELAY_NUM);
+    mpack_write_u8(&writer, relay->number);
+
+    mpack_write_uint(&writer, COMMAND_MAPPING_SCHEDULES_ARRAY);
+    // 7 = days of week
+    mpack_start_array(&writer, 7);
+    for(int i = 0; i < 7; ++i)
+    {
+        uint16_t *periods_blob = schedule_periods_to_blob(relay->schedules[i]);
+        uint16_t periods_count = periods_blob[0];
+
+        // 3 = code, relaynum, schedules(array)
+        mpack_start_map(&writer, 3);
+
+        mpack_write_uint(&writer, COMMAND_MAPPING_PERIODS_COUNT);
+        mpack_write_u16(&writer, periods_count);
+
+        mpack_write_uint(&writer, COMMAND_MAPPING_SCHEDULE_ID);
+        mpack_write_bin(&writer, (char*)relay->schedules[0]->uid, sizeof(uuid_t));
+
+        mpack_write_uint(&writer, COMMAND_MAPPING_PERIODS_BLOB);
+        // periods + 1 to skip length in periods[0]
+        // periods_count * 2 because each uint16_t is a timestamp. 2 are start and end
+        mpack_write_bin(&writer, (char*)(periods_blob + 1), sizeof(uint16_t) * periods_count * 2);
+
+        mpack_finish_map(&writer);
+
+        free(periods_blob);
+    }
+    mpack_finish_array(&writer);
+
+    mpack_finish_map(&writer);
+
+    // finish writing
+    if (mpack_writer_destroy(&writer) != mpack_ok)
+    {
+        LOG_ERROR("an error occurred encoding the data");
+        controller_free(controller);
+        return 1;
+    }
+
+    int result = command_send(controller, COMMAND_CODE_SET_SCHEDULE, payload, payload_size);
+
+    controller_free(controller);
+    return result;
+}
+
+int
+command_set_controller_name(controller_t *controller)
+{
+    char* payload;
+    size_t payload_size;
+    mpack_writer_t writer;
+    mpack_writer_init_growable(&writer, &payload, &payload_size);
+
+    // write the example on the msgpack homepage
+    mpack_start_map(&writer, 2);
+
+    mpack_write_uint(&writer, COMMAND_MAPPING_CODE);
+    mpack_write_u8(&writer, COMMAND_CODE_SET_NAME);
+
+    mpack_write_uint(&writer, COMMAND_MAPPING_NAME);
+    mpack_write_cstr(&writer, controller->name);
+
+    mpack_finish_map(&writer);
+
+    // finish writing
+    if (mpack_writer_destroy(&writer) != mpack_ok)
+    {
+        LOG_ERROR("an error occurred encoding the data");
+        return 1;
+    }
+    return command_send(controller, COMMAND_CODE_SET_NAME, payload, payload_size);
+}
+    
+int
+command_send(controller_t *controller, int command_code, char *payload, uint32_t payload_size)
+{
+    LOG_DEBUG("commanding %d\n", command_code);
+
+    int bytes_transferred;
+
+    int fd_controller = helper_connect_tcp_server(controller->ip, controller->port);
+
+    if(fd_controller == -1)
+    {
+        LOG_ERROR("can't open command socket %s:%d\n", controller->ip, controller->port);
+        return 1;
+    }
+
+    if((bytes_transferred = send(fd_controller, &payload_size, sizeof(payload_size), 0)) <= 0)
+    {
+        LOG_ERROR("error during sending size\n");
+        return 1;
+    }
+    if((bytes_transferred = send(fd_controller, payload, payload_size, 0)) <= 0)
+    {
+        LOG_ERROR("error during sending\n");
+        return 1;
+    }
+
+    close(fd_controller);
+    return 0;
+}
diff --git a/endpoints/api_v1_controllers_STR.c b/endpoints/api_v1_controllers_STR.c
index c6646c7..1e3d7a9 100644
--- a/endpoints/api_v1_controllers_STR.c
+++ b/endpoints/api_v1_controllers_STR.c
@@ -1,4 +1,5 @@
 #include <cJSON.h>
+#include <command.h>
 #include <constants.h>
 #include <endpoints/api_v1_controllers.h>
 #include <logger.h>
@@ -114,16 +115,24 @@ api_v1_controllers_STR_PUT(struct mg_connection *c, endpoint_args_t *args, struc
     cJSON_Delete(json);
     json = controller_to_json(controller);
 
+    int result = command_set_controller_name(controller);
+    int status_code = 200;
+
+    if(result)
+    {
+        status_code = 504;
+    }
+
     char *json_str = cJSON_Print(json);
     if (json_str == NULL)
     {
         LOG_ERROR("failed to print controller json\n");
-        mg_send_head(c, 200, 2, "Content-Type: application/json\r\n" STANDARD_HEADERS);
+        mg_send_head(c, status_code, 2, "Content-Type: application/json\r\n" STANDARD_HEADERS);
         mg_printf(c, "{}");
     }
     else
     {
-        mg_send_head(c, 200, strlen(json_str), "Content-Type: application/json\r\n" STANDARD_HEADERS);
+        mg_send_head(c, status_code, strlen(json_str), "Content-Type: application/json\r\n" STANDARD_HEADERS);
         mg_printf(c, "%s", json_str);
         free(json_str);
     }
diff --git a/endpoints/api_v1_controllers_STR_relays_INT.c b/endpoints/api_v1_controllers_STR_relays_INT.c
index 7bdc2d1..601686f 100644
--- a/endpoints/api_v1_controllers_STR_relays_INT.c
+++ b/endpoints/api_v1_controllers_STR_relays_INT.c
@@ -1,4 +1,5 @@
 #include <cJSON.h>
+#include <command.h>
 #include <constants.h>
 #include <endpoints/api_v1_controllers.h>
 #include <logger.h>
@@ -104,7 +105,9 @@ api_v1_controllers_STR_relays_INT_PUT(struct mg_connection *c, endpoint_args_t *
         {
             relay->schedules[i] = schedule_get_by_uid(tmp_uuid);
         }
-        relay->active_schedule = schedule_get_by_uid(tmp_uuid);
+        time_t timestamp = time(NULL);
+        struct tm *time_struct = localtime(&timestamp);
+        relay->active_schedule = relay->schedules[helper_get_weekday(time_struct)];
     }
 
     cJSON *json = cJSON_ParseWithLength(hm->body.p, hm->body.len);
@@ -169,7 +172,10 @@ api_v1_controllers_STR_relays_INT_PUT(struct mg_connection *c, endpoint_args_t *
         cJSON *json_active_schedule_uid = cJSON_GetObjectItemCaseSensitive(json_active_schedule, "id");
         if(cJSON_IsString(json_active_schedule_uid) && json_active_schedule_uid->valuestring)
         {
-            int day_of_week = helper_get_weekday(time(NULL));
+            time_t timestamp = time(NULL);
+            struct tm *time_struct = localtime(&timestamp);
+            int day_of_week = helper_get_weekday(time_struct);
+
             schedule_free(relay->schedules[day_of_week]);
 
             uuid_t target_uid;
@@ -220,16 +226,24 @@ api_v1_controllers_STR_relays_INT_PUT(struct mg_connection *c, endpoint_args_t *
     cJSON_Delete(json);
     json = relay_to_json(relay);
 
+    int result = command_set_relay_schedule(relay);
+    int status_code = 200;
+
+    if(result)
+    {
+        status_code = 504;
+    }
+
     char *json_str = cJSON_Print(json);
     if (json_str == NULL)
     {
         LOG_ERROR("failed to print relay json\n");
-        mg_send_head(c, 200, 2, "Content-Type: application/json\r\n" STANDARD_HEADERS);
+        mg_send_head(c, status_code, 2, "Content-Type: application/json\r\n" STANDARD_HEADERS);
         mg_printf(c, "{}");
     }
     else
     {
-        mg_send_head(c, 200, strlen(json_str), "Content-Type: application/json\r\n" STANDARD_HEADERS);
+        mg_send_head(c, status_code, strlen(json_str), "Content-Type: application/json\r\n" STANDARD_HEADERS);
         mg_printf(c, "%s", json_str);
         free(json_str);
     }
diff --git a/endpoints/api_v1_controllers_discover.c b/endpoints/api_v1_controllers_discover.c
index 971dd8b..94a954c 100644
--- a/endpoints/api_v1_controllers_discover.c
+++ b/endpoints/api_v1_controllers_discover.c
@@ -244,6 +244,7 @@ api_v1_controllers_discover_POST(struct mg_connection *c, endpoint_args_t *args,
                 discovered_controller->active = 1;
 
                 controller_save(discovered_controller);
+                controller_free(discovered_controller);
             }
             mpack_tree_destroy(&tree);
             free(answer_payload);
diff --git a/endpoints/api_v1_schedules_STR.c b/endpoints/api_v1_schedules_STR.c
index 6643ccd..a87d51a 100644
--- a/endpoints/api_v1_schedules_STR.c
+++ b/endpoints/api_v1_schedules_STR.c
@@ -83,6 +83,9 @@ api_v1_schedules_STR_PUT(struct mg_connection *c, endpoint_args_t *args, struct
             LOG_ERROR("error before: %s\n", error_ptr);
         }
         cJSON_Delete(json);
+        mg_send_head(c, 400, 2, "Content-Type: application/json\r\n" STANDARD_HEADERS);
+        mg_printf(c, "{}");
+        return;
     }
 
     cJSON *json_name = cJSON_GetObjectItemCaseSensitive(json, "name");
diff --git a/helpers/get_day_of_week.c b/helpers/get_day_of_week.c
deleted file mode 100644
index 0214f63..0000000
--- a/helpers/get_day_of_week.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <time.h>
-
-#include <helpers.h>
-
-int
-helper_get_weekday(const time_t timestamp_now)
-{
-    struct tm *now = localtime(&timestamp_now);
-    int wday_sun_sat = now->tm_wday;
-    int wday_mon_sun = (wday_sun_sat + 6) % 7;
-    return wday_mon_sun;
-}
diff --git a/helpers/get_weekday.c b/helpers/get_weekday.c
new file mode 100644
index 0000000..68f029e
--- /dev/null
+++ b/helpers/get_weekday.c
@@ -0,0 +1,11 @@
+#include <time.h>
+
+#include <helpers.h>
+
+int
+helper_get_weekday(const struct tm *time_struct)
+{
+    int wday_sun_sat = time_struct->tm_wday;
+    int wday_mon_sun = (wday_sun_sat + 6) % 7;
+    return wday_mon_sun;
+}
diff --git a/include/command.h b/include/command.h
new file mode 100644
index 0000000..01b045f
--- /dev/null
+++ b/include/command.h
@@ -0,0 +1,16 @@
+#ifndef CORE_COMMAND_H
+#define CORE_COMMAND_H
+
+#include <models/controller.h>
+#include <models/relay.h>
+
+int
+command_set_relay_schedule(relay_t *relay);
+
+int
+command_set_controller_name(controller_t *controller);
+
+int
+command_send(controller_t *controller, int command_code, char *payload, uint32_t payload_size);
+
+#endif /* CORE_COMMAND_H */
diff --git a/include/helpers.h b/include/helpers.h
index a958bd5..f382679 100644
--- a/include/helpers.h
+++ b/include/helpers.h
@@ -1,6 +1,7 @@
 #ifndef CORE_HELPERS_H
 #define CORE_HELPERS_H
 
+#include <time.h>
 #include <config.h>
 #include <confini.h>
 
@@ -29,6 +30,6 @@ void
 helper_parse_cli(int argc, const char **argv, config_t *config);
 
 int
-helper_get_weekday(const time_t timestamp_now);
+helper_get_weekday(const struct tm *time_struct);
 
 #endif /* CORE_HELPERS_H */
diff --git a/models/controller.c b/models/controller.c
index 7ad9be7..3007159 100644
--- a/models/controller.c
+++ b/models/controller.c
@@ -235,7 +235,14 @@ controller_to_json(controller_t *controller)
     }
     cJSON_AddItemToObject(json, "active", json_active);
 
-    //TODO add relays
+    relay_t **relays = relay_get_by_controller_id(controller->id);
+    cJSON *json_relays = cJSON_CreateArray();
+    for(int i = 0; relays[i] != NULL; ++i)
+    {
+        cJSON_AddItemToArray(json_relays, relay_to_json(relays[i]));
+    }
+    cJSON_AddItemToObject(json, "relays", json_relays);
+    relay_free_list(relays);
 
     return json;
 }
diff --git a/models/relay.c b/models/relay.c
index d86e0f9..e876624 100644
--- a/models/relay.c
+++ b/models/relay.c
@@ -169,7 +169,9 @@ relay_remove(relay_t *relay)
 void
 relay_reload_active_schedule(relay_t *relay)
 {
-    relay->active_schedule = relay->schedules[helper_get_weekday(time(NULL))];
+    time_t timestamp = time(NULL);
+    struct tm *time_struct = localtime(&timestamp);
+    relay->active_schedule = relay->schedules[helper_get_weekday(time_struct)];
 }
 
 void