123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- const pull = require('../server/node_modules/pull-stream');
- const os = require('os');
- const fs = require('fs');
- const { getConfig } = require('../configs/config-manager.js');
- const logLimit = getConfig().ssbLogStream?.limit || 1000;
- module.exports = ({ cooler }) => {
- let ssb;
- const openSsb = async () => { if (!ssb) ssb = await cooler.open(); return ssb; };
- const types = [
- 'bookmark','event','task','votes','report','feed',
- 'image','audio','video','document','transfer','post','tribe','market','forum','job'
- ];
- const getFolderSize = (folderPath) => {
- const files = fs.readdirSync(folderPath);
- let totalSize = 0;
- for (const file of files) {
- const filePath = `${folderPath}/${file}`;
- const stats = fs.statSync(filePath);
- totalSize += stats.isDirectory() ? getFolderSize(filePath) : stats.size;
- }
- return totalSize;
- };
- const formatSize = (sizeInBytes) => {
- if (sizeInBytes < 1024) return `${sizeInBytes} B`;
- const kb = 1024, mb = kb * 1024, gb = mb * 1024, tb = gb * 1024;
- if (sizeInBytes < mb) return `${(sizeInBytes / kb).toFixed(2)} KB`;
- if (sizeInBytes < gb) return `${(sizeInBytes / mb).toFixed(2)} MB`;
- if (sizeInBytes < tb) return `${(sizeInBytes / gb).toFixed(2)} GB`;
- return `${(sizeInBytes / tb).toFixed(2)} TB`;
- };
- const getStats = async (filter = 'ALL') => {
- const ssbClient = await openSsb();
- const userId = ssbClient.id;
- const messages = await new Promise((res, rej) => {
- pull(
- ssbClient.createLogStream({ limit: logLimit }),
- pull.collect((err, msgs) => err ? rej(err) : res(msgs))
- );
- });
- const allMsgs = messages.filter(m => m.value?.content);
- const tombTargets = new Set(
- allMsgs
- .filter(m => m.value.content.type === 'tombstone' && m.value.content.target)
- .map(m => m.value.content.target)
- );
- const scopedMsgs = filter === 'MINE' ? allMsgs.filter(m => m.value.author === userId) : allMsgs;
- const byType = {};
- const parentOf = {};
- for (const t of types) {
- byType[t] = new Map();
- parentOf[t] = new Map();
- }
- for (const m of scopedMsgs) {
- const k = m.key;
- const c = m.value.content;
- const t = c.type;
- if (!types.includes(t)) continue;
- byType[t].set(k, { key: k, ts: m.value.timestamp, content: c });
- if (c.replaces) parentOf[t].set(k, c.replaces);
- }
- const findRoot = (t, id) => {
- let cur = id;
- const pMap = parentOf[t];
- while (pMap.has(cur)) cur = pMap.get(cur);
- return cur;
- };
- const tipOf = {};
- for (const t of types) {
- tipOf[t] = new Map();
- const pMap = parentOf[t];
- const fwd = new Map();
- for (const [child, parent] of pMap.entries()) {
- fwd.set(parent, child);
- }
- const allMap = byType[t];
- const roots = new Set(Array.from(allMap.keys()).map(id => findRoot(t, id)));
- for (const root of roots) {
- let tip = root;
- while (fwd.has(tip)) tip = fwd.get(tip);
- if (tombTargets.has(tip)) continue;
- const node = allMap.get(tip) || allMap.get(root);
- if (node) tipOf[t].set(root, node);
- }
- }
- const content = {};
- const opinions = {};
- for (const t of types) {
- let vals = Array.from(tipOf[t].values()).map(v => v.content);
- if (t === 'forum') {
- vals = vals.filter(c => !(c.root && tombTargets.has(c.root)));
- }
- content[t] = vals.length;
- opinions[t] = vals.filter(e => Array.isArray(e.opinions_inhabitants) && e.opinions_inhabitants.length > 0).length;
- }
- const tribeVals = Array.from(tipOf['tribe'].values()).map(v => v.content);
- const memberTribes = tribeVals
- .filter(c => Array.isArray(c.members) && c.members.includes(userId))
- .map(c => c.name || c.title || c.id);
- const inhabitants = new Set(allMsgs.map(m => m.value.author)).size;
- const secretStat = fs.statSync(`${os.homedir()}/.ssb/secret`);
- const createdAt = secretStat.birthtime.toLocaleString();
- const folderSize = getFolderSize(`${os.homedir()}/.ssb`);
- const flumeSize = getFolderSize(`${os.homedir()}/.ssb/flume`);
- const blobsSize = getFolderSize(`${os.homedir()}/.ssb/blobs`);
- return {
- id: userId,
- createdAt,
- inhabitants,
- content,
- opinions,
- memberTribes,
- userTombstoneCount: scopedMsgs.filter(m => m.value.content.type === 'tombstone').length,
- networkTombstoneCount: allMsgs.filter(m => m.value.content.type === 'tombstone').length,
- folderSize: formatSize(folderSize),
- statsBlockchainSize: formatSize(flumeSize),
- statsBlobsSize: formatSize(blobsSize)
- };
- };
- return { getStats };
- };
|