This commit is contained in:
Doug Hoyte
2024-12-16 01:36:12 -05:00
parent fe5a081c37
commit b82c269cc3
4 changed files with 69 additions and 20 deletions

View File

@ -1,6 +1,13 @@
#pragma once
struct FeedReader {
std::string feedId;
bool found = false;
tao::json::value feedJson;
std::string pubkey;
std::string feedName;
struct EventInfo {
uint64_t comments = 0;
double score = 0.0;
@ -13,36 +20,38 @@ struct FeedReader {
EventInfo info;
};
std::vector<FeedEvent> getEvents(lmdb::txn &txn, Decompressor &decomp, const std::string &feedId, uint64_t resultsPerPage, uint64_t page) {
uint64_t skip = page * resultsPerPage;
uint64_t remaining = resultsPerPage;
FeedReader(lmdb::txn &txn, Decompressor &decomp, std::string_view feedId_) : feedId(feedId_) {
if (feedId == "homepage") feedId = cfg().web__homepageFeedId;
size_t pos = feedId.find(".");
if (pos == std::string_view::npos) throw herr("bad feedId: ", feedId);
std::string pubkey = from_hex(feedId.substr(0, pos));
std::string adminTopic = feedId.substr(pos + 1);
pubkey = from_hex(feedId.substr(0, pos));
feedName = feedId.substr(pos + 1);
tao::json::value filter = tao::json::value({
{ "authors", tao::json::value::array({ to_hex(pubkey) }) },
{ "kinds", tao::json::value::array({ uint64_t(33800) }) },
{ "#d", tao::json::value::array({ adminTopic }) },
{ "#d", tao::json::value::array({ feedName }) },
});
bool found = false;
tao::json::value feedJson;
foreachByFilter(txn, filter, [&](uint64_t levId){
feedJson = tao::json::from_string(getEventJson(txn, decomp, levId));
found = true;
return false;
});
}
std::vector<FeedEvent> getEvents(lmdb::txn &txn, Decompressor &decomp, uint64_t resultsPerPage, uint64_t page) const {
if (!found) throw herr("unable to lookup feedId: ", feedId);
std::vector<FeedEvent> output;
uint64_t skip = page * resultsPerPage;
uint64_t remaining = resultsPerPage;
tao::json::value currFeedJson = feedJson;
while (true) {
const auto &tags = feedJson.at("tags").get_array();
const auto &tags = currFeedJson.at("tags").get_array();
std::string prev;
for (const auto &tag : tags) {
@ -75,7 +84,7 @@ struct FeedReader {
if (remaining && prev.size()) {
auto ev = lookupEventById(txn, prev);
if (ev) {
feedJson = tao::json::from_string(getEventJson(txn, decomp, ev->primaryKeyId));
currFeedJson = tao::json::from_string(getEventJson(txn, decomp, ev->primaryKeyId));
continue;
}
}
@ -86,7 +95,7 @@ struct FeedReader {
return output;
}
EventInfo buildEventInfo(lmdb::txn &txn, const std::string &id) {
EventInfo buildEventInfo(lmdb::txn &txn, const std::string &id) const {
EventInfo output;
std::string prefix = "e";

View File

@ -92,9 +92,8 @@ void doSearch(lmdb::txn &txn, Decompressor &decomp, std::string_view search, std
TemplarResult renderFeed(lmdb::txn &txn, Decompressor &decomp, UserCache &userCache, const std::string &feedId, uint64_t resultsPerPage, uint64_t page) {
FeedReader feedReader;
auto events = feedReader.getEvents(txn, decomp, feedId, resultsPerPage, page);
TemplarResult renderFeed(lmdb::txn &txn, Decompressor &decomp, UserCache &userCache, const FeedReader &feedReader, uint64_t resultsPerPage, uint64_t page) {
auto events = feedReader.getEvents(txn, decomp, resultsPerPage, page);
std::vector<TemplarResult> rendered;
auto now = hoytech::curr_time_s();
@ -165,15 +164,24 @@ HTTPResponse WebServer::generateReadResponse(lmdb::txn &txn, Decompressor &decom
std::optional<std::string> rawBody;
// Misc:
std::optional<FeedReader> feedReader;
if (u.path.size() == 0) {
uint64_t resultsPerPage = 30;
uint64_t page = 0;
auto pageStr = u.lookupQuery("p");
if (pageStr) page = std::stoull(std::string(*pageStr));
body = renderFeed(txn, decomp, userCache, cfg().web__homepageFeedId, resultsPerPage, page);
feedReader.emplace(txn, decomp, "homepage");
httpResp.extraHeaders += "Cache-Control: max-age=30\r\n";
if (feedReader->found) {
body = renderFeed(txn, decomp, userCache, *feedReader, resultsPerPage, page);
httpResp.extraHeaders += "Cache-Control: max-age=30\r\n";
} else {
rawBody = "Feed not found.";
}
} else if (u.path[0] == "e") {
if (u.path.size() == 2) {
EventThread et(txn, decomp, decodeBech32Simple(u.path[1]));
@ -267,6 +275,26 @@ HTTPResponse WebServer::generateReadResponse(lmdb::txn &txn, Decompressor &decom
body = tmpl::user::followers(ctx);
}
}
} else if (u.path[0] == "f") {
if (u.path.size() == 2) {
feedReader.emplace(txn, decomp, u.path[1]);
// FIXME: feed
} else if (u.path.size() == 3 && u.path[2] == "info") {
feedReader.emplace(txn, decomp, u.path[1]);
if (feedReader->found) {
struct {
const std::optional<FeedReader> &feedReader;
} ctx = {
feedReader,
};
body = tmpl::feed::info(ctx);
title = feedReader->feedName;
} else {
rawBody = "Feed not found.";
}
}
} else if (u.path[0] == "search") {
std::vector<TemplarResult> results;
@ -326,6 +354,7 @@ HTTPResponse WebServer::generateReadResponse(lmdb::txn &txn, Decompressor &decom
std::string_view staticOddbeanCssHash;
std::string_view staticOddbeanJsHash;
std::string_view staticOddbeanSvgHash;
const std::optional<FeedReader> &feedReader;
} ctx = {
*body,
title,
@ -333,6 +362,7 @@ HTTPResponse WebServer::generateReadResponse(lmdb::txn &txn, Decompressor &decom
oddbeanStatic__oddbean_css__hash().substr(0, 16),
oddbeanStatic__oddbean_js__hash().substr(0, 16),
oddbeanStatic__oddbean_svg__hash().substr(0, 16),
feedReader,
};
responseData = std::move(tmpl::main(ctx).str);

View File

@ -0,0 +1,9 @@
<div class="feed-info-page">
<p>
Feed: $(ctx.feedReader->feedName)
</p>
<p>
ID: $(ctx.feedReader->feedId)
</p>
</div>

View File

@ -14,9 +14,10 @@
<a href="/" class="logo-link"><img class="logo" src="$(ctx.staticFilesPrefix)/oddbean.svg?$(ctx.staticOddbeanSvgHash)"></a>
<span>
<a href="/" class="sitename">
<span class="oddbean-name">Oddbean</span>
</a>
<a href="/" class="sitename"><span class="oddbean-name">Oddbean</span></a>
<> ?(ctx.feedReader)
/ <a href="/f/$(ctx.feedReader->feedName)/info" class="feedname">$(ctx.feedReader->feedName)</a>
</>
</span>
<a href="/post" class="new-post-link">new post</a>