diff options
| author | Joel Klinghed <the_jk@spawned.biz> | 2021-11-17 22:34:57 +0100 |
|---|---|---|
| committer | Joel Klinghed <the_jk@spawned.biz> | 2021-11-17 22:34:57 +0100 |
| commit | 6232d13f5321b87ddf12a1aa36b4545da45f173d (patch) | |
| tree | 23f3316470a14136debd9d02f9e920ca2b06f4cc /src/static_files.cc | |
Travel3: Simple image and video display site
Reads the images and videos from filesystem and builds a site in
memroy.
Diffstat (limited to 'src/static_files.cc')
| -rw-r--r-- | src/static_files.cc | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/static_files.cc b/src/static_files.cc new file mode 100644 index 0000000..7125ee0 --- /dev/null +++ b/src/static_files.cc @@ -0,0 +1,113 @@ +#include "common.hh" + +#include "files_finder.hh" +#include "hasher.hh" +#include "mime_types.hh" +#include "send_file.hh" +#include "static_files.hh" +#include "weak_ptr.hh" + +#include <optional> + +namespace { + +class StaticFilesImpl : public StaticFiles, public FilesFinder::Delegate { +public: + StaticFilesImpl( + std::shared_ptr<Logger> logger, + std::shared_ptr<TaskRunner> runner, + std::shared_ptr<SendFile> send_file, + std::filesystem::path path, + size_t threads) + : root_(std::move(path)), send_file_(std::move(send_file)), + weak_ptr_owner_(this) { + finder_ = FilesFinder::create(logger, runner, root_, this, threads); + hasher_ = Hasher::create(logger, runner, threads); + } + + std::unique_ptr<Transport::Response> request( + Transport* transport, std::string_view path) override { + auto it = files_.find(std::string(path)); + if (it == files_.end()) + return nullptr; + auto resp = send_file_->create_ok_file(transport, it->second.path_, + it->first, it->second.etag_, + it->second.size_); + if (!it->second.mime_type_.empty()) + resp->add_header("Content-Type", it->second.mime_type_); + return resp; + } + + void file(std::filesystem::path path) override { + std::string name("/"); + name.append(path.filename()); + auto parent = path.parent_path(); + while (true) { + if (parent == root_ || !parent.has_parent_path()) + break; + name.insert(0, parent.filename()); + name.insert(0, "/"); + parent = parent.parent_path(); + } + files_[name].path_ = path; + if (path.has_extension()) + files_[name].mime_type_ = mime_types::from_extension( + std::string(path.extension()).substr(1)); + hasher_->hash(path, std::bind(&StaticFilesImpl::weak_hashed, + weak_ptr_owner_.get(), name, + std::placeholders::_1, + std::placeholders::_2)); + } + + void done() override { + finder_.reset(); + } + +private: + struct File { + std::filesystem::path path_; + std::string mime_type_; + std::string etag_; + std::optional<uint64_t> size_; + }; + + static void weak_hashed(std::shared_ptr<WeakPtr<StaticFilesImpl>> weak_ptr, + std::string const& name, + std::string hash, + uint64_t size) { + auto* ptr = weak_ptr->get(); + if (ptr) + ptr->hashed(name, std::move(hash), size); + } + + void hashed(std::string const& name, std::string hash, uint64_t size) { + if (hash.empty()) + return; + + hash.insert(0, "\""); + hash.push_back('"'); + files_[name].etag_ = std::move(hash); + files_[name].size_ = size; + } + + std::filesystem::path root_; + std::shared_ptr<SendFile> send_file_; + std::unordered_map<std::string, File> files_; + std::unique_ptr<FilesFinder> finder_; + std::unique_ptr<Hasher> hasher_; + + WeakPtrOwner<StaticFilesImpl> weak_ptr_owner_; +}; + +} // namespace + +std::unique_ptr<StaticFiles> StaticFiles::create( + std::shared_ptr<Logger> logger, + std::shared_ptr<TaskRunner> runner, + std::shared_ptr<SendFile> send_file, + std::filesystem::path path, + size_t threads) { + return std::make_unique<StaticFilesImpl>( + std::move(logger), std::move(runner), std::move(send_file), + std::move(path), threads); +} |
