sync: auto-sync from HOWARD-HOME at 2026-07-07 20:31:16
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-07-07 20:31:16
This commit is contained in:
@@ -57,6 +57,8 @@ if [ "${1:-}" = "--read" ]; then
|
||||
THREAD="${2:-}"
|
||||
LIMIT="${3:-25}"
|
||||
[ -z "$THREAD" ] && { echo "[ERROR] usage: ask-forum.sh --read <thread_id> [limit]" >&2; exit 1; }
|
||||
printf '%s' "$LIMIT" | grep -qE '^[0-9]+$' || LIMIT=25 # Discord caps at 100
|
||||
[ "$LIMIT" -lt 1 ] && LIMIT=1; [ "$LIMIT" -gt 100 ] && LIMIT=100
|
||||
TOKEN="$(resolve_token)"
|
||||
[ -z "$TOKEN" ] || [ "$TOKEN" = "null" ] && { echo "[ERROR] no Discord bot token" >&2; exit 2; }
|
||||
auth=(-H "Authorization: Bot ${TOKEN}" -H "User-Agent: ${UA}")
|
||||
@@ -86,15 +88,20 @@ if [ "${1:-}" = "--wait" ]; then
|
||||
TOKEN="$(resolve_token)"
|
||||
[ -z "$TOKEN" ] || [ "$TOKEN" = "null" ] && { echo "[ERROR] no Discord bot token" >&2; exit 2; }
|
||||
auth=(-H "Authorization: Bot ${TOKEN}" -H "User-Agent: ${UA}")
|
||||
# baseline = id of newest message present right now
|
||||
AFTER="$(curl -s -m 20 "${auth[@]}" "$API/channels/${THREAD}/messages?limit=1" | jq -r '.[0].id // "0"' 2>/dev/null)"
|
||||
[ -z "$AFTER" ] && AFTER="0"
|
||||
# baseline: for a forum post the starter message id == the thread id, so
|
||||
# after=<thread> returns every human reply after the starter -- this catches a
|
||||
# reply that already landed BEFORE this --wait began (the old "newest message
|
||||
# now" baseline missed it and hung to timeout).
|
||||
AFTER="${THREAD}"
|
||||
echo "[INFO] waiting on thread ${THREAD} for a human reply (up to ${TIMEOUT}s)..." >&2
|
||||
DEADLINE=$(( $(date +%s) + TIMEOUT ))
|
||||
while [ "$(date +%s)" -lt "$DEADLINE" ]; do
|
||||
sleep "$POLL"
|
||||
MSGS="$(curl -s -m 20 "${auth[@]}" "$API/channels/${THREAD}/messages?after=${AFTER}")"
|
||||
printf '%s' "$MSGS" | jq -e 'type=="array"' >/dev/null 2>&1 || continue
|
||||
if ! printf '%s' "$MSGS" | jq -e 'type=="array"' >/dev/null 2>&1; then
|
||||
# thread gone -> bail fast; otherwise (transient/429) keep waiting
|
||||
printf '%s' "$MSGS" | jq -e '.code==10003' >/dev/null 2>&1 && { echo "[ERROR] thread ${THREAD} no longer exists" >&2; exit 3; }
|
||||
sleep "$POLL"; continue
|
||||
fi
|
||||
HUMAN="$(printf '%s' "$MSGS" | jq -c 'reverse[] | select(.author.bot|not) | {u:.author.username, c:.content}')"
|
||||
if [ -n "$HUMAN" ]; then
|
||||
echo "[OK] answer received in thread ${THREAD}:"
|
||||
@@ -102,6 +109,7 @@ if [ "${1:-}" = "--wait" ]; then
|
||||
echo "THREAD_ID=${THREAD}"
|
||||
exit 0
|
||||
fi
|
||||
sleep "$POLL"
|
||||
done
|
||||
echo "[TIMEOUT] no human reply on thread ${THREAD} within ${TIMEOUT}s" >&2
|
||||
echo "THREAD_ID=${THREAD}" >&2
|
||||
@@ -149,7 +157,18 @@ fi
|
||||
auth=(-H "Authorization: Bot ${TOKEN}" -H "Content-Type: application/json" -H "User-Agent: ${UA}")
|
||||
|
||||
# --- create the forum post (thread) with the question ---
|
||||
BODY="$(jq -nc --arg name "$TITLE" --arg c "$CONTENT" '{name:$name, message:{content:$c}}')"
|
||||
# Discord caps message content at 2000 chars. Keep the starter <=1900 and send any
|
||||
# overflow as follow-up messages in the created thread (rare, but don't hard-fail).
|
||||
LIMIT_CHARS=1900
|
||||
STARTER_CONTENT="$CONTENT"
|
||||
OVERFLOW=""
|
||||
if [ "${#CONTENT}" -gt "$LIMIT_CHARS" ]; then
|
||||
STARTER_CONTENT="${CONTENT:0:$LIMIT_CHARS}"
|
||||
nl="${STARTER_CONTENT%$'\n'*}"
|
||||
[ "${#nl}" -lt "${#STARTER_CONTENT}" ] && [ "${#nl}" -gt 0 ] && STARTER_CONTENT="$nl"
|
||||
OVERFLOW="${CONTENT:${#STARTER_CONTENT}}"; OVERFLOW="${OVERFLOW#$'\n'}"
|
||||
fi
|
||||
BODY="$(jq -nc --arg name "$TITLE" --arg c "$STARTER_CONTENT" '{name:$name, message:{content:$c}}')"
|
||||
RESP="$(printf '%s' "$BODY" | curl -s -m 20 -w $'\n%{http_code}' "${auth[@]}" \
|
||||
-X POST "$API/channels/${FORUM_ID}/threads" --data-binary @-)"
|
||||
HTTP="$(printf '%s' "$RESP" | tail -n1)"
|
||||
@@ -165,17 +184,29 @@ if [ -z "$THREAD" ]; then
|
||||
echo "[ERROR] posted but no thread id in response: $(printf '%s' "$JSON" | head -c 200)" >&2
|
||||
exit 3
|
||||
fi
|
||||
# --- post any overflow chunks as follow-up messages in the new thread ---
|
||||
rest="$OVERFLOW"
|
||||
while [ -n "$rest" ]; do
|
||||
piece="${rest:0:$LIMIT_CHARS}"
|
||||
nl="${piece%$'\n'*}"; [ "${#nl}" -lt "${#piece}" ] && [ "${#nl}" -gt 0 ] && piece="$nl"
|
||||
printf '%s' "$(jq -nc --arg c "$piece" '{content:$c}')" | \
|
||||
curl -s -m 15 "${auth[@]}" -X POST "$API/channels/${THREAD}/messages" --data-binary @- >/dev/null 2>&1
|
||||
rest="${rest:${#piece}}"; rest="${rest#$'\n'}"
|
||||
done
|
||||
|
||||
echo "[INFO] asked in #ct-forum (thread=${THREAD}) — waiting up to ${TIMEOUT}s for a human reply..." >&2
|
||||
|
||||
# --- block-poll the thread for the first NON-BOT reply ---
|
||||
AFTER="${STARTER:-0}"
|
||||
# starter message id == thread id for a forum post, so after=<starter> = all replies.
|
||||
AFTER="${STARTER:-$THREAD}"
|
||||
DEADLINE=$(( $(date +%s) + TIMEOUT ))
|
||||
while [ "$(date +%s)" -lt "$DEADLINE" ]; do
|
||||
sleep "$POLL"
|
||||
Q="after=${AFTER}"
|
||||
[ "$AFTER" = "0" ] && Q="limit=50"
|
||||
MSGS="$(curl -s -m 20 "${auth[@]}" "$API/channels/${THREAD}/messages?${Q}")"
|
||||
printf '%s' "$MSGS" | jq -e 'type=="array"' >/dev/null 2>&1 || continue
|
||||
MSGS="$(curl -s -m 20 "${auth[@]}" "$API/channels/${THREAD}/messages?after=${AFTER}")"
|
||||
if ! printf '%s' "$MSGS" | jq -e 'type=="array"' >/dev/null 2>&1; then
|
||||
printf '%s' "$MSGS" | jq -e '.code==10003' >/dev/null 2>&1 && { echo "[ERROR] thread ${THREAD} disappeared" >&2; exit 3; }
|
||||
continue
|
||||
fi
|
||||
# oldest-first; keep only human (non-bot) messages
|
||||
HUMAN="$(printf '%s' "$MSGS" | jq -c 'reverse[] | select(.author.bot|not) | {u:.author.username, c:.content, id:.id}')"
|
||||
if [ -n "$HUMAN" ]; then
|
||||
|
||||
Reference in New Issue
Block a user