#include #include #include #include #include #include #include #include #include "httplib.h" #include "json.hpp" #include "helpers.h" using nlohmann::json; using namespace std; struct device { string id; string api_key; string friendly_id; int refresh_rate; // Default constructor device() : id(""), api_key(""), friendly_id(""), refresh_rate(600) {} }; void to_json(json& j, const device& d) { j = json{ {"ID", d.id}, {"api_key", d.api_key}, {"friendly_id", d.friendly_id}, {"refresh_rate", d.refresh_rate} }; } bool json_extract(const json& j, const string& key, device& out) { bool result = false; if (!key.empty()) { if (j.contains(key) && j[key].is_object()) { result |= json_extract(j[key], "ID", out.id); result |= json_extract(j[key], "api_key", out.api_key); result |= json_extract(j[key], "friendly_id", out.friendly_id); result |= json_extract(j[key], "refresh_rate", out.refresh_rate); } } else { result |= json_extract(j, "ID", out.id); result |= json_extract(j, "api_key", out.api_key); result |= json_extract(j, "friendly_id", out.friendly_id); result |= json_extract(j, "refresh_rate", out.refresh_rate); } return result; } string device_id_to_friendly(string id) { size_t pos = id.find(':'); while (pos != string::npos) { id.erase(pos, 1); pos = id.find(':'); } if (id.size() <= 6) { return id; } else { return id.substr(id.size() - 6); } } class DeviceContainer { private: list m_devices; map::iterator> m_by_id; map::iterator> m_by_friendly; public: DeviceContainer() = default; void add_device(const device& d) { if (d.id.empty()) { return; } auto it = m_devices.insert(m_devices.end(), d); m_by_id.insert(make_pair(it->id, it)); if (!it->friendly_id.empty()) { m_by_friendly.insert(make_pair(it->friendly_id, it)); } } const device* get_device_by_id(const string& id) { if (0 == m_by_id.count(id)) { return nullptr; } else { return &(*(*(m_by_id.find(id))).second); } } const device* get_device_by_friendly(const string& friendly) { if (0 == m_by_friendly.count(friendly)) { return nullptr; } else { return &(*(*(m_by_friendly.find(friendly))).second); } } void set_device_friendly(const string& id, const string& friendly) { if (0 == m_by_id.count(id)) { return; } auto it = m_by_id[id]; it->friendly_id = friendly; m_by_friendly.insert(make_pair(it->friendly_id, it)); } }; int main(int argc, char **argv) { string config_filename = "config.json"; string devices_filename = "devices.json"; string host = ""; string cert_file = ""; string key_file = ""; uint16_t port = 0; shared_ptr server = nullptr; bool ok; json cfg; json devs; vector devices; DeviceContainer container; if (argc > 2) { config_filename = argv[1]; } ok = read_file_json(cfg, config_filename, &cout); if (!ok) { return -1; } json_extract(cfg, "devices_filename", devices_filename); json_extract(cfg, "host", host); json_extract(cfg, "port", port); // json_extract(cfg, "cert_file", cert_file); // json_extract(cfg, "key_file", cert_file); if (host.empty()) { cout << "host not provided" << endl; return -1; } if (0 == port) { cout << "port number not provided" << endl; return -1; } if (!cert_file.empty() && !key_file.empty()) { // TODO: Implement SSL Server Properly } else { server = make_shared(); } ok = read_file_json(devs, devices_filename, &cout); if (!ok) { return -1; } if (devs.is_array()) { for (int i = 0; i < devs.size(); ++i) { device d; json_extract(devs[i], "", d); devices.push_back(d); } } for (auto device : devices) { container.add_device(device); } auto setup_handler = [&container](const httplib::Request& req, httplib::Response& res) { if (req.has_header("ID")) { json response; string id = req.get_header_value("ID"); const device* dev = container.get_device_by_id(id); if (nullptr == dev) { res.status = 404; response["status"] = 404; response["api_key"] = nullptr; response["friendly_id"] = nullptr; response["image_url"] = nullptr; response["filename"] = nullptr; res.body = response.dump(); } else { res.status = 200; if (dev->friendly_id.empty()) { container.set_device_friendly(id, device_id_to_friendly(id)); } device* dev_mut = const_cast(dev); response["status"] = 200; response["api_key"] = "nullptr"; response["friendly_id"] = dev->friendly_id; response["image_url"] = "https://trmnl.com/images/setup/setup-logo.bmp"; response["filename"] = "welcome"; res.body = response.dump(); json test = *dev_mut; cout << test.dump(4) << endl; } } else { res.status = 500; } }; auto log_handler = [](const httplib::Request& req, httplib::Response& res) { try { json j = json::parse(req.body); cout << j.dump(4) << endl; } catch (const exception& e) { cout << req.body << endl; } res.status = 200; }; server->Get("/api/setup/", setup_handler); server->Get("/api/setup", setup_handler); server->Post("/api/log/", log_handler); server->Post("/api/log", log_handler); server->listen(host, port); return 0; }