mirror of
https://github.com/MeshEnvy/lobbs.git
synced 2026-11-03 11:32:25 +01:00
feat(meshtastic): extract LoBBS plugin library
This commit is contained in:
1 parent
1f7ded8f3f
commit
5bffe8d259
124 files changed
+10907
-39
No files matched your search
@@ -0,0 +1,52 @@
|
||||
#if !MESHTASTIC_EXCLUDE_LOBBS
|
||||
|
||||
#include "paginate.h"
|
||||
#include "LoBBSReply.h"
|
||||
#include <cstdio>
|
||||
|
||||
#include "LoBBSStackGuard.h"
|
||||
|
||||
bool lobbsPaginateMachine(uint32_t reqId, const std::string &document, uint32_t page1, std::string &pageOut, const char **errMsg)
|
||||
{
|
||||
pageOut.clear();
|
||||
if (page1 == 0)
|
||||
page1 = 1;
|
||||
|
||||
char prefix[40];
|
||||
size_t prefixLen = (size_t)snprintf(prefix, sizeof(prefix), "<%u>ok\n", reqId);
|
||||
if (prefixLen + document.size() <= LOBBS_REPLY_BYTES) {
|
||||
if (page1 > 1) {
|
||||
if (errMsg)
|
||||
*errMsg = "No such page.";
|
||||
return false;
|
||||
}
|
||||
pageOut = prefix;
|
||||
pageOut += document;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Size every page for the widest header at this digit count; widen until the page count fits.
|
||||
uint32_t widest = 9;
|
||||
size_t budget = 0;
|
||||
uint32_t pages = 0;
|
||||
while (true) {
|
||||
prefixLen = (size_t)snprintf(prefix, sizeof(prefix), "<%u>ok [%u:%u]\n", reqId, widest, widest);
|
||||
budget = LOBBS_REPLY_BYTES - prefixLen;
|
||||
pages = (uint32_t)((document.size() + budget - 1) / budget);
|
||||
if (pages <= widest)
|
||||
break;
|
||||
widest = widest * 10 + 9;
|
||||
}
|
||||
|
||||
if (page1 > pages) {
|
||||
if (errMsg)
|
||||
*errMsg = "No such page.";
|
||||
return false;
|
||||
}
|
||||
snprintf(prefix, sizeof(prefix), "<%u>ok [%u:%u]\n", reqId, page1, pages);
|
||||
pageOut = prefix;
|
||||
pageOut.append(document, (size_t)(page1 - 1) * budget, budget);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#if !MESHTASTIC_EXCLUDE_LOBBS
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
bool lobbsPaginateMachine(uint32_t reqId, const std::string &document, uint32_t page1, std::string &pageOut, const char **errMsg);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#if !MESHTASTIC_EXCLUDE_LOBBS
|
||||
|
||||
#include "serialize.h"
|
||||
#include <cstddef>
|
||||
|
||||
#include "LoBBSStackGuard.h"
|
||||
|
||||
bool lobbsSerializeMachine(const LoBBSResponse &resp, std::string &out)
|
||||
{
|
||||
out.clear();
|
||||
if (!resp.ok) {
|
||||
out = resp.error;
|
||||
return true;
|
||||
}
|
||||
for (const LoScalar &rec : resp.records) {
|
||||
if (!out.empty())
|
||||
out.push_back('\n');
|
||||
std::string line;
|
||||
if (!rec.encode(line, SIZE_MAX))
|
||||
return false;
|
||||
out += line;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#if !MESHTASTIC_EXCLUDE_LOBBS
|
||||
|
||||
#include "LoBBSResponse.h"
|
||||
#include <string>
|
||||
|
||||
bool lobbsSerializeMachine(const LoBBSResponse &resp, std::string &out);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
#if !MESHTASTIC_EXCLUDE_LOBBS
|
||||
|
||||
#include "paginate.h"
|
||||
#include "LoBBSReply.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "LoBBSStackGuard.h"
|
||||
|
||||
static constexpr size_t LOBBS_PAGER_FOOTER_MAX = 16;
|
||||
static constexpr int LOBBS_PAGER_MAX_PAGES = 64;
|
||||
static constexpr char LOBBS_LINE_TRUNC[] = "[...]";
|
||||
static constexpr size_t LOBBS_LINE_TRUNC_LEN = sizeof(LOBBS_LINE_TRUNC) - 1;
|
||||
|
||||
static size_t lobbsHumanLineLen(const std::string &line, size_t maxBytes)
|
||||
{
|
||||
size_t len = strlen(line.c_str());
|
||||
if (len <= maxBytes)
|
||||
return len;
|
||||
return maxBytes <= LOBBS_LINE_TRUNC_LEN ? 0 : maxBytes;
|
||||
}
|
||||
|
||||
static void lobbsHumanAppendLine(std::string &out, const std::string &line, size_t maxBytes)
|
||||
{
|
||||
size_t len = strlen(line.c_str());
|
||||
if (len <= maxBytes) {
|
||||
out.append(line, 0, len);
|
||||
return;
|
||||
}
|
||||
if (maxBytes <= LOBBS_LINE_TRUNC_LEN)
|
||||
return;
|
||||
out.append(line, 0, maxBytes - LOBBS_LINE_TRUNC_LEN);
|
||||
out += LOBBS_LINE_TRUNC;
|
||||
}
|
||||
|
||||
static bool lobbsHumanPackPages(const std::vector<std::string> &lines, size_t maxBytes, bool reserveFooter, uint32_t *pageStarts,
|
||||
int &pageCountOut)
|
||||
{
|
||||
pageCountOut = 0;
|
||||
if (lines.empty())
|
||||
return false;
|
||||
uint32_t idx = 0;
|
||||
while (idx < lines.size() && pageCountOut < LOBBS_PAGER_MAX_PAGES) {
|
||||
pageStarts[pageCountOut] = idx;
|
||||
size_t used = 0;
|
||||
while (idx < lines.size()) {
|
||||
size_t footerReserve = reserveFooter ? LOBBS_PAGER_FOOTER_MAX : 0;
|
||||
size_t maxLine = maxBytes > footerReserve ? maxBytes - footerReserve : 0;
|
||||
size_t lineLen = lobbsHumanLineLen(lines[idx], maxLine);
|
||||
size_t add = lineLen + (used > 0 ? 1 : 0);
|
||||
if (used + add + footerReserve > maxBytes) {
|
||||
if (used > 0)
|
||||
break;
|
||||
used += lineLen;
|
||||
idx++;
|
||||
break;
|
||||
}
|
||||
used += add;
|
||||
idx++;
|
||||
if (idx < lines.size()) {
|
||||
size_t nextAdd = lobbsHumanLineLen(lines[idx], maxLine) + 1;
|
||||
if (used + nextAdd + footerReserve > maxBytes)
|
||||
break;
|
||||
}
|
||||
}
|
||||
pageCountOut++;
|
||||
}
|
||||
if (pageCountOut < LOBBS_PAGER_MAX_PAGES)
|
||||
pageStarts[pageCountOut] = (uint32_t)lines.size();
|
||||
return pageCountOut > 0;
|
||||
}
|
||||
|
||||
bool lobbsPaginatePlainText(const std::string &text, uint32_t page1, std::string &pageOut, const char **errMsg)
|
||||
{
|
||||
pageOut.clear();
|
||||
if (text.empty()) {
|
||||
if (errMsg)
|
||||
*errMsg = "Empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> lines;
|
||||
size_t start = 0;
|
||||
while (start <= text.size()) {
|
||||
size_t end = text.find('\n', start);
|
||||
if (end == std::string::npos) {
|
||||
lines.push_back(text.substr(start));
|
||||
break;
|
||||
}
|
||||
lines.push_back(text.substr(start, end - start));
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
if (page1 == 0)
|
||||
page1 = 1;
|
||||
uint32_t pageStarts[LOBBS_PAGER_MAX_PAGES + 1];
|
||||
memset(pageStarts, 0, sizeof(pageStarts));
|
||||
int pageCount = 0;
|
||||
lobbsHumanPackPages(lines, LOBBS_REPLY_BYTES, true, pageStarts, pageCount);
|
||||
if (pageCount <= 0) {
|
||||
if (errMsg)
|
||||
*errMsg = "Empty.";
|
||||
return false;
|
||||
}
|
||||
if (pageCount == 1) {
|
||||
lobbsHumanPackPages(lines, LOBBS_REPLY_BYTES, false, pageStarts, pageCount);
|
||||
pageStarts[1] = (uint32_t)lines.size();
|
||||
}
|
||||
if (page1 > (uint32_t)pageCount) {
|
||||
if (errMsg)
|
||||
*errMsg = "No such page.";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t from = pageStarts[page1 - 1];
|
||||
uint32_t to = pageStarts[page1];
|
||||
size_t footerReserve = pageCount > 1 ? LOBBS_PAGER_FOOTER_MAX : 0;
|
||||
size_t maxLine = LOBBS_REPLY_BYTES > footerReserve ? LOBBS_REPLY_BYTES - footerReserve : 0;
|
||||
for (uint32_t i = from; i < to; i++) {
|
||||
if (i > from)
|
||||
pageOut.push_back('\n');
|
||||
lobbsHumanAppendLine(pageOut, lines[i], maxLine);
|
||||
}
|
||||
if ((uint32_t)pageCount > 1) {
|
||||
char footer[LOBBS_PAGER_FOOTER_MAX];
|
||||
snprintf(footer, sizeof(footer), "{p %u/%u}", page1, (uint32_t)pageCount);
|
||||
pageOut.push_back('\n');
|
||||
pageOut += footer;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#if !MESHTASTIC_EXCLUDE_LOBBS
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
bool lobbsPaginatePlainText(const std::string &text, uint32_t page1, std::string &pageOut, const char **errMsg);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
#if !MESHTASTIC_EXCLUDE_LOBBS
|
||||
|
||||
#include "serialize.h"
|
||||
#include "LoBBSHooks.h"
|
||||
#include <lodb/LoDB.h>
|
||||
|
||||
#include "LoBBSStackGuard.h"
|
||||
|
||||
static void lobbsDisplayGeneric(const LoScalar &record, std::string &lineOut)
|
||||
{
|
||||
std::string title;
|
||||
std::string body;
|
||||
record.getString(LODB_F_TITLE, title);
|
||||
record.getString(LODB_F_DESCRIPTION, body);
|
||||
if (title.empty() && body.empty()) {
|
||||
lineOut.clear();
|
||||
return;
|
||||
}
|
||||
if (title.empty()) {
|
||||
lineOut = body;
|
||||
return;
|
||||
}
|
||||
if (body.empty()) {
|
||||
lineOut = title;
|
||||
return;
|
||||
}
|
||||
lineOut = title + " (" + body + ")";
|
||||
}
|
||||
|
||||
bool lobbsSerializePlainText(const LoBBSCommandCtx &ctx, const LoBBSResponse &resp, std::string &out)
|
||||
{
|
||||
out.clear();
|
||||
if (!resp.ok) {
|
||||
out = resp.error;
|
||||
return !out.empty();
|
||||
}
|
||||
for (const LoScalar &rec : resp.records) {
|
||||
std::string line;
|
||||
lobbsDisplayGeneric(rec, line);
|
||||
LoScalar shown;
|
||||
shown.setString(LODB_F_TITLE, line);
|
||||
lobbsApplyFilter("display_human", const_cast<LoBBSCommandCtx &>(ctx), shown, rec);
|
||||
line.clear();
|
||||
shown.getString(LODB_F_TITLE, line);
|
||||
if (line.empty())
|
||||
continue;
|
||||
if (!out.empty())
|
||||
out.push_back('\n');
|
||||
out += line;
|
||||
}
|
||||
return !out.empty();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#if !MESHTASTIC_EXCLUDE_LOBBS
|
||||
|
||||
#include "LoBBSCommandCtx.h"
|
||||
#include "LoBBSResponse.h"
|
||||
#include <string>
|
||||
|
||||
bool lobbsSerializePlainText(const LoBBSCommandCtx &ctx, const LoBBSResponse &resp, std::string &out);
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user