trainings/CreatingReliableSoftwareCpp/Presentation/examples/refactoring/refactoring.cpp

216 lines
5.4 KiB
C++

#include <algorithm>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>
#include <variant>
#include <vector>
struct Credentail {
int cert_;
};
struct Download {
enum ConnectionType { Telnet,
Ssh };
std::string url_;
Credentail credentail_;
int maxMbps_;
bool cache_;
ConnectionType type_;
};
struct Upload {
enum ConnectionType { Telnet,
Ssh };
std::string url_;
Credentail credentail_;
int maxMbps_;
int size_;
ConnectionType type_;
};
struct RemoveFromCache {
std::string url_;
};
struct ClearCache {
};
struct Image {
std::vector<uint8_t> bitmap_;
};
class Server {
public:
void handle(const Download& request, void (*callback)(bool, Image)) {
Image image;
for (const auto& pair : cache_) {
if (pair.second == request.url_) {
image = pair.first;
callback(true, image);
return;
}
}
if (download(request, &image)) {
if (request.cache_) {
cache_.push_back(std::pair<Image, std::string>(image, request.url_));
}
callback(true, image);
return;
}
callback(false, Image{});
}
void handle(const Upload& request, void (*callback)(bool, Image)) {
if (request.size_ > 100) {
callback(false, Image{});
return;
}
Image image;
bool succes = upload(request, &image);
callback(succes, Image{});
}
void handle(const RemoveFromCache& request, void (*callback)(bool, Image)) {
for (auto it = cache_.begin(); it != cache_.end(); ++it) {
if (it->second == request.url_) {
cache_.erase(it);
callback(true, Image{});
return;
}
}
callback(false, Image{});
}
void handle(const ClearCache& request, void (*callback)(bool, Image)) {
cache_.clear();
callback(true, Image{});
}
private:
bool download(const Download& request, Image* image) {
if (request.type_ == Download::Ssh && request.credentail_.cert_ != 123) {
return false;
}
if (request.type_ == Download::Telnet && request.credentail_.cert_ != 231) {
return false;
}
// Simulate some other error
if (request.maxMbps_ % 2) {
return false;
}
image->bitmap_ = {97, 98, 99, 100, 101, 102};
return true;
}
bool upload(const Upload& request, const Image* image) {
if (request.type_ == Upload::Ssh && request.credentail_.cert_ != 1234) {
return false;
}
if (request.type_ == Upload::Telnet && request.credentail_.cert_ != 5432) {
return false;
}
// Simulate some other error
if (!request.maxMbps_ % 2) {
return false;
}
return true;
}
std::vector<std::pair<Image, std::string>> cache_;
};
class RequestHandler {
public:
enum RequestType { Download,
Upload,
Remove,
Clear };
void start(Server* server) {
std::thread(&RequestHandler::run, this, server).detach();
}
void stop() {
stop_ = true;
}
void pushRequest(void* request, RequestType type, void (*callback)(bool, Image)) {
requests_.push(std::tuple<void*, RequestType, void (*)(bool, Image)>(request, type, callback));
}
private:
void run(Server* server) {
while (!stop_) {
auto tuple = waitForRequest();
switch (std::get<1>(tuple)) {
case Download:
server->handle(*((::Download*)(std::get<0>(tuple))), std::get<2>(tuple));
break;
case Upload:
server->handle(*((::Upload*)(std::get<0>(tuple))), std::get<2>(tuple));
break;
case Remove:
server->handle(*((RemoveFromCache*)(std::get<0>(tuple))), std::get<2>(tuple));
break;
case Clear:
server->handle(*((ClearCache*)(std::get<0>(tuple))), std::get<2>(tuple));
break;
}
}
}
std::tuple<void*, RequestType, void (*)(bool, Image)> waitForRequest() {
while (requests_.empty() || !stop_) {
}
auto pair = requests_.front();
requests_.pop();
return pair;
}
bool stop_;
std::queue<std::tuple<void*, RequestType, void (*)(bool, Image)>> requests_;
};
int main() {
Server server;
RequestHandler handler;
handler.start(&server);
Download d{"sth.png", 123, 100, true, Download::Ssh};
handler.pushRequest((void*)(&d),
RequestHandler::Download,
[](bool succes, Image image) {
if (succes) {
for (auto el : image.bitmap_) {
std::cout << el << ' ';
}
std::cout << '\n';
} else {
std::cout << "FAILED!\n";
}
});
std::this_thread::sleep_for(std::chrono::seconds(1));
handler.stop();
}