embed size limits
This commit is contained in:
@@ -6,6 +6,20 @@
|
||||
|
||||
var BARE_OS_DISCORD_REPLY_MAX = 1900
|
||||
var BARE_OS_DISCORD_FS_MAX = 12 * 1024
|
||||
/** Discord API hard caps (message content / embed parts / combined embed). */
|
||||
var BARE_OS_DISCORD_LIMIT = {
|
||||
content: 2000,
|
||||
title: 256,
|
||||
desc: 4096,
|
||||
fieldName: 256,
|
||||
fieldValue: 1024,
|
||||
footer: 2048,
|
||||
author: 256,
|
||||
fields: 25,
|
||||
embedTotal: 6000,
|
||||
pageChars: 3000
|
||||
}
|
||||
var BARE_OS_DISCORD_MORE_SESSIONS = Object.create(null)
|
||||
/** discord.js MessageFlags.Ephemeral (1 << 6). Avoid the deprecated `ephemeral` option. */
|
||||
var BARE_OS_DISCORD_FLAG_EPHEMERAL = 64
|
||||
var BARE_OS_DISCORD_WHITELIST_DENY =
|
||||
@@ -126,7 +140,44 @@ function discordCmdClip(text, max) {
|
||||
const s = String(text == null ? '' : text)
|
||||
const n = max || BARE_OS_DISCORD_REPLY_MAX
|
||||
if (s.length <= n) return s
|
||||
return s.slice(0, n - 20) + '\n…(truncated)'
|
||||
return discordClipSmart(s, n, '\n…(truncated)').text
|
||||
}
|
||||
|
||||
function discordClipSmart(text, max, suffix) {
|
||||
const s = String(text == null ? '' : text)
|
||||
const tail = suffix == null ? '\n…' : suffix
|
||||
if (s.length <= max) return { text: s, truncated: false, hidden: 0 }
|
||||
const room = Math.max(8, max - tail.length)
|
||||
let cut = s.lastIndexOf('\n', room)
|
||||
if (cut < room * 0.55) {
|
||||
const sp = s.lastIndexOf(' ', room)
|
||||
if (sp > room * 0.55) cut = sp
|
||||
}
|
||||
if (cut < Math.floor(room * 0.4)) cut = room
|
||||
return { text: s.slice(0, cut) + tail, truncated: true, hidden: s.length - cut }
|
||||
}
|
||||
|
||||
function discordSafeDesc(desc, max) {
|
||||
const s = String(desc == null ? '' : desc)
|
||||
if (max <= 0) return ''
|
||||
if (s.length <= max) return s
|
||||
const open = s.indexOf('```')
|
||||
if (open >= 0) {
|
||||
const nl = s.indexOf('\n', open)
|
||||
const close = s.lastIndexOf('```')
|
||||
if (nl > open && close > nl) {
|
||||
const head = s.slice(0, nl + 1)
|
||||
const after = s.slice(close + 3)
|
||||
const hint = '\n…'
|
||||
const budget = max - head.length - 4 - after.length - hint.length
|
||||
if (budget >= 16) {
|
||||
const body = s.slice(nl + 1, close).replace(/\n+$/, '')
|
||||
const fit = discordClipSmart(body, budget, hint)
|
||||
return head + fit.text.replace(/```/g, '`ˋ`') + '\n```' + after
|
||||
}
|
||||
}
|
||||
}
|
||||
return discordClipSmart(s, max, '\n…').text
|
||||
}
|
||||
|
||||
function discordCmdRedact(text) {
|
||||
@@ -135,9 +186,126 @@ function discordCmdRedact(text) {
|
||||
.replace(/(DISCORD_TOKEN|BOT_TOKEN|TOKEN|SECRET|PASSWORD|PASSWD|API_KEY)\s*[=:]\s*\S+/gi, '$1=[redacted]')
|
||||
}
|
||||
|
||||
function discordCmdFence(text, lang) {
|
||||
const body = discordCmdClip(discordCmdRedact(text))
|
||||
return '```' + (lang || '') + '\n' + body.replace(/```/g, '`ˋ`') + '\n```'
|
||||
function discordCmdFence(text, lang, max) {
|
||||
const tag = lang ? String(lang) : ''
|
||||
const wrap = 8 + tag.length
|
||||
const cap = Math.max(32, (max || BARE_OS_DISCORD_LIMIT.desc) - wrap)
|
||||
const fit = discordClipSmart(discordCmdRedact(text).replace(/```/g, '`ˋ`'), cap, '\n…')
|
||||
return '```' + tag + '\n' + fit.text + '\n```'
|
||||
}
|
||||
|
||||
function discordTextPages(text, pageChars) {
|
||||
const s = String(text == null ? '' : text)
|
||||
const size = Math.max(200, pageChars || BARE_OS_DISCORD_LIMIT.pageChars)
|
||||
if (!s) return ['']
|
||||
if (s.length <= size) return [s]
|
||||
const pages = []
|
||||
let i = 0
|
||||
while (i < s.length) {
|
||||
if (s.length - i <= size) {
|
||||
pages.push(s.slice(i))
|
||||
break
|
||||
}
|
||||
let cut = s.lastIndexOf('\n', i + size)
|
||||
if (cut <= i + Math.floor(size * 0.4)) cut = i + size
|
||||
pages.push(s.slice(i, cut))
|
||||
i = cut
|
||||
while (s.charAt(i) === '\n') i++
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
function discordEmbedSize(e) {
|
||||
if (!e) return 0
|
||||
let n = 0
|
||||
if (e.title) n += String(e.title).length
|
||||
if (e.description) n += String(e.description).length
|
||||
if (e.footer && e.footer.text) n += String(e.footer.text).length
|
||||
if (e.author && e.author.name) n += String(e.author.name).length
|
||||
const fs = e.fields || []
|
||||
for (let i = 0; i < fs.length; i++) {
|
||||
n += String(fs[i].name || '').length + String(fs[i].value || '').length
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
function discordPackEmbed(opts) {
|
||||
const o = opts || {}
|
||||
const L = BARE_OS_DISCORD_LIMIT
|
||||
const title = o.title ? String(o.title).slice(0, L.title) : ''
|
||||
const footer = String(o.footer || 'Bare OS · expires after 2m idle').slice(0, L.footer)
|
||||
const authorName = o.author && o.author.name ? String(o.author.name).slice(0, L.author) : ''
|
||||
const chrome = title.length + footer.length + authorName.length
|
||||
const preferDesc = o.prefer === 'desc'
|
||||
const rawFields = []
|
||||
if (o.fields && o.fields.length) {
|
||||
for (let i = 0; i < o.fields.length && rawFields.length < L.fields; i++) {
|
||||
const f = o.fields[i]
|
||||
if (!f) continue
|
||||
let v = String(f.value == null ? '' : f.value).trim()
|
||||
if (!v || v === '—') continue
|
||||
v = discordCmdRedact(v)
|
||||
if (v.length > L.fieldValue) v = discordClipSmart(v, L.fieldValue, '\n…').text
|
||||
rawFields.push({
|
||||
name: String(f.name || '·').slice(0, L.fieldName),
|
||||
value: v,
|
||||
inline: Boolean(f.inline)
|
||||
})
|
||||
}
|
||||
}
|
||||
let fieldBytes = 0
|
||||
for (let i = 0; i < rawFields.length; i++) {
|
||||
fieldBytes += rawFields[i].name.length + rawFields[i].value.length
|
||||
}
|
||||
let descRoom
|
||||
if (preferDesc) {
|
||||
descRoom = Math.min(L.desc, Math.max(0, L.embedTotal - chrome - Math.min(fieldBytes, 900)))
|
||||
} else {
|
||||
descRoom = Math.min(L.desc, Math.max(0, L.embedTotal - chrome - fieldBytes))
|
||||
}
|
||||
let desc = o.desc ? discordCmdRedact(String(o.desc)) : ''
|
||||
if (desc) desc = discordSafeDesc(desc, descRoom)
|
||||
let fields = rawFields.slice()
|
||||
let used = chrome + desc.length + fieldBytes
|
||||
if (used > L.embedTotal && fields.length) {
|
||||
const keep = []
|
||||
let acc = chrome + desc.length
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
const add = fields[i].name.length + fields[i].value.length
|
||||
if (acc + add > L.embedTotal - 48) break
|
||||
keep.push(fields[i])
|
||||
acc += add
|
||||
}
|
||||
const omitted = fields.length - keep.length
|
||||
if (omitted > 0) {
|
||||
const note = '_' + omitted + ' more not shown_'
|
||||
if (keep.length && acc + note.length + 8 <= L.embedTotal) {
|
||||
keep.push({ name: '…', value: note, inline: false })
|
||||
} else if (desc.length + 2 + note.length <= L.desc) {
|
||||
desc = (desc ? desc + '\n' : '') + note
|
||||
}
|
||||
}
|
||||
fields = keep
|
||||
used = chrome + desc.length
|
||||
for (let i = 0; i < fields.length; i++) used += fields[i].name.length + fields[i].value.length
|
||||
}
|
||||
if (used > L.embedTotal && desc) {
|
||||
desc = discordSafeDesc(desc, Math.max(0, desc.length - (used - L.embedTotal)))
|
||||
}
|
||||
const embed = {
|
||||
color: o.color == null ? BARE_OS_DISCORD_COLOR : o.color,
|
||||
timestamp: new Date().toISOString(),
|
||||
footer: { text: footer }
|
||||
}
|
||||
if (title) embed.title = title
|
||||
if (desc) embed.description = desc
|
||||
if (fields.length) embed.fields = fields
|
||||
if (o.author) embed.author = { name: authorName || 'Bare OS' }
|
||||
return {
|
||||
embed: embed,
|
||||
truncated: fields.length < rawFields.length || !!(o.desc && desc.length < String(o.desc).length),
|
||||
size: discordEmbedSize(embed)
|
||||
}
|
||||
}
|
||||
|
||||
function discordTryJson(raw) {
|
||||
@@ -340,15 +508,20 @@ function discordPrettySnapshot(title, raw, extras) {
|
||||
const parsed = discordTryJson(raw)
|
||||
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
||||
const text = raw == null ? '' : String(raw)
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
if (!text) {
|
||||
return discordResult(discordEmbed({ title: title, desc: 'unavailable' }), extras)
|
||||
}
|
||||
return {
|
||||
more: {
|
||||
title: title,
|
||||
desc: text
|
||||
? discordCmdFence(discordCmdClip(text, 1400))
|
||||
: 'unavailable'
|
||||
}),
|
||||
extras
|
||||
)
|
||||
body: text,
|
||||
fence: true,
|
||||
components: extras && extras.components,
|
||||
editPath: extras && extras.editPath,
|
||||
created: extras && extras.created,
|
||||
color: extras && extras.color
|
||||
}
|
||||
}
|
||||
}
|
||||
const fields = []
|
||||
discordCollectFields(parsed, '', fields, 0)
|
||||
@@ -479,34 +652,119 @@ function discordCmdReplyPayload(result) {
|
||||
}
|
||||
|
||||
function discordEmbed(opts) {
|
||||
const o = opts || {}
|
||||
const e = {
|
||||
color: o.color == null ? BARE_OS_DISCORD_COLOR : o.color,
|
||||
timestamp: new Date().toISOString(),
|
||||
footer: { text: o.footer || 'Bare OS · expires after 2m idle' }
|
||||
}
|
||||
if (o.title) e.title = String(o.title).slice(0, 256)
|
||||
if (o.desc) e.description = discordCmdClip(discordCmdRedact(o.desc), 1800)
|
||||
if (o.fields && o.fields.length) {
|
||||
const fields = []
|
||||
for (let i = 0; i < o.fields.length && fields.length < 25; i++) {
|
||||
const f = o.fields[i]
|
||||
if (!f) continue
|
||||
const v = String(f.value == null ? '' : f.value).trim()
|
||||
if (!v || v === '—') continue
|
||||
fields.push(f)
|
||||
}
|
||||
if (fields.length) e.fields = fields
|
||||
}
|
||||
if (o.author) e.author = o.author
|
||||
return e
|
||||
return discordPackEmbed(opts).embed
|
||||
}
|
||||
|
||||
function discordField(name, value, inline) {
|
||||
let v = value == null || value === '' ? '—' : String(value)
|
||||
v = discordCmdClip(discordCmdRedact(v), 1024)
|
||||
v = discordCmdRedact(v)
|
||||
if (v.length > BARE_OS_DISCORD_LIMIT.fieldValue) {
|
||||
v = discordClipSmart(v, BARE_OS_DISCORD_LIMIT.fieldValue, '\n…').text
|
||||
}
|
||||
if (!v) v = '—'
|
||||
return { name: String(name).slice(0, 256), value: v, inline: Boolean(inline) }
|
||||
return {
|
||||
name: String(name).slice(0, BARE_OS_DISCORD_LIMIT.fieldName),
|
||||
value: v,
|
||||
inline: Boolean(inline)
|
||||
}
|
||||
}
|
||||
|
||||
function discordMoreKey(interaction) {
|
||||
return discordInteractionUserId(interaction) || 'anon'
|
||||
}
|
||||
|
||||
function discordMoreGc() {
|
||||
const now = Date.now()
|
||||
for (const k in BARE_OS_DISCORD_MORE_SESSIONS) {
|
||||
const r = BARE_OS_DISCORD_MORE_SESSIONS[k]
|
||||
if (!r || now - r.atMs > BARE_OS_DISCORD_IDLE_MS) delete BARE_OS_DISCORD_MORE_SESSIONS[k]
|
||||
}
|
||||
}
|
||||
|
||||
function discordMorePut(interaction, rec) {
|
||||
discordMoreGc()
|
||||
rec.atMs = Date.now()
|
||||
BARE_OS_DISCORD_MORE_SESSIONS[discordMoreKey(interaction)] = rec
|
||||
}
|
||||
|
||||
function discordMoreGet(interaction) {
|
||||
discordMoreGc()
|
||||
return BARE_OS_DISCORD_MORE_SESSIONS[discordMoreKey(interaction)] || null
|
||||
}
|
||||
|
||||
function discordMoreResult(interaction) {
|
||||
const rec = discordMoreGet(interaction)
|
||||
if (!rec) return { text: 'This view expired after 2 minutes idle.', ephemeral: true }
|
||||
const n = rec.pages.length
|
||||
if (rec.page < 0) rec.page = n - 1
|
||||
if (rec.page >= n) rec.page = 0
|
||||
rec.atMs = Date.now()
|
||||
const chunk = rec.pages[rec.page] || ''
|
||||
const inner = rec.fence === false ? chunk : discordCmdFence(chunk, rec.lang, 3600)
|
||||
const navline =
|
||||
n > 1
|
||||
? '\nPage **' + (rec.page + 1) + '/' + n + '** · ' + rec.total + ' characters'
|
||||
: ''
|
||||
const btns =
|
||||
n > 1
|
||||
? discordButtons([
|
||||
{ id: 'more:prev', label: '← Prev' },
|
||||
{ id: 'more:next', label: 'Next →', style: 1 }
|
||||
])
|
||||
: null
|
||||
const extra = (rec.extra || []).concat(btns ? [btns] : [])
|
||||
const out = discordResult(
|
||||
discordEmbed({
|
||||
title: rec.title,
|
||||
desc: (rec.lead || '') + inner + navline,
|
||||
color: rec.color,
|
||||
footer: rec.footer,
|
||||
prefer: 'desc'
|
||||
}),
|
||||
{ components: extra }
|
||||
)
|
||||
return out
|
||||
}
|
||||
|
||||
function discordLongTextResult(interaction, opts) {
|
||||
const o = opts || {}
|
||||
const body = String(o.body == null ? '' : o.body)
|
||||
const pages = discordTextPages(body, o.pageChars || BARE_OS_DISCORD_LIMIT.pageChars)
|
||||
const extraComps = o.components || []
|
||||
if (pages.length > 1) {
|
||||
let lead = o.lead ? String(o.lead) : ''
|
||||
if (lead && !/\n$/.test(lead)) lead += '\n'
|
||||
discordMorePut(interaction, {
|
||||
title: o.title,
|
||||
pages: pages,
|
||||
page: 0,
|
||||
fence: o.fence !== false,
|
||||
lang: o.lang || '',
|
||||
lead: lead,
|
||||
color: o.color,
|
||||
footer: o.footer,
|
||||
extra: extraComps,
|
||||
total: body.length
|
||||
})
|
||||
const view = discordMoreResult(interaction)
|
||||
if (o.editPath) view.editPath = o.editPath
|
||||
if (o.created) view.created = true
|
||||
return view
|
||||
}
|
||||
const inner = o.fence === false ? body : discordCmdFence(body, o.lang, 3800)
|
||||
let lead = o.lead ? String(o.lead) : ''
|
||||
if (lead && inner && !/\n$/.test(lead)) lead += '\n'
|
||||
const out = discordResult(
|
||||
discordEmbed({
|
||||
title: o.title,
|
||||
desc: lead + inner,
|
||||
color: o.color,
|
||||
footer: o.footer,
|
||||
prefer: 'desc'
|
||||
}),
|
||||
{ components: extraComps, editPath: o.editPath, created: o.created }
|
||||
)
|
||||
return out
|
||||
}
|
||||
|
||||
function discordButtons(items) {
|
||||
@@ -1241,12 +1499,10 @@ async function discordCmdHandleBare(ctx, sub) {
|
||||
}
|
||||
if (sub === 'motd') {
|
||||
const t = await discordCmdReadText(ctx, '/etc/motd')
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
title: 'motd',
|
||||
desc: t ? discordCmdFence(t) : '(no /etc/motd)'
|
||||
})
|
||||
)
|
||||
if (!t) {
|
||||
return discordResult(discordEmbed({ title: 'motd', desc: 'No `/etc/motd`.' }))
|
||||
}
|
||||
return { more: { title: 'motd', body: t, fence: true } }
|
||||
}
|
||||
return { text: 'unknown /bare subcommand', ephemeral: true }
|
||||
}
|
||||
@@ -1646,19 +1902,26 @@ async function discordCmdHandleSvc(ctx, sub, unit) {
|
||||
: sub === 'start' || sub === 'restart'
|
||||
? BARE_OS_DISCORD_COLOR_OK
|
||||
: BARE_OS_DISCORD_COLOR
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
if (!out) {
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
title: name,
|
||||
desc: 'No output from `systemctl ' + sub + '`.',
|
||||
color: color
|
||||
}),
|
||||
{ components: act ? [act] : [] }
|
||||
)
|
||||
}
|
||||
return {
|
||||
more: {
|
||||
title: name,
|
||||
desc: out
|
||||
? '`' +
|
||||
sub +
|
||||
'`\n' +
|
||||
discordCmdFence(discordCmdClip(discordCmdRedact(out), 1100))
|
||||
: 'No output from `systemctl ' + sub + '`.',
|
||||
color: color
|
||||
}),
|
||||
{ components: act ? [act] : [] }
|
||||
)
|
||||
lead: '`' + sub + '`',
|
||||
body: discordCmdRedact(out),
|
||||
fence: true,
|
||||
color: color,
|
||||
components: act ? [act] : []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
|
||||
@@ -1682,22 +1945,21 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
|
||||
})
|
||||
.join(' ')
|
||||
: '(empty)'
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
return {
|
||||
more: {
|
||||
title: 'Listing',
|
||||
desc:
|
||||
lead:
|
||||
'`' +
|
||||
p +
|
||||
'` · ' +
|
||||
list.length +
|
||||
' ' +
|
||||
(list.length === 1 ? 'entry' : 'entries') +
|
||||
'\n' +
|
||||
desc +
|
||||
(list.length > shown.length ? '\n+' + (list.length - shown.length) + ' more' : ''),
|
||||
(list.length === 1 ? 'entry' : 'entries'),
|
||||
body: desc === '(empty)' ? '' : shown.join('\n'),
|
||||
fence: desc !== '(empty)',
|
||||
footer: discordSessionUser(ctx)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
return { text: 'ls failed: ' + ((err && err.message) || err), ephemeral: true }
|
||||
}
|
||||
@@ -1753,23 +2015,30 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
|
||||
return discordPrettySnapshot(p, asJson, extra)
|
||||
}
|
||||
if (sub === 'head') {
|
||||
const n = Math.max(1, Math.min(40, Number(nlines) || 12))
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
const n = Math.max(1, Math.min(80, Number(nlines) || 12))
|
||||
const head = text.split(/\r?\n/).slice(0, n).join('\n')
|
||||
return {
|
||||
more: {
|
||||
title: 'Head',
|
||||
desc: '`' + p + '` · first ' + n + ' lines\n' + discordCmdFence(text.split(/\r?\n/).slice(0, n).join('\n'))
|
||||
}),
|
||||
extra
|
||||
)
|
||||
lead: '`' + p + '` · first ' + n + ' lines',
|
||||
body: head,
|
||||
fence: true,
|
||||
components: extra.components,
|
||||
editPath: extra.editPath
|
||||
}
|
||||
}
|
||||
}
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
return {
|
||||
more: {
|
||||
title: 'File',
|
||||
desc: '`' + p + '`\n' + discordCmdFence(text.slice(0, BARE_OS_DISCORD_FS_MAX)),
|
||||
footer: text.length + ' bytes · ' + discordSessionUser(ctx)
|
||||
}),
|
||||
extra
|
||||
)
|
||||
lead: '`' + p + '`',
|
||||
body: text.slice(0, BARE_OS_DISCORD_FS_MAX),
|
||||
fence: true,
|
||||
footer: text.length + ' bytes · ' + discordSessionUser(ctx),
|
||||
components: extra.components,
|
||||
editPath: extra.editPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function discordFormatNetSummary(obj) {
|
||||
@@ -1962,13 +2231,13 @@ async function discordCmdHandleMan(ctx, page) {
|
||||
const clean = String(out)
|
||||
.replace(/\x1b\[[0-9;]*m/g, '')
|
||||
.trim()
|
||||
const first = clean.split(/\r?\n/).slice(0, 28).join('\n')
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
return {
|
||||
more: {
|
||||
title: 'man ' + name,
|
||||
desc: discordCmdClip(first, 1600)
|
||||
})
|
||||
)
|
||||
body: clean,
|
||||
fence: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const t = await discordCmdReadText(ctx, '/share/man/man.json')
|
||||
@@ -1979,14 +2248,14 @@ async function discordCmdHandleMan(ctx, page) {
|
||||
for (let i = 0; i < pages.length; i++) {
|
||||
if (pages[i] && pages[i].name === name) {
|
||||
const p = pages[i]
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
return {
|
||||
more: {
|
||||
title: 'man ' + (p.title || name),
|
||||
desc:
|
||||
(p.synopsis && p.synopsis[0] ? '`' + p.synopsis[0] + '`\n\n' : '') +
|
||||
String(p.description || '').slice(0, 1400)
|
||||
})
|
||||
)
|
||||
lead: p.synopsis && p.synopsis[0] ? '`' + p.synopsis[0] + '`' : '',
|
||||
body: String(p.description || ''),
|
||||
fence: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
@@ -2036,15 +2305,23 @@ async function discordCmdHandleRun(ctx, raw) {
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
return discordPrettySnapshot('$ ' + key, parsed)
|
||||
}
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
if (!out) {
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
title: '$ ' + key,
|
||||
footer: 'ran as ' + discordSessionUser(ctx),
|
||||
desc: '(no output, exit ' + String(ctx.exitCode || 0) + ')'
|
||||
})
|
||||
)
|
||||
}
|
||||
return {
|
||||
more: {
|
||||
title: '$ ' + key,
|
||||
footer: 'ran as ' + discordSessionUser(ctx),
|
||||
desc: out
|
||||
? discordCmdFence(discordCmdClip(discordCmdRedact(out), 1400))
|
||||
: '(no output, exit ' + String(ctx.exitCode || 0) + ')'
|
||||
})
|
||||
)
|
||||
body: discordCmdRedact(out),
|
||||
fence: true,
|
||||
footer: 'ran as ' + discordSessionUser(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function discordCmdHandleJournal(ctx, unit) {
|
||||
@@ -2058,47 +2335,23 @@ async function discordCmdHandleJournal(ctx, unit) {
|
||||
'30'
|
||||
])
|
||||
})
|
||||
const lines = String(out || '')
|
||||
.split(/\r?\n/)
|
||||
.filter(Boolean)
|
||||
.slice(-20)
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
title: 'Journal · ' + unit,
|
||||
desc: lines.length
|
||||
? discordCmdFence(
|
||||
lines
|
||||
.map(function (ln) {
|
||||
return discordCmdRedact(ln).slice(0, 180)
|
||||
})
|
||||
.join('\n')
|
||||
)
|
||||
: 'Empty journal for `' + unit + '`.'
|
||||
})
|
||||
)
|
||||
const body = discordCmdRedact(String(out || ''))
|
||||
if (!body.trim()) {
|
||||
return discordResult(
|
||||
discordEmbed({ title: 'Journal · ' + unit, desc: 'Empty journal for `' + unit + '`.' })
|
||||
)
|
||||
}
|
||||
return { more: { title: 'Journal · ' + unit, body: body, fence: true } }
|
||||
}
|
||||
const t =
|
||||
(await discordCmdReadText(ctx, '/var/log/bare-os/discord.log')) ||
|
||||
(await discordCmdReadText(ctx, '/var/log/bare-os/kernel-console.log')) ||
|
||||
(await discordCmdReadText(ctx, '/var/log/messages'))
|
||||
const lines = String(t || '')
|
||||
.split(/\r?\n/)
|
||||
.filter(Boolean)
|
||||
.slice(-18)
|
||||
return discordResult(
|
||||
discordEmbed({
|
||||
title: 'Journal',
|
||||
desc: lines.length
|
||||
? discordCmdFence(
|
||||
lines
|
||||
.map(function (ln) {
|
||||
return discordCmdRedact(ln).slice(0, 180)
|
||||
})
|
||||
.join('\n')
|
||||
)
|
||||
: 'No journal in `/var/log/bare-os`.'
|
||||
})
|
||||
)
|
||||
const body = discordCmdRedact(String(t || ''))
|
||||
if (!body.trim()) {
|
||||
return discordResult(discordEmbed({ title: 'Journal', desc: 'No journal in `/var/log/bare-os`.' }))
|
||||
}
|
||||
return { more: { title: 'Journal', body: body, fence: true } }
|
||||
}
|
||||
|
||||
function discordPanel(ctx) {
|
||||
@@ -3697,6 +3950,7 @@ function discordIdleForgetSessions(userId) {
|
||||
delete BARE_OS_DISCORD_EDIT_SESSIONS[userId]
|
||||
delete BARE_OS_DISCORD_FM_SESSIONS[userId]
|
||||
delete BARE_OS_DISCORD_SET_SESSIONS[userId]
|
||||
delete BARE_OS_DISCORD_MORE_SESSIONS[userId]
|
||||
}
|
||||
|
||||
function discordUnwrapMessage(sent) {
|
||||
@@ -3815,6 +4069,9 @@ async function discordIdleWatch(interaction, payload, sent) {
|
||||
}
|
||||
|
||||
async function discordSendResult(ctx, interaction, result) {
|
||||
if (result && result.more) {
|
||||
return discordSendResult(ctx, interaction, discordLongTextResult(interaction, result.more))
|
||||
}
|
||||
if (result && result.editPath) {
|
||||
const prev = discordEditGet(interaction)
|
||||
discordEditPut(interaction, {
|
||||
@@ -4128,6 +4385,17 @@ async function discordDispatchComponent(ctx, interaction) {
|
||||
const opt = function () {
|
||||
return ''
|
||||
}
|
||||
if (id === 'more:prev' || id === 'more:next') {
|
||||
const rec = discordMoreGet(interaction)
|
||||
if (!rec) {
|
||||
return discordSendResult(ctx, interaction, {
|
||||
text: 'This view expired after 2 minutes idle.',
|
||||
ephemeral: true
|
||||
})
|
||||
}
|
||||
rec.page += id === 'more:next' ? 1 : -1
|
||||
return discordSendResult(ctx, interaction, discordMoreResult(interaction))
|
||||
}
|
||||
if (id.indexOf('set:') === 0) {
|
||||
await discordSettingsAction(ctx, interaction, id)
|
||||
return true
|
||||
@@ -4596,6 +4864,11 @@ var bareOsDiscordCommands = {
|
||||
uniqueComponents: discordUniqueComponents,
|
||||
navRows: discordNavRows,
|
||||
result: discordResult,
|
||||
packEmbed: discordPackEmbed,
|
||||
textPages: discordTextPages,
|
||||
clipSmart: discordClipSmart,
|
||||
embedSize: discordEmbedSize,
|
||||
LIMIT: BARE_OS_DISCORD_LIMIT,
|
||||
idleMs: BARE_OS_DISCORD_IDLE_MS,
|
||||
idleExpire: discordIdleExpire,
|
||||
idleSweep: discordIdleSweep,
|
||||
|
||||
Reference in New Issue
Block a user