diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | SConstruct | 1 | ||||
-rw-r--r-- | cache.cpp | 47 | ||||
-rw-r--r-- | cache.h | 26 | ||||
-rw-r--r-- | config.cpp | 1 | ||||
-rw-r--r-- | music.cpp | 30 |
6 files changed, 91 insertions, 17 deletions
@@ -9,3 +9,6 @@ .sconsign.dblite .sconf_temp config.log +/audist.db +/static +/cache @@ -24,6 +24,7 @@ else: env.ParseConfig('pkg-config --cflags --libs libmpg123') env.ParseConfig('pkg-config --cflags --libs id3tag') env.ParseConfig('pkg-config --cflags --libs vorbisenc') +env.ParseConfig('pkg-config --cflags --libs libssl') env.Program('audistd', Glob('*.cpp') + Glob('decoders/*.cpp') + Glob('encoders/*.cpp')) diff --git a/cache.cpp b/cache.cpp new file mode 100644 index 0000000..92e0cfa --- /dev/null +++ b/cache.cpp @@ -0,0 +1,47 @@ +#include "cache.h" +#include "config.h" + +#include <boost/format.hpp> +#include <boost/filesystem/fstream.hpp> +#include <openssl/sha.h> + +#include <iostream> +#include <stdexcept> + +EncodedCache::EncodedCache(fs::path path, Decoder::p decoder, Encoder::p encoder) { + this->decoder = decoder; + this->encoder = encoder; + + // TODO: Differentiate between encoders? + SHA_CTX context; + unsigned char md[SHA_DIGEST_LENGTH]; + SHA_Init(&context); + SHA_Update(&context, (unsigned char*)path.string().c_str(), path.string().length()); + SHA_Final(md, &context); + for(int i = 0; i < SHA_DIGEST_LENGTH; i++) { + hash = hash + (boost::format("%02x") % (int)md[i]).str(); + } +} + +fs::path EncodedCache::get_path() { + return fs::path(config::vm["audist.cache_dir"].as<std::string>()) / hash; +} + +void EncodedCache::create_cache() { + fs::path path = get_path(); + + // TODO: Locking? + fs::ofstream os(path, std::ios::out | std::ios::binary); + // TODO: Make an encoder-to-istream adapter to get rid of this: + + if(!os.is_open()) + throw std::runtime_error("failed to create cache object"); + char data[0x10000]; + std::streamsize size = 1; + while(size) { + size = encoder->read(data, 0x10000); + if(size > 0) + os.write(data, size); + } + os.close(); +} @@ -0,0 +1,26 @@ +#ifndef CACHE_H +#define CACHE_H + +#include "decoder.h" +#include "encoder.h" + +#include <boost/filesystem.hpp> + +namespace fs = boost::filesystem; + +class EncodedCache { + private: + Decoder::p decoder; + Encoder::p encoder; + + std::string hash; + + public: + EncodedCache(fs::path path, Decoder::p decoder, Encoder::p encoder); + virtual ~EncodedCache() {}; + + fs::path get_path(); + void create_cache(); +}; + +#endif @@ -14,6 +14,7 @@ void config::init() { ("audist.telnetd_port", po::value<int>()->default_value(7681), "telnetd port") ("audist.threads", po::value<std::size_t>()->default_value(10), "threads") ("audist.database", po::value<std::string>(), "database string") + ("audist.cache_dir", po::value<std::string>(), "cache dir") ; std::ifstream is("audist.conf", std::ios::in); po::store(po::parse_config_file(is, desc, true), vm); @@ -2,8 +2,8 @@ #include "decoder.h" #include "encoder.h" #include "tag.h" -#include "config.h" #include "database.h" +#include "cache.h" #include <boost/format.hpp> #include <boost/algorithm/string/predicate.hpp> @@ -170,26 +170,22 @@ MusicDirectory::MusicDirectory(const fs::path root) { void MusicTrack::render(HTTP::Connection::p req) { req->add_header("content-type", "application/octet-stream"); + fs::path file_path = path; if(req->args.count("decoder") && req->args.count("encoder")) { Decoder::p decoder = Decoder::get(req->args["decoder"], path.string()); Encoder::p encoder = Encoder::get(req->args["encoder"], decoder); - - // TODO: Make an encoder-to-istream adapter to get rid of this: - char data[0x10000]; - std::streamsize size = 1; - while(size) { - size = encoder->read(data, 0x10000); - if(size > 0) - req->send_data(data, size); - } - - } else { - fs::ifstream is(path, std::ios::in | std::ios::binary); - is.seekg(0, std::ios::end); - req->add_header("content-length", boost::str(boost::format("%d") % is.tellg())); - is.seekg(0, std::ios::beg); - req->send_data(is); + EncodedCache ec(path, decoder, encoder); + file_path = ec.get_path(); + if(!fs::exists(file_path)) + ec.create_cache(); } + + fs::ifstream is(file_path, std::ios::in | std::ios::binary); + is.seekg(0, std::ios::end); + req->add_header("content-length", boost::str(boost::format("%d") % is.tellg())); + is.seekg(0, std::ios::beg); + + req->send_data(is); } |