From 6e7b8f94bf7fdc087cd1eed604eabed6070dffad Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Wed, 2 Mar 2011 19:22:33 +0100 Subject: Implemented simple caching for transcoded audio data. --- .gitignore | 3 +++ SConstruct | 1 + cache.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ cache.h | 26 ++++++++++++++++++++++++++ config.cpp | 1 + music.cpp | 30 +++++++++++++----------------- 6 files changed, 91 insertions(+), 17 deletions(-) create mode 100644 cache.cpp create mode 100644 cache.h diff --git a/.gitignore b/.gitignore index 85183e8..fc370ea 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ .sconsign.dblite .sconf_temp config.log +/audist.db +/static +/cache diff --git a/SConstruct b/SConstruct index 6b960cf..65311ab 100644 --- a/SConstruct +++ b/SConstruct @@ -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 +#include +#include + +#include +#include + +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()) / 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(); +} diff --git a/cache.h b/cache.h new file mode 100644 index 0000000..21d4a52 --- /dev/null +++ b/cache.h @@ -0,0 +1,26 @@ +#ifndef CACHE_H +#define CACHE_H + +#include "decoder.h" +#include "encoder.h" + +#include + +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 diff --git a/config.cpp b/config.cpp index 68e8a2f..910d0f0 100644 --- a/config.cpp +++ b/config.cpp @@ -14,6 +14,7 @@ void config::init() { ("audist.telnetd_port", po::value()->default_value(7681), "telnetd port") ("audist.threads", po::value()->default_value(10), "threads") ("audist.database", po::value(), "database string") + ("audist.cache_dir", po::value(), "cache dir") ; std::ifstream is("audist.conf", std::ios::in); po::store(po::parse_config_file(is, desc, true), vm); diff --git a/music.cpp b/music.cpp index de5575f..51c44a8 100644 --- a/music.cpp +++ b/music.cpp @@ -2,8 +2,8 @@ #include "decoder.h" #include "encoder.h" #include "tag.h" -#include "config.h" #include "database.h" +#include "cache.h" #include #include @@ -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); } -- cgit v1.2.3