2017-10-13 16:58:41 +05:00
|
|
|
#include <cassert>
|
2017-10-24 17:51:21 +05:00
|
|
|
#include <nntpchan/crypto.hpp>
|
2017-10-17 19:29:56 +05:00
|
|
|
#include <nntpchan/sanitize.hpp>
|
|
|
|
#include <nntpchan/storage.hpp>
|
2017-10-09 20:48:10 +05:00
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
namespace nntpchan
|
|
|
|
{
|
|
|
|
|
2018-05-06 17:10:20 +05:00
|
|
|
const fs::path posts_skiplist_dir = "posts";
|
|
|
|
const fs::path threads_skiplist_dir = "threads";
|
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
ArticleStorage::ArticleStorage(const fs::path &fpath) { SetPath(fpath); }
|
|
|
|
|
|
|
|
ArticleStorage::~ArticleStorage() {}
|
|
|
|
|
|
|
|
void ArticleStorage::SetPath(const fs::path &fpath)
|
|
|
|
{
|
|
|
|
basedir = fpath;
|
|
|
|
fs::create_directories(basedir);
|
2017-10-24 17:51:21 +05:00
|
|
|
assert(init_skiplist(posts_skiplist_dir));
|
|
|
|
assert(init_skiplist(threads_skiplist_dir));
|
2018-05-03 22:38:35 +05:00
|
|
|
errno = 0;
|
2017-10-17 19:29:56 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArticleStorage::init_skiplist(const std::string &subdir) const
|
|
|
|
{
|
2017-10-24 17:51:21 +05:00
|
|
|
fs::path skiplist = skiplist_root(subdir);
|
2018-05-06 17:10:20 +05:00
|
|
|
const auto subdirs = {
|
|
|
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
|
|
|
|
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '2', '3', '4', '5', '6', '7',
|
|
|
|
};
|
2017-10-17 19:29:56 +05:00
|
|
|
for (const auto &s : subdirs)
|
2017-10-24 17:51:21 +05:00
|
|
|
fs::create_directories(skiplist / std::string(&s, 1));
|
2017-10-17 19:29:56 +05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArticleStorage::Accept(const std::string &msgid) const
|
|
|
|
{
|
|
|
|
if (!IsValidMessageID(msgid))
|
|
|
|
return false;
|
|
|
|
auto p = MessagePath(msgid);
|
2018-05-03 22:38:35 +05:00
|
|
|
bool ret = !fs::exists(p);
|
|
|
|
errno = 0;
|
|
|
|
return ret;
|
2017-10-17 19:29:56 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
fs::path ArticleStorage::MessagePath(const std::string &msgid) const { return basedir / msgid; }
|
|
|
|
|
|
|
|
FileHandle_ptr ArticleStorage::OpenRead(const std::string &msgid) const { return OpenFile(MessagePath(msgid), eRead); }
|
|
|
|
|
|
|
|
FileHandle_ptr ArticleStorage::OpenWrite(const std::string &msgid) const
|
|
|
|
{
|
|
|
|
return OpenFile(MessagePath(msgid), eWrite);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArticleStorage::LoadBoardPage(BoardPage &board, const std::string &newsgroup, uint32_t perpage,
|
|
|
|
uint32_t page) const
|
|
|
|
{
|
|
|
|
(void)board;
|
|
|
|
(void)newsgroup;
|
|
|
|
(void)perpage;
|
|
|
|
(void)page;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool ArticleStorage::FindThreadByHash(const std::string &hashhex, std::string &msgid) const
|
|
|
|
{
|
|
|
|
(void)hashhex;
|
|
|
|
(void)msgid;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool ArticleStorage::LoadThread(Thread &thread, const std::string &rootmsgid) const
|
|
|
|
{
|
|
|
|
(void)thread;
|
|
|
|
(void)rootmsgid;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** ensure symlinks are formed for this article by message id */
|
2017-10-24 17:51:21 +05:00
|
|
|
void ArticleStorage::EnsureSymlinks(const std::string &msgid) const
|
|
|
|
{
|
|
|
|
std::string msgidhash = Blake2B_base32(msgid);
|
2018-05-06 21:35:03 +05:00
|
|
|
auto skip = skiplist_dir(skiplist_root(posts_skiplist_dir), msgidhash) / msgidhash;
|
|
|
|
auto path = fs::path("..") / fs::path("..") / fs::path("..") / MessagePath(msgid);
|
|
|
|
fs::create_symlink(path, skip);
|
|
|
|
errno = 0;
|
2017-10-24 17:51:21 +05:00
|
|
|
}
|
|
|
|
|
2018-05-06 17:10:20 +05:00
|
|
|
fs::path ArticleStorage::skiplist_root(const std::string &name) const { return basedir / name; }
|
|
|
|
fs::path ArticleStorage::skiplist_dir(const fs::path &root, const std::string &name) const
|
|
|
|
{
|
|
|
|
return root / name.substr(0, 1);
|
|
|
|
}
|
2017-10-09 20:48:10 +05:00
|
|
|
}
|