300 lines
5.3 KiB
C++
300 lines
5.3 KiB
C++
#include <iostream>
|
|
#include <list>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <random>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <stdint.h>
|
|
|
|
#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<device> m_devices;
|
|
map<string, list<device>::iterator> m_by_id;
|
|
map<string, list<device>::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<httplib::Server> server = nullptr;
|
|
|
|
bool ok;
|
|
json cfg;
|
|
json devs;
|
|
vector<device> 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<httplib::Server>();
|
|
}
|
|
|
|
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<device*>(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;
|
|
}
|