Skip to content

Commit 952d4f4

Browse files
committed
Implement Readings endpoint for read
1 parent f91f8b3 commit 952d4f4

23 files changed

+652
-0
lines changed

CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
cmake_minimum_required(VERSION 3.19)
2+
project(developer_joyofenergy_cpp_beast)
3+
4+
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
5+
set(CMAKE_CXX_STANDARD 17)
6+
7+
add_subdirectory(rest)
8+
add_executable(app main.cpp)
9+
target_link_libraries(app PRIVATE rest)
10+
11+
enable_testing()
12+
add_subdirectory(test)

conanfile.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[requires]
2+
boost/1.76.0
3+
gtest/1.11.0
4+
nlohmann_json/3.9.1
5+
6+
[generators]
7+
cmake_find_package
8+
9+
[options]
10+
boost:header_only=True

main.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <iostream>
2+
3+
#include "rest/server.h"
4+
5+
int main(int argc, char *argv[]) {
6+
if (argc != 4) {
7+
std::cerr << "Usage: app <address> <kPort> <concurrency>\n"
8+
<< "Example:\n"
9+
<< " http-server-async 0.0.0.0 8080 1\n";
10+
return EXIT_FAILURE;
11+
}
12+
auto const address = argv[1];
13+
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
14+
auto const threads = std::max<int>(1, std::atoi(argv[3]));
15+
server a{threads};
16+
a.run(address, port);
17+
char wait;
18+
std::cin >> wait;
19+
return EXIT_SUCCESS;
20+
}

rest/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
add_subdirectory(service)
2+
add_subdirectory(controller)
3+
add_library(rest)
4+
target_sources(rest PRIVATE server.cpp)
5+
target_include_directories(rest INTERFACE ..)
6+
target_link_libraries(rest PUBLIC controller)

rest/configuration.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef DEVELOPER_JOYOFENERGY_CPP_BEAST_CONFIGURATION_H
2+
#define DEVELOPER_JOYOFENERGY_CPP_BEAST_CONFIGURATION_H
3+
4+
#include <domain/ElectricityReading.h>
5+
#include <domain/PricePlan.h>
6+
7+
#include "generator.h"
8+
9+
constexpr auto DR_EVILS_DARK_ENERGY_ENERGY_SUPPLIER = "Dr Evil's Dark Energy";
10+
constexpr auto THE_GREEN_ECO_ENERGY_SUPPLIER = "The Green Eco";
11+
constexpr auto POWER_FOR_EVERYONE_ENERGY_SUPPLIER = "Power for Everyone";
12+
13+
constexpr auto MOST_EVIL_PRICE_PLAN_ID = "price-plan-0";
14+
constexpr auto RENEWABLES_PRICE_PLAN_ID = "price-plan-1";
15+
constexpr auto STANDARD_PRICE_PLAN_ID = "price-plan-2";
16+
17+
constexpr auto SARAHS_SMART_METER_ID = "smart-meter-0";
18+
constexpr auto PETERS_SMART_METER_ID = "smart-meter-1";
19+
constexpr auto CHARLIES_SMART_METER_ID = "smart-meter-2";
20+
constexpr auto ANDREAS_SMART_METER_ID = "smart-meter-3";
21+
constexpr auto ALEXS_SMART_METER_ID = "smart-meter-4";
22+
23+
std::vector<PricePlan> price_plans() {
24+
// todo
25+
// pricePlans.add(new PricePlan(MOST_EVIL_PRICE_PLAN_ID, "Dr Evil's Dark Energy", BigDecimal.TEN, emptyList()));
26+
// pricePlans.add(new PricePlan(RENEWABLES_PRICE_PLAN_ID, "The Green Eco", BigDecimal.valueOf(2), emptyList()));
27+
// pricePlans.add(new PricePlan(STANDARD_PRICE_PLAN_ID, "Power for Everyone", BigDecimal.ONE, emptyList()));
28+
return {};
29+
}
30+
31+
std::unordered_map<std::string, std::string> smart_meter_to_price_plan_accounts() {
32+
return {{SARAHS_SMART_METER_ID, MOST_EVIL_PRICE_PLAN_ID},
33+
{PETERS_SMART_METER_ID, RENEWABLES_PRICE_PLAN_ID},
34+
{CHARLIES_SMART_METER_ID, MOST_EVIL_PRICE_PLAN_ID},
35+
{ANDREAS_SMART_METER_ID, STANDARD_PRICE_PLAN_ID},
36+
{ALEXS_SMART_METER_ID, RENEWABLES_PRICE_PLAN_ID}};
37+
};
38+
39+
auto readings() {
40+
std::unordered_map<std::string, std::vector<ElectricityReading>> result;
41+
for (auto &[meter, plan] : smart_meter_to_price_plan_accounts()) {
42+
result[meter] = generator{}.generate(20);
43+
}
44+
return result;
45+
}
46+
47+
#endif // DEVELOPER_JOYOFENERGY_CPP_BEAST_CONFIGURATION_H

rest/controller/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
add_library(controller INTERFACE)
2+
find_package(Boost REQUIRED)
3+
find_package(nlohmann_json REQUIRED)
4+
target_link_libraries(controller INTERFACE Boost::headers nlohmann_json::nlohmann_json service)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#ifndef DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGCONTROLLER_H
2+
#define DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGCONTROLLER_H
3+
4+
#include <service/ElectricityReadingService.h>
5+
6+
#include <ctime>
7+
#include <iomanip>
8+
9+
#include <boost/beast/http.hpp>
10+
#include <nlohmann/json.hpp>
11+
12+
namespace http = boost::beast::http;
13+
14+
namespace detail {
15+
auto toRfc3339(std::chrono::time_point<std::chrono::system_clock> time) {
16+
std::stringstream ss;
17+
const auto ctime = std::chrono::system_clock::to_time_t(time);
18+
ss << std::put_time(std::gmtime(&ctime), "%FT%T");
19+
return ss.str();
20+
}
21+
22+
auto renderReadingAsJson(const ElectricityReading &r) {
23+
return nlohmann::json{{"time", toRfc3339(r.getTime())},
24+
{"reading", r.getReading()}};
25+
}
26+
} // namespace detail
27+
28+
class MeterReadingController {
29+
public:
30+
MeterReadingController(ElectricityReadingService &meterReadingService) : meterReadingService(meterReadingService) {}
31+
32+
http::response<http::string_body>
33+
Read(const http::request<http::string_body> &req, const std::vector<std::string> &queries) {
34+
const auto &meterId = queries[0];
35+
auto readings = meterReadingService.GetReading(meterId);
36+
37+
if (!readings) {
38+
return {http::status::not_found, req.version()};
39+
}
40+
http::response<http::string_body> res{http::status::ok, req.version()};
41+
res.set(http::field::content_type, "application/json");
42+
res.keep_alive(req.keep_alive());
43+
auto results = nlohmann::json::array();
44+
std::transform(readings->begin(), readings->end(), std::back_inserter(results), &detail::renderReadingAsJson);
45+
nlohmann::json j;
46+
j["readings"] = results;
47+
res.body() = j.dump();
48+
res.prepare_payload();
49+
return res;
50+
}
51+
52+
private:
53+
ElectricityReadingService &meterReadingService;
54+
};
55+
56+
#endif // DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGCONTROLLER_H

rest/domain/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
add_library(domain INTERFACE)
2+
target_include_directories(domain INTERFACE ..)

rest/domain/ElectricityReading.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#ifndef DEVELOPER_JOYOFENERGY_CPP_BEAST_ELECTRICITYREADING_H
2+
#define DEVELOPER_JOYOFENERGY_CPP_BEAST_ELECTRICITYREADING_H
3+
4+
#include <chrono>
5+
#include <ctime>
6+
7+
class ElectricityReading {
8+
public:
9+
using time_point_type = std::chrono::time_point<std::chrono::system_clock>;
10+
11+
ElectricityReading(time_point_type time, size_t reading) : time(time), reading(reading) {}
12+
13+
time_point_type getTime() const { return time; }
14+
15+
size_t getReading() const { return reading; }
16+
17+
private:
18+
time_point_type time;
19+
size_t reading;
20+
};
21+
22+
#endif // DEVELOPER_JOYOFENERGY_CPP_BEAST_ELECTRICITYREADING_H

rest/domain/PricePlan.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLAN_H
2+
#define DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLAN_H
3+
4+
class PricePlan {
5+
// todo:
6+
};
7+
8+
#endif // DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLAN_H

0 commit comments

Comments
 (0)