diff --git a/modules/media/media.cc b/modules/media/media.cc index b98fb7f14..12006bc03 100644 --- a/modules/media/media.cc +++ b/modules/media/media.cc @@ -35,3 +35,140 @@ file_room_id(const string_view &server, b58encode(buf, hash), my_host() }; } + +size_t +write_file(const m::room &room, + const string_view &content, + const string_view &content_type) +{ + //TODO: TXN + send(room, m::me.user_id, "ircd.file.stat", "size", + { + { "value", long(size(content)) } + }); + + //TODO: TXN + send(room, m::me.user_id, "ircd.file.stat", "type", + { + { "value", content_type } + }); + + const auto lpath + { + fs::make_path({fs::DPATH, "media"}) + }; + + char pathbuf[768]; + size_t pathlen{0}; + pathlen = strlcpy(pathbuf, lpath); + pathlen = strlcat(pathbuf, "/"_sv); //TODO: fs utils + const mutable_buffer pathpart + { + pathbuf + pathlen, sizeof(pathbuf) - pathlen + }; + + size_t off{0}, wrote{0}; + while(off < size(content)) + { + const size_t blksz + { + std::min(size(content) - off, size_t(32_KiB)) + }; + + const const_buffer &block + { + data(content) + off, blksz + }; + + const sha256::buf hash_ + { + sha256{block} + }; + + char b58buf[hash_.size() * 2]; + const string_view hash + { + b58encode(b58buf, hash_) + }; + + send(room, m::me.user_id, "ircd.file.block", + { + { "size", long(blksz) }, + { "hash", hash } + }); + + const string_view path + { + pathbuf, pathlen + copy(pathpart, hash) + }; + + if(!fs::exists(path)) + wrote += size(fs::write(path, block)); + + off += blksz; + } + + assert(off == size(content)); + assert(wrote <= off); + return wrote; +} + +size_t +read_each_block(const m::room &room, + const std::function &closure) +{ + const auto lpath + { + fs::make_path({fs::DPATH, "media"}) + }; + + char pathbuf[768]; + size_t pathlen{0}; + pathlen = strlcpy(pathbuf, lpath); + pathlen = strlcat(pathbuf, "/"_sv); //TODO: fs utils + const mutable_buffer pathpart + { + pathbuf + pathlen, sizeof(pathbuf) - pathlen + }; + + // Block buffer + const unique_buffer buf + { + 64_KiB + }; + + size_t ret{0}; + m::room::messages it{room, 0}; + for(; bool(it); ++it) + { + const m::event &event{*it}; + if(at<"type"_>(event) != "ircd.file.block") + continue; + + const auto &hash + { + unquote(at<"content"_>(event).at("hash")) + }; + + const auto &blksz + { + at<"content"_>(event).get("size") + }; + + const string_view path + { + pathbuf, pathlen + copy(pathpart, hash) + }; + + const string_view &block + { + fs::read(path, buf) + }; + + assert(size(block) == blksz); + ret += size(block); + closure(block); + } + + return ret; +} diff --git a/modules/media/media.h b/modules/media/media.h index ae1ae8746..a568c8cf9 100644 --- a/modules/media/media.h +++ b/modules/media/media.h @@ -11,3 +11,6 @@ using namespace ircd; m::room::id::buf file_room_id(const string_view &server, const string_view &file); + +size_t read_each_block(const m::room &, const std::function &); +size_t write_file(const m::room &room, const string_view &content, const string_view &content_type); diff --git a/modules/media/thumbnail.cc b/modules/media/thumbnail.cc index e48fd9b7b..dd0846873 100644 --- a/modules/media/thumbnail.cc +++ b/modules/media/thumbnail.cc @@ -82,16 +82,22 @@ get__thumbnail(client &client, }; m::vm::opts::commit vmopts; + vmopts.history = false; const m::room room { - room_id + room_id, &vmopts }; + //TODO: ABA if(m::exists(room)) return get__thumbnail_local(client, request, server, file, room); if(!my_host(server)) + { + //TODO: ABA TXN + create(room, m::me.user_id, "file"); return get__thumbnail_remote(client, request, server, file, room); + } throw m::NOT_FOUND { @@ -117,6 +123,7 @@ get__thumbnail_remote(client &client, const string_view &hostname, const string_view &mediaid, const m::room &room) +try { const net::hostport remote { @@ -200,76 +207,20 @@ get__thumbnail_remote(client &client, client, remote_request.in.content, content_type }; - //TODO: TXN - create(room, m::me.user_id, "file"); - - //TODO: TXN - send(room, m::me.user_id, "ircd.file.stat", "size", + const size_t written { - { "value", long(file_size) } - }); - - //TODO: TXN - send(room, m::me.user_id, "ircd.file.stat", "type", - { - { "value", content_type } - }); - - const auto lpath{fs::make_path({fs::DPATH, "media"})}; - thread_local char pathbuf[1024]; - size_t pathlen{0}; - pathlen = strlcpy(pathbuf, lpath); - pathlen = strlcat(pathbuf, "/"_sv); //TODO: fs utils - const mutable_buffer pathpart - { - pathbuf + pathlen, sizeof(pathbuf) - pathlen + write_file(room, remote_request.in.content, content_type) }; - size_t off{0}, wrote{0}; - while(off < file_size) - { - const size_t blksz - { - std::min(file_size - off, size_t(32_KiB)) - }; - - const const_buffer &block - { - data(remote_request.in.content) + off, blksz - }; - - const sha256::buf hash_ - { - sha256{block} - }; - - char b58buf[hash_.size() * 2]; - const string_view hash - { - b58encode(b58buf, hash_) - }; - - send(room, m::me.user_id, "ircd.file.block", - { - { "size", long(blksz) }, - { "hash", hash } - }); - - const string_view path - { - pathbuf, pathlen + copy(pathpart, hash) - }; - - if(!fs::exists(path)) - wrote += size(fs::write(path, block)); - - off += blksz; - } - - assert(off == file_size); - assert(wrote <= off); return {}; } +catch(const ircd::server::unavailable &e) +{ + throw http::error + { + http::BAD_GATEWAY, e.what() + }; +} static resource::response get__thumbnail_local(client &client, @@ -288,7 +239,11 @@ get__thumbnail_local(client &client, // Get the MIME type char type_buf[64]; - string_view content_type; + string_view content_type + { + "application/octet-stream" + }; + room.get("ircd.file.stat", "type", [&type_buf, &content_type] (const m::event &event) { @@ -309,57 +264,13 @@ get__thumbnail_local(client &client, client, http::OK, content_type, file_size }; - const auto lpath{fs::make_path({fs::DPATH, "media"})}; - thread_local char pathbuf[1024]; - size_t pathlen{0}; - pathlen = strlcpy(pathbuf, lpath); - pathlen = strlcat(pathbuf, "/"_sv); //TODO: fs utils - const mutable_buffer pathpart + size_t sent{0}, read; + read = read_each_block(room, [&client, &sent] + (const string_view &block) { - pathbuf + pathlen, sizeof(pathbuf) - pathlen - }; - - // Block buffer - const unique_buffer buf - { - 64_KiB - }; - - // Spool content to client - size_t sent{0}, read{0}; - m::room::messages it{room, 1}; - for(; bool(it); ++it) - { - const m::event &event{*it}; - if(at<"type"_>(event) != "ircd.file.block") - continue; - - const auto &hash - { - unquote(at<"content"_>(event).at("hash")) - }; - - const auto &blksz - { - at<"content"_>(event).get("size") - }; - - const string_view path - { - pathbuf, pathlen + copy(pathpart, hash) - }; - - const string_view &block - { - fs::read(path, buf) - }; - - assert(size(block) == blksz); - read += size(block); sent += write_all(*client.sock, block); - } + }); - assert(read == file_size); - assert(sent == read); + //assert(sent == file_size); return {}; }