secubox-openwrt/package/secubox/secubox-p2p/root/www/api/factory/packages-sync
CyberMind-FR 304ac7b9a1 feat: P2P App Store, Remote Access & Mesh Media packages
P2P App Store Emancipation:
- secubox-p2p: Package distribution via mesh peers (CGI API, RPCD, CLI)
- packages.js: LuCI view with LOCAL/PEER badges, fetch/install actions
- devstatus.js: Dev Status widget with Gitea commits, v1.0 progress tracking
- secubox-feed: sync-content command for auto-installing content packages
- ACL fix for P2P feed RPCD methods

Remote Access:
- secubox-app-rustdesk: Native hbbs/hbbr relay server from GitHub releases
- secubox-app-guacamole: LXC Debian container with guacd + Tomcat (partial)

Content Distribution:
- secubox-content-pkg: Auto-package Metablogizer/Streamlit as IPKs
- Auto-publish hooks in metablogizerctl and streamlitctl

Mesh Media:
- secubox-app-ksmbd: In-kernel SMB3 server with ksmbdctl CLI
- Pre-configured shares for Jellyfin, Lyrion, Backup

UI Consistency:
- client-guardian: Ported to sh-page-header chip layout
- auth-guardian: Ported to sh-page-header chip layout

Fixes:
- services.js: RPC expect unwrapping bug fix
- metablogizer: Chunked upload for uhttpd 64KB limit

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 00:33:53 +01:00

174 lines
4.3 KiB
Bash

#!/bin/sh
# P2P Package Catalog Sync API
# Aggregates package catalogs from all mesh peers
echo "Content-Type: application/json"
echo "Access-Control-Allow-Origin: *"
echo "Access-Control-Allow-Methods: GET, POST, OPTIONS"
echo ""
# Handle CORS preflight
if [ "$REQUEST_METHOD" = "OPTIONS" ]; then
exit 0
fi
# Load P2P feed library
. /usr/lib/secubox/p2p-feed.sh 2>/dev/null
# Parse query string
parse_query() {
local query="$QUERY_STRING"
local key value
PEER_FILTER=""
REFRESH=""
while [ -n "$query" ]; do
key="${query%%=*}"
query="${query#*=}"
value="${query%%&*}"
query="${query#*&}"
[ "$query" = "$value" ] && query=""
case "$key" in
peer) PEER_FILTER="$value" ;;
refresh) REFRESH="$value" ;;
esac
done
}
parse_query
# Invalidate cache if refresh requested
if [ "$REFRESH" = "1" ]; then
invalidate_peer_cache
fi
# Get node info
NODE_ID=$(get_local_node_id)
NODE_NAME=$(get_local_node_name)
UPDATED=$(date -Iseconds 2>/dev/null || date '+%Y-%m-%dT%H:%M:%S')
# Start JSON output
echo '{'
echo "\"node_id\":\"$NODE_ID\","
echo "\"node_name\":\"$NODE_NAME\","
echo "\"updated\":\"$UPDATED\","
# Sync stats
PEERS_SYNCED=0
PEERS_FAILED=0
TOTAL_PACKAGES=0
echo '"sources":['
FIRST_SOURCE=1
# Include local packages
if feed_exists; then
LOCAL_COUNT=$(get_package_count)
TOTAL_PACKAGES=$LOCAL_COUNT
echo '{'
echo "\"node_id\":\"$NODE_ID\","
echo "\"node_name\":\"$NODE_NAME\","
echo "\"type\":\"local\","
echo "\"address\":\"local\","
echo "\"status\":\"ok\","
echo "\"feed_hash\":\"$(get_feed_hash)\","
echo "\"package_count\":$LOCAL_COUNT,"
echo "\"packages\":$(packages_to_json)"
echo '}'
FIRST_SOURCE=0
fi
# Sync from peers
PEERS_FILE="/tmp/secubox-p2p-peers.json"
if [ -f "$PEERS_FILE" ]; then
PEER_COUNT=$(jsonfilter -i "$PEERS_FILE" -e '@.peers[*]' 2>/dev/null | wc -l)
I=0
while [ $I -lt $PEER_COUNT ]; do
IS_LOCAL=$(jsonfilter -i "$PEERS_FILE" -e "@.peers[$I].is_local" 2>/dev/null)
[ "$IS_LOCAL" = "true" ] && { I=$((I + 1)); continue; }
PEER_ADDR=$(jsonfilter -i "$PEERS_FILE" -e "@.peers[$I].address" 2>/dev/null)
PEER_NAME=$(jsonfilter -i "$PEERS_FILE" -e "@.peers[$I].name" 2>/dev/null)
PEER_WG=$(jsonfilter -i "$PEERS_FILE" -e "@.peers[$I].wg_addresses" 2>/dev/null | cut -d',' -f1)
# Prefer WireGuard address
USE_ADDR="$PEER_ADDR"
[ -n "$PEER_WG" ] && USE_ADDR="$PEER_WG"
# Skip if filtering for specific peer
if [ -n "$PEER_FILTER" ] && [ "$USE_ADDR" != "$PEER_FILTER" ] && [ "$PEER_NAME" != "$PEER_FILTER" ]; then
I=$((I + 1))
continue
fi
[ -n "$USE_ADDR" ] || { I=$((I + 1)); continue; }
# Fetch peer's package catalog
PEER_CATALOG=$(curl -s --connect-timeout 5 --max-time 30 \
"http://${USE_ADDR}:7331/api/factory/packages" 2>/dev/null)
[ $FIRST_SOURCE -eq 0 ] && echo ','
FIRST_SOURCE=0
if [ -n "$PEER_CATALOG" ]; then
PEER_HASH=$(echo "$PEER_CATALOG" | jsonfilter -e '@.feed_hash' 2>/dev/null)
PEER_PKG_COUNT=$(echo "$PEER_CATALOG" | jsonfilter -e '@.package_count' 2>/dev/null)
PEER_PACKAGES=$(echo "$PEER_CATALOG" | jsonfilter -e '@.packages' 2>/dev/null)
if [ -n "$PEER_HASH" ]; then
PEERS_SYNCED=$((PEERS_SYNCED + 1))
TOTAL_PACKAGES=$((TOTAL_PACKAGES + ${PEER_PKG_COUNT:-0}))
echo '{'
echo "\"node_id\":\"$USE_ADDR\","
echo "\"node_name\":\"$PEER_NAME\","
echo "\"type\":\"peer\","
echo "\"address\":\"$USE_ADDR\","
echo "\"status\":\"ok\","
echo "\"feed_hash\":\"$PEER_HASH\","
echo "\"package_count\":${PEER_PKG_COUNT:-0},"
echo "\"packages\":${PEER_PACKAGES:-[]}"
echo '}'
else
PEERS_FAILED=$((PEERS_FAILED + 1))
echo '{'
echo "\"node_id\":\"$USE_ADDR\","
echo "\"node_name\":\"$PEER_NAME\","
echo "\"type\":\"peer\","
echo "\"address\":\"$USE_ADDR\","
echo "\"status\":\"error\","
echo "\"error\":\"invalid_response\""
echo '}'
fi
else
PEERS_FAILED=$((PEERS_FAILED + 1))
echo '{'
echo "\"node_id\":\"$USE_ADDR\","
echo "\"node_name\":\"$PEER_NAME\","
echo "\"type\":\"peer\","
echo "\"address\":\"$USE_ADDR\","
echo "\"status\":\"unreachable\","
echo "\"error\":\"connection_failed\""
echo '}'
fi
I=$((I + 1))
done
fi
echo '],'
# Summary stats
echo "\"sync_stats\":{"
echo "\"peers_synced\":$PEERS_SYNCED,"
echo "\"peers_failed\":$PEERS_FAILED,"
echo "\"total_packages\":$TOTAL_PACKAGES"
echo '}'
echo '}'