From 10eb0b3216d4b2599e6f2ef02267e373a6063256 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Mon, 26 Feb 2018 04:03:07 -0800 Subject: [PATCH] modules/media: 11.7.1.4 Thumbnail; remote fetch. --- modules/Makefile.am | 2 + modules/media/thumbnail.cc | 185 +++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 modules/media/thumbnail.cc diff --git a/modules/Makefile.am b/modules/Makefile.am index b04982be3..fe5d4c186 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -226,10 +226,12 @@ media_moduledir = @moduledir@ media_media_download_la_SOURCES = media/download.cc media_media_upload_la_SOURCES = media/upload.cc +media_media_thumbnail_la_SOURCES = media/thumbnail.cc media_module_LTLIBRARIES = \ media/media_download.la \ media/media_upload.la \ + media/media_thumbnail.la \ ### ############################################################################### diff --git a/modules/media/thumbnail.cc b/modules/media/thumbnail.cc new file mode 100644 index 000000000..37b6552b0 --- /dev/null +++ b/modules/media/thumbnail.cc @@ -0,0 +1,185 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2018 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +using namespace ircd; + +mapi::header +IRCD_MODULE +{ + "Client-Sever 11.7.1.4 :Media thumbnails" +}; + +resource +thumbnail_resource__legacy +{ + "/_matrix/media/v1/thumbnail/", + { + "Media thumbnails (legacy version)", + resource::DIRECTORY, + } +}; + +resource +thumbnail_resource +{ + "/_matrix/media/r0/thumbnail/", + { + "Media thumbnails", + resource::DIRECTORY, + } +}; + +static resource::response +get__thumbnail_remote(client &client, + const resource::request &request, + const string_view &server, + const string_view &file); + +resource::response +get__thumbnail(client &client, + const resource::request &request) +{ + if(request.parv.size() < 1) + throw http::error + { + http::MULTIPLE_CHOICES, "Server name parameter required" + }; + + if(request.parv.size() < 2) + throw http::error + { + http::MULTIPLE_CHOICES, "Media ID parameter required" + }; + + const auto &server + { + request.parv[0] + }; + + const auto &file + { + request.parv[1] + }; + + //TODO: cache check + + if(!my_host(server)) + return get__thumbnail_remote(client, request, server, file); + + throw m::NOT_FOUND{}; //TODO: X + + const string_view data + { + + }; + + char mime_type_buf[64]; + const string_view content_type + { + magic::mime(mime_type_buf, data) + }; + + return resource::response + { + client, string_view{data}, content_type + }; +} + +resource::method +method_get__legacy +{ + thumbnail_resource__legacy, "GET", get__thumbnail +}; + +resource::method +method_get +{ + thumbnail_resource, "GET", get__thumbnail +}; + +static resource::response +get__thumbnail_remote(client &client, + const resource::request &request, + const string_view &hostname, + const string_view &mediaid) +{ + const net::hostport remote + { + hostname + }; + + const unique_buffer in + { + 512_KiB //TODO: XXX + }; + + char outbuf[3_KiB]; + thread_local char uri[2_KiB]; + window_buffer wb{outbuf}; + http::request + { + wb, hostname, "GET", fmt::sprintf + { + uri, "/_matrix/media/v1/thumbnail/%s/%s", hostname, mediaid + } + }; + + struct server::request::opts opts; + opts.http_exceptions = false; + + server::request remote_request + { + remote, { wb.completed() }, { in }, &opts + }; + + if(remote_request.wait(seconds(5)) == ctx::future_status::timeout) //TODO: conf + throw http::error + { + http::REQUEST_TIMEOUT + }; + + const auto &code + { + remote_request.get() + }; + + if(code != http::OK) + return resource::response + { + client, code + }; + + //TODO: cache add + + char mime_type_buf[64]; + const string_view content_type + { + magic::mime(mime_type_buf, remote_request.in.content) + }; + + parse::buffer pb{remote_request.in.head}; + parse::capstan pc{pb}; + pc.read += size(remote_request.in.head); + const http::response::head head{pc}; + if(content_type != head.content_type) + log::warning + { + "Server %s claims thumbnail %s is '%s' but we think it is '%s'", + hostname, + mediaid, + head.content_type, + content_type + }; + + return resource::response + { + client, remote_request.in.content, head.content_type + }; +}