summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Bergli Heier <snakebite@jvnv.net>2011-03-02 19:22:33 +0100
committerJon Bergli Heier <snakebite@jvnv.net>2011-03-02 19:22:33 +0100
commit6e7b8f94bf7fdc087cd1eed604eabed6070dffad (patch)
treee882988bd580903fdc0142d7c10ddfc9b5468f35
parent67a0e925ff1efc839ecb067d605bb45ebebf866a (diff)
Implemented simple caching for transcoded audio data.
-rw-r--r--.gitignore3
-rw-r--r--SConstruct1
-rw-r--r--cache.cpp47
-rw-r--r--cache.h26
-rw-r--r--config.cpp1
-rw-r--r--music.cpp30
6 files changed, 91 insertions, 17 deletions
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 <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();
+}
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 <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
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<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);
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 <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);
}