feat(talk-hpb): Add Nextcloud Talk High Performance Backend package
New package secubox-app-talk-hpb: - Docker-based signaling server and Janus WebRTC gateway - Auto-generates TURN/SIGNALING/INTERNAL secrets - Creates HAProxy vhost with SSL/ACME - STUN/TURN server with UDP+TCP support - CLI tool: talk-hpbctl setup/status/test/logs Hub generator v5: - Add PeerTube videos with thumbnails and duration badges - Fix Streamlit instance detection (=instance vs =app) - Total count now: sites + streamlit + videos MetaBlogizer fix: - Add priority=50 to new vhosts to prevent wildcard catch Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8223692436
commit
daacdb731c
@ -435,6 +435,7 @@ EOF
|
|||||||
uci set "haproxy.$vhost_name.ssl_redirect=$ssl"
|
uci set "haproxy.$vhost_name.ssl_redirect=$ssl"
|
||||||
uci set "haproxy.$vhost_name.acme=$acme_val"
|
uci set "haproxy.$vhost_name.acme=$acme_val"
|
||||||
uci set "haproxy.$vhost_name.enabled=1"
|
uci set "haproxy.$vhost_name.enabled=1"
|
||||||
|
uci set "haproxy.$vhost_name.priority=50"
|
||||||
uci commit haproxy
|
uci commit haproxy
|
||||||
|
|
||||||
# Add mitmproxy route for WAF inspection
|
# Add mitmproxy route for WAF inspection
|
||||||
@ -1117,6 +1118,7 @@ EOF
|
|||||||
uci set "haproxy.$vhost_name.ssl_redirect=1"
|
uci set "haproxy.$vhost_name.ssl_redirect=1"
|
||||||
uci set "haproxy.$vhost_name.acme=1"
|
uci set "haproxy.$vhost_name.acme=1"
|
||||||
uci set "haproxy.$vhost_name.enabled=1"
|
uci set "haproxy.$vhost_name.enabled=1"
|
||||||
|
uci set "haproxy.$vhost_name.priority=50"
|
||||||
|
|
||||||
uci commit haproxy
|
uci commit haproxy
|
||||||
|
|
||||||
@ -1914,6 +1916,7 @@ EOF
|
|||||||
uci set "haproxy.$vhost_name.ssl_redirect=1"
|
uci set "haproxy.$vhost_name.ssl_redirect=1"
|
||||||
uci set "haproxy.$vhost_name.acme=1"
|
uci set "haproxy.$vhost_name.acme=1"
|
||||||
uci set "haproxy.$vhost_name.enabled=1"
|
uci set "haproxy.$vhost_name.enabled=1"
|
||||||
|
uci set "haproxy.$vhost_name.priority=50"
|
||||||
|
|
||||||
uci commit haproxy
|
uci commit haproxy
|
||||||
|
|
||||||
|
|||||||
@ -1,28 +1,27 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# SecuBox Hub Generator v3 - Dynamic portal with categories and thumbnails
|
# SecuBox Hub Generator v5 - MetaBlogizer + Streamlit + PeerTube videos
|
||||||
|
|
||||||
OUTPUT="/www/gk2-hub/index.html"
|
OUTPUT="/www/gk2-hub/index.html"
|
||||||
TEMP="/tmp/hub_gen_$$.html"
|
TEMP="/tmp/hub_gen_$$.html"
|
||||||
CACHE_DIR="/tmp/hub-cache"
|
|
||||||
DATE=$(date "+%Y-%m-%d %H:%M")
|
DATE=$(date "+%Y-%m-%d %H:%M")
|
||||||
|
PEERTUBE_API="http://192.168.255.1:9001/api/v1"
|
||||||
|
PEERTUBE_URL="https://tube.gk2.secubox.in"
|
||||||
|
|
||||||
mkdir -p "$CACHE_DIR"
|
|
||||||
|
|
||||||
# Categorize site based on name
|
|
||||||
categorize_site() {
|
categorize_site() {
|
||||||
local name=$(echo "$1" | tr '[:upper:]' '[:lower:]')
|
local name=$(echo "$1" | tr '[:upper:]' '[:lower:]')
|
||||||
case "$name" in
|
case "$name" in
|
||||||
*intel*|*dgse*|*osint*|*threat*|*secu*|*raid*|*confid*|*mku*|*bdgse*|*camus*) echo "Intelligence" ;;
|
*intel*|*dgse*|*osint*|*threat*|*secu*|*raid*|*confid*|*mku*|*bdgse*|*camus*) echo "Intelligence" ;;
|
||||||
*game*|*play*|*comic*|*virus*|*survie*) echo "Divertissement" ;;
|
*game*|*play*|*comic*|*virus*|*survie*) echo "Divertissement" ;;
|
||||||
*dev*|*code*|*git*|*sdlc*|*crt*|*fabric*) echo "Développement" ;;
|
*dev*|*code*|*git*|*sdlc*|*crt*|*fabric*|*hermes*) echo "Développement" ;;
|
||||||
*doc*|*manual*|*guide*|*how*|*fm*|*bgp*|*lrh*|*bcf*) echo "Documentation" ;;
|
*doc*|*manual*|*guide*|*how*|*fm*|*bgp*|*lrh*|*bcf*) echo "Documentation" ;;
|
||||||
*media*|*video*|*tube*|*stream*|*radio*|*lyrion*|*jellyfin*) echo "Média" ;;
|
*media*|*video*|*tube*|*stream*|*radio*|*lyrion*|*jellyfin*) echo "Média" ;;
|
||||||
*blog*|*news*|*press*|*zine*|*flash*|*pub*) echo "Actualités" ;;
|
*blog*|*news*|*press*|*zine*|*flash*|*pub*) echo "Actualités" ;;
|
||||||
*cloud*|*file*|*nextcloud*) echo "Cloud" ;;
|
*cloud*|*file*|*nextcloud*|*photo*) echo "Cloud" ;;
|
||||||
*admin*|*control*|*status*|*hub*|*glances*|*holo*) echo "Administration" ;;
|
*admin*|*control*|*status*|*hub*|*glances*|*holo*|*console*|*evolution*) echo "Administration" ;;
|
||||||
*money*|*coin*|*crypto*|*cgv*|*cpi*|*apr*) echo "Finance" ;;
|
*money*|*coin*|*crypto*|*cgv*|*cpi*|*apr*) echo "Finance" ;;
|
||||||
*geo*|*map*|*gondwana*|*earth*) echo "Géographie" ;;
|
*geo*|*map*|*gondwana*|*earth*) echo "Géographie" ;;
|
||||||
*psy*|*oracle*|*yijing*|*bazi*|*equa*|*lunaquar*|*clock*) echo "Ésotérique" ;;
|
*psy*|*oracle*|*yijing*|*bazi*|*equa*|*lunaquar*|*clock*|*wuyun*|*yling*|*pix*|*tam*) echo "Ésotérique" ;;
|
||||||
|
*metabol*|*osint*|*generix*|*swg*|*ftvm*|*cpf*) echo "Outils" ;;
|
||||||
*) echo "Projets" ;;
|
*) echo "Projets" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@ -40,11 +39,27 @@ get_emoji() {
|
|||||||
"Finance") echo "💰" ;;
|
"Finance") echo "💰" ;;
|
||||||
"Géographie") echo "🌍" ;;
|
"Géographie") echo "🌍" ;;
|
||||||
"Ésotérique") echo "🔮" ;;
|
"Ésotérique") echo "🔮" ;;
|
||||||
|
"Outils") echo "🛠️" ;;
|
||||||
|
"Streamlit") echo "📊" ;;
|
||||||
|
"PeerTube") echo "🎥" ;;
|
||||||
*) echo "📄" ;;
|
*) echo "📄" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
# Start HTML
|
format_duration() {
|
||||||
|
local sec=$1
|
||||||
|
local min=$((sec / 60))
|
||||||
|
local s=$((sec % 60))
|
||||||
|
if [ $min -ge 60 ]; then
|
||||||
|
local h=$((min / 60))
|
||||||
|
min=$((min % 60))
|
||||||
|
printf "%d:%02d:%02d" $h $min $s
|
||||||
|
else
|
||||||
|
printf "%d:%02d" $min $s
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTML Header
|
||||||
cat > "$TEMP" << 'HTMLHEAD'
|
cat > "$TEMP" << 'HTMLHEAD'
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
@ -54,7 +69,7 @@ cat > "$TEMP" << 'HTMLHEAD'
|
|||||||
<title>GK² Hub — Portal SecuBox</title>
|
<title>GK² Hub — Portal SecuBox</title>
|
||||||
<meta http-equiv="refresh" content="300">
|
<meta http-equiv="refresh" content="300">
|
||||||
<style>
|
<style>
|
||||||
:root{--bg:#0a0a0f;--surface:#12121a;--surface2:#1a1a24;--border:#2a2a3e;--accent:#00d4ff;--accent2:#7c3aed;--text:#e0e0e0;--muted:#888}
|
:root{--bg:#0a0a0f;--surface:#12121a;--surface2:#1a1a24;--border:#2a2a3e;--accent:#00d4ff;--accent2:#7c3aed;--accent3:#10b981;--accent4:#f97316;--text:#e0e0e0;--muted:#888}
|
||||||
*{box-sizing:border-box;margin:0;padding:0}
|
*{box-sizing:border-box;margin:0;padding:0}
|
||||||
body{background:var(--bg);color:var(--text);font-family:'Segoe UI',system-ui,sans-serif;min-height:100vh}
|
body{background:var(--bg);color:var(--text);font-family:'Segoe UI',system-ui,sans-serif;min-height:100vh}
|
||||||
.bg-grid{position:fixed;inset:0;background-image:linear-gradient(rgba(0,212,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(0,212,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;z-index:0}
|
.bg-grid{position:fixed;inset:0;background-image:linear-gradient(rgba(0,212,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(0,212,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;z-index:0}
|
||||||
@ -88,17 +103,28 @@ body{background:var(--bg);color:var(--text);font-family:'Segoe UI',system-ui,san
|
|||||||
.view-compact .sites-grid{grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:8px}
|
.view-compact .sites-grid{grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:8px}
|
||||||
.site-card{background:var(--surface);border:1px solid var(--border);border-radius:12px;overflow:hidden;text-decoration:none;color:inherit;display:flex;flex-direction:column;transition:all 0.3s}
|
.site-card{background:var(--surface);border:1px solid var(--border);border-radius:12px;overflow:hidden;text-decoration:none;color:inherit;display:flex;flex-direction:column;transition:all 0.3s}
|
||||||
.site-card:hover{border-color:var(--accent);transform:translateY(-3px);box-shadow:0 10px 40px rgba(0,212,255,0.15)}
|
.site-card:hover{border-color:var(--accent);transform:translateY(-3px);box-shadow:0 10px 40px rgba(0,212,255,0.15)}
|
||||||
|
.site-card.streamlit{border-color:var(--accent3)}
|
||||||
|
.site-card.streamlit:hover{border-color:var(--accent3);box-shadow:0 10px 40px rgba(16,185,129,0.15)}
|
||||||
|
.site-card.video{border-color:var(--accent4)}
|
||||||
|
.site-card.video:hover{border-color:var(--accent4);box-shadow:0 10px 40px rgba(249,115,22,0.15)}
|
||||||
.view-list .site-card{flex-direction:row}
|
.view-list .site-card{flex-direction:row}
|
||||||
.card-preview{width:100%;height:120px;background:var(--surface2);position:relative;overflow:hidden}
|
.card-preview{width:100%;height:120px;background:var(--surface2);position:relative;overflow:hidden}
|
||||||
.view-list .card-preview{width:160px;flex-shrink:0}
|
.view-list .card-preview{width:160px;flex-shrink:0}
|
||||||
.view-compact .card-preview{height:70px}
|
.view-compact .card-preview{height:70px}
|
||||||
.card-preview iframe{width:200%;height:200%;transform:scale(0.5);transform-origin:0 0;border:none;pointer-events:none}
|
.card-preview iframe{width:200%;height:200%;transform:scale(0.5);transform-origin:0 0;border:none;pointer-events:none}
|
||||||
.card-preview .emoji-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:2.5rem;background:linear-gradient(135deg,var(--surface2),var(--bg))}
|
.card-preview img{width:100%;height:100%;object-fit:cover}
|
||||||
|
.card-preview .duration{position:absolute;bottom:4px;right:4px;background:rgba(0,0,0,0.8);color:#fff;padding:2px 6px;border-radius:4px;font-size:0.7rem;font-family:monospace}
|
||||||
|
.card-preview .play-icon{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:48px;height:48px;background:rgba(0,0,0,0.7);border-radius:50%;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity 0.2s}
|
||||||
|
.site-card.video:hover .play-icon{opacity:1}
|
||||||
|
.play-icon:after{content:'';border-style:solid;border-width:10px 0 10px 16px;border-color:transparent transparent transparent #fff;margin-left:4px}
|
||||||
.card-content{padding:12px;flex:1}
|
.card-content{padding:12px;flex:1}
|
||||||
.view-compact .card-content{padding:8px}
|
.view-compact .card-content{padding:8px}
|
||||||
.card-title{font-weight:600;font-size:0.9rem;margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
.card-title{font-weight:600;font-size:0.9rem;margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||||
.card-domain{font-size:0.7rem;color:var(--accent);font-family:monospace;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
.card-domain{font-size:0.7rem;color:var(--accent);font-family:monospace;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||||
.card-cat{display:inline-block;padding:2px 6px;background:linear-gradient(135deg,var(--accent),var(--accent2));border-radius:4px;font-size:0.6rem;color:#fff;font-weight:600}
|
.card-cat{display:inline-block;padding:2px 6px;border-radius:4px;font-size:0.6rem;color:#fff;font-weight:600;margin-right:4px}
|
||||||
|
.card-cat.meta{background:linear-gradient(135deg,var(--accent),var(--accent2))}
|
||||||
|
.card-cat.streamlit{background:linear-gradient(135deg,var(--accent3),#059669)}
|
||||||
|
.card-cat.video{background:linear-gradient(135deg,var(--accent4),#ea580c)}
|
||||||
.footer{margin-top:40px;padding:20px 0;border-top:1px solid var(--border);text-align:center;color:var(--muted);font-size:0.8rem}
|
.footer{margin-top:40px;padding:20px 0;border-top:1px solid var(--border);text-align:center;color:var(--muted);font-size:0.8rem}
|
||||||
.footer a{color:var(--accent);text-decoration:none}
|
.footer a{color:var(--accent);text-decoration:none}
|
||||||
@media(max-width:768px){.header{flex-direction:column;align-items:flex-start}.view-list .site-card{flex-direction:column}.view-list .card-preview{width:100%}}
|
@media(max-width:768px){.header{flex-direction:column;align-items:flex-start}.view-list .site-card{flex-direction:column}.view-list .card-preview{width:100%}}
|
||||||
@ -129,38 +155,111 @@ cat >> "$TEMP" << EOF
|
|||||||
</div>
|
</div>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Collect sites
|
# Collect all sites
|
||||||
SITES_FILE="/tmp/hub_sites_$$.txt"
|
SITES_FILE="/tmp/hub_sites_$$.txt"
|
||||||
CAT_FILE="/tmp/hub_cats_$$.txt"
|
CAT_FILE="/tmp/hub_cats_$$.txt"
|
||||||
|
VIDEOS_FILE="/tmp/hub_videos_$$.txt"
|
||||||
> "$SITES_FILE"
|
> "$SITES_FILE"
|
||||||
> "$CAT_FILE"
|
> "$CAT_FILE"
|
||||||
|
> "$VIDEOS_FILE"
|
||||||
|
|
||||||
|
# MetaBlogizer sites
|
||||||
uci show metablogizer 2>/dev/null | grep "=site$" | sed "s/metablogizer\.\(.*\)=site/\1/" | while read site; do
|
uci show metablogizer 2>/dev/null | grep "=site$" | sed "s/metablogizer\.\(.*\)=site/\1/" | while read site; do
|
||||||
name=$(uci -q get "metablogizer.$site.name")
|
name=$(uci -q get "metablogizer.$site.name")
|
||||||
domain=$(uci -q get "metablogizer.$site.domain")
|
domain=$(uci -q get "metablogizer.$site.domain")
|
||||||
enabled=$(uci -q get "metablogizer.$site.enabled")
|
enabled=$(uci -q get "metablogizer.$site.enabled")
|
||||||
|
|
||||||
[ "$enabled" != "1" ] && continue
|
[ "$enabled" != "1" ] && continue
|
||||||
[ -z "$domain" ] && continue
|
[ -z "$domain" ] && continue
|
||||||
|
|
||||||
cat=$(categorize_site "$name")
|
cat=$(categorize_site "$name")
|
||||||
emoji=$(get_emoji "$cat")
|
emoji=$(get_emoji "$cat")
|
||||||
|
|
||||||
echo "$cat" >> "$CAT_FILE"
|
echo "$cat" >> "$CAT_FILE"
|
||||||
printf '%s\t%s\t%s\t%s\n' "$domain" "$name" "$cat" "$emoji" >> "$SITES_FILE"
|
printf '%s\t%s\t%s\t%s\tmeta\t\t\n' "$domain" "$name" "$cat" "$emoji" >> "$SITES_FILE"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Streamlit instances
|
||||||
|
uci show streamlit 2>/dev/null | grep "=instance$" | sed "s/streamlit\.\(.*\)=instance/\1/" | while read app; do
|
||||||
|
name=$(uci -q get "streamlit.$app.name")
|
||||||
|
domain=$(uci -q get "streamlit.$app.domain")
|
||||||
|
enabled=$(uci -q get "streamlit.$app.enabled")
|
||||||
|
[ "$enabled" != "1" ] && continue
|
||||||
|
[ -z "$domain" ] && continue
|
||||||
|
cat=$(categorize_site "$name")
|
||||||
|
emoji=$(get_emoji "$cat")
|
||||||
|
echo "$cat" >> "$CAT_FILE"
|
||||||
|
printf '%s\t%s\t%s\t%s\tstreamlit\t\t\n' "$domain" "$name" "$cat" "$emoji" >> "$SITES_FILE"
|
||||||
|
done
|
||||||
|
|
||||||
|
# PeerTube videos
|
||||||
|
VIDEOS_JSON=$(curl -s "${PEERTUBE_API}/videos?count=50" 2>/dev/null)
|
||||||
|
TOTAL_VIDEOS=0
|
||||||
|
if [ -n "$VIDEOS_JSON" ]; then
|
||||||
|
# Parse videos using jsonfilter
|
||||||
|
echo "$VIDEOS_JSON" | jsonfilter -e '@.data[*]' 2>/dev/null | while read -r video_line; do
|
||||||
|
# Skip if empty
|
||||||
|
[ -z "$video_line" ] && continue
|
||||||
|
|
||||||
|
uuid=$(echo "$VIDEOS_JSON" | jsonfilter -e "@.data[$TOTAL_VIDEOS].uuid" 2>/dev/null)
|
||||||
|
name=$(echo "$VIDEOS_JSON" | jsonfilter -e "@.data[$TOTAL_VIDEOS].name" 2>/dev/null)
|
||||||
|
thumb=$(echo "$VIDEOS_JSON" | jsonfilter -e "@.data[$TOTAL_VIDEOS].thumbnailPath" 2>/dev/null)
|
||||||
|
duration=$(echo "$VIDEOS_JSON" | jsonfilter -e "@.data[$TOTAL_VIDEOS].duration" 2>/dev/null)
|
||||||
|
|
||||||
|
[ -z "$uuid" ] && break
|
||||||
|
[ -z "$name" ] && continue
|
||||||
|
|
||||||
|
# Format duration
|
||||||
|
dur_fmt=$(format_duration "$duration")
|
||||||
|
|
||||||
|
# Video URL and thumbnail
|
||||||
|
video_url="${PEERTUBE_URL}/w/${uuid}"
|
||||||
|
thumb_url="${PEERTUBE_URL}${thumb}"
|
||||||
|
|
||||||
|
echo "Média" >> "$CAT_FILE"
|
||||||
|
printf '%s\t%s\tMédia\t🎥\tvideo\t%s\t%s\n' "$video_url" "$name" "$thumb_url" "$dur_fmt" >> "$VIDEOS_FILE"
|
||||||
|
|
||||||
|
TOTAL_VIDEOS=$((TOTAL_VIDEOS + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
# Alternative parsing if jsonfilter fails
|
||||||
|
if [ ! -s "$VIDEOS_FILE" ]; then
|
||||||
|
# Use simple sed/awk parsing
|
||||||
|
echo "$VIDEOS_JSON" | sed 's/},/}\n/g' | while read -r line; do
|
||||||
|
uuid=$(echo "$line" | sed -n 's/.*"uuid":"\([^"]*\)".*/\1/p')
|
||||||
|
name=$(echo "$line" | sed -n 's/.*"name":"\([^"]*\)".*/\1/p' | head -1)
|
||||||
|
thumb=$(echo "$line" | sed -n 's/.*"thumbnailPath":"\([^"]*\)".*/\1/p')
|
||||||
|
duration=$(echo "$line" | sed -n 's/.*"duration":\([0-9]*\).*/\1/p')
|
||||||
|
|
||||||
|
[ -z "$uuid" ] && continue
|
||||||
|
[ -z "$name" ] && continue
|
||||||
|
|
||||||
|
dur_fmt=$(format_duration "${duration:-0}")
|
||||||
|
video_url="${PEERTUBE_URL}/w/${uuid}"
|
||||||
|
thumb_url="${PEERTUBE_URL}${thumb}"
|
||||||
|
|
||||||
|
echo "Média" >> "$CAT_FILE"
|
||||||
|
printf '%s\t%s\tMédia\t🎥\tvideo\t%s\t%s\n' "$video_url" "$name" "$thumb_url" "$dur_fmt" >> "$VIDEOS_FILE"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Merge videos into sites file
|
||||||
|
cat "$VIDEOS_FILE" >> "$SITES_FILE" 2>/dev/null
|
||||||
|
|
||||||
# Stats
|
# Stats
|
||||||
TOTAL=$(wc -l < "$SITES_FILE" | tr -d ' ')
|
TOTAL=$(wc -l < "$SITES_FILE" | tr -d ' ')
|
||||||
[ -z "$TOTAL" ] && TOTAL=0
|
TOTAL_META=$(grep " meta " "$SITES_FILE" | wc -l | tr -d ' ')
|
||||||
CAT_COUNTS=$(sort "$CAT_FILE" 2>/dev/null | uniq -c | sort -rn)
|
TOTAL_STREAMLIT=$(grep " streamlit " "$SITES_FILE" | wc -l | tr -d ' ')
|
||||||
|
TOTAL_VIDEOS=$(grep " video " "$SITES_FILE" | wc -l | tr -d ' ')
|
||||||
|
CAT_COUNTS=$(grep -v "^$" "$CAT_FILE" 2>/dev/null | sort | uniq -c | sort -rn)
|
||||||
|
|
||||||
# Stats bar
|
# Stats bar
|
||||||
cat >> "$TEMP" << EOF
|
cat >> "$TEMP" << EOF
|
||||||
<div class="stats-bar">
|
<div class="stats-bar">
|
||||||
<div class="stat"><span class="stat-value">$TOTAL</span><span class="stat-label">Sites</span></div>
|
<div class="stat"><span class="stat-value">$TOTAL</span><span class="stat-label">Total</span></div>
|
||||||
|
<div class="stat"><span class="stat-value">$TOTAL_META</span><span class="stat-label">Sites</span></div>
|
||||||
|
<div class="stat"><span class="stat-value">$TOTAL_STREAMLIT</span><span class="stat-label">Streamlit</span></div>
|
||||||
|
<div class="stat"><span class="stat-value">$TOTAL_VIDEOS</span><span class="stat-label">Vidéos</span></div>
|
||||||
EOF
|
EOF
|
||||||
echo "$CAT_COUNTS" | head -5 | while read count cat; do
|
echo "$CAT_COUNTS" | head -3 | while read count cat; do
|
||||||
[ -n "$cat" ] && printf ' <div class="stat"><span class="stat-value">%s</span><span class="stat-label">%s</span></div>\n' "$count" "$cat" >> "$TEMP"
|
[ -n "$cat" ] && printf ' <div class="stat"><span class="stat-value">%s</span><span class="stat-label">%s</span></div>\n' "$count" "$cat" >> "$TEMP"
|
||||||
done
|
done
|
||||||
echo "</div>" >> "$TEMP"
|
echo "</div>" >> "$TEMP"
|
||||||
@ -168,6 +267,9 @@ echo "</div>" >> "$TEMP"
|
|||||||
# Tag cloud
|
# Tag cloud
|
||||||
echo '<div class="tag-cloud" id="tagCloud">' >> "$TEMP"
|
echo '<div class="tag-cloud" id="tagCloud">' >> "$TEMP"
|
||||||
echo '<span class="tag active" data-cat="all">Tous</span>' >> "$TEMP"
|
echo '<span class="tag active" data-cat="all">Tous</span>' >> "$TEMP"
|
||||||
|
echo '<span class="tag" data-cat="meta">📝 Sites</span>' >> "$TEMP"
|
||||||
|
echo '<span class="tag" data-cat="streamlit">📊 Streamlit</span>' >> "$TEMP"
|
||||||
|
echo '<span class="tag" data-cat="video">🎥 Vidéos</span>' >> "$TEMP"
|
||||||
echo "$CAT_COUNTS" | while read count cat; do
|
echo "$CAT_COUNTS" | while read count cat; do
|
||||||
[ -n "$cat" ] && printf '<span class="tag" data-cat="%s">%s<span class="count">%s</span></span>\n' "$cat" "$cat" "$count" >> "$TEMP"
|
[ -n "$cat" ] && printf '<span class="tag" data-cat="%s">%s<span class="count">%s</span></span>\n' "$cat" "$cat" "$count" >> "$TEMP"
|
||||||
done
|
done
|
||||||
@ -176,27 +278,53 @@ echo '</div>' >> "$TEMP"
|
|||||||
# Category tabs
|
# Category tabs
|
||||||
echo '<div class="category-tabs">' >> "$TEMP"
|
echo '<div class="category-tabs">' >> "$TEMP"
|
||||||
printf '<div class="cat-tab active" data-cat="all">📁 Tous<span class="count">%s</span></div>\n' "$TOTAL" >> "$TEMP"
|
printf '<div class="cat-tab active" data-cat="all">📁 Tous<span class="count">%s</span></div>\n' "$TOTAL" >> "$TEMP"
|
||||||
echo "$CAT_COUNTS" | while read count cat; do
|
printf '<div class="cat-tab" data-cat="meta">📝 Sites<span class="count">%s</span></div>\n' "$TOTAL_META" >> "$TEMP"
|
||||||
|
printf '<div class="cat-tab" data-cat="streamlit">📊 Streamlit<span class="count">%s</span></div>\n' "$TOTAL_STREAMLIT" >> "$TEMP"
|
||||||
|
printf '<div class="cat-tab" data-cat="video">🎥 Vidéos<span class="count">%s</span></div>\n' "$TOTAL_VIDEOS" >> "$TEMP"
|
||||||
|
echo "$CAT_COUNTS" | head -6 | while read count cat; do
|
||||||
emoji=$(get_emoji "$cat")
|
emoji=$(get_emoji "$cat")
|
||||||
[ -n "$cat" ] && printf '<div class="cat-tab" data-cat="%s">%s %s<span class="count">%s</span></div>\n' "$cat" "$emoji" "$cat" "$count" >> "$TEMP"
|
[ -n "$cat" ] && printf '<div class="cat-tab" data-cat="%s">%s %s<span class="count">%s</span></div>\n' "$cat" "$emoji" "$cat" "$count" >> "$TEMP"
|
||||||
done
|
done
|
||||||
echo '</div>' >> "$TEMP"
|
echo '</div>' >> "$TEMP"
|
||||||
|
|
||||||
# Sites grid with iframe preview
|
# Sites grid
|
||||||
echo '<div class="view-grid" id="viewContainer"><div class="sites-grid" id="sitesGrid">' >> "$TEMP"
|
echo '<div class="view-grid" id="viewContainer"><div class="sites-grid" id="sitesGrid">' >> "$TEMP"
|
||||||
|
|
||||||
while IFS=' ' read -r domain name cat emoji; do
|
while IFS=' ' read -r url name cat emoji type thumb duration; do
|
||||||
[ -z "$domain" ] && continue
|
[ -z "$url" ] && continue
|
||||||
|
|
||||||
|
if [ "$type" = "streamlit" ]; then
|
||||||
|
card_class="site-card streamlit"
|
||||||
|
cat_class="card-cat streamlit"
|
||||||
|
preview_html="<iframe src=\"https://$url/\" loading=\"lazy\" sandbox></iframe>"
|
||||||
|
elif [ "$type" = "video" ]; then
|
||||||
|
card_class="site-card video"
|
||||||
|
cat_class="card-cat video"
|
||||||
|
preview_html="<img src=\"$thumb\" alt=\"$name\" loading=\"lazy\"><div class=\"play-icon\"></div><span class=\"duration\">$duration</span>"
|
||||||
|
else
|
||||||
|
card_class="site-card"
|
||||||
|
cat_class="card-cat meta"
|
||||||
|
preview_html="<iframe src=\"https://$url/\" loading=\"lazy\" sandbox></iframe>"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# URL handling - videos already have full URL
|
||||||
|
if [ "$type" = "video" ]; then
|
||||||
|
link_url="$url"
|
||||||
|
domain_display="tube.gk2.secubox.in"
|
||||||
|
else
|
||||||
|
link_url="https://$url/"
|
||||||
|
domain_display="$url"
|
||||||
|
fi
|
||||||
|
|
||||||
cat >> "$TEMP" << CARD
|
cat >> "$TEMP" << CARD
|
||||||
<a href="https://$domain/" class="site-card" target="_blank" data-category="$cat" data-search="$domain $name $cat">
|
<a href="$link_url" class="$card_class" target="_blank" data-category="$cat" data-type="$type" data-search="$url $name $cat $type">
|
||||||
<div class="card-preview">
|
<div class="card-preview">
|
||||||
<iframe src="https://$domain/" loading="lazy" sandbox></iframe>
|
$preview_html
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="card-title">$name</div>
|
<div class="card-title">$name</div>
|
||||||
<div class="card-domain">$domain</div>
|
<div class="card-domain">$domain_display</div>
|
||||||
<span class="card-cat">$emoji $cat</span>
|
<span class="$cat_class">$emoji $cat</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
CARD
|
CARD
|
||||||
@ -227,7 +355,10 @@ document.addEventListener('DOMContentLoaded',function(){
|
|||||||
};
|
};
|
||||||
|
|
||||||
function filter(cat){
|
function filter(cat){
|
||||||
cards.forEach(c=>c.style.display=(cat==='all'||c.dataset.category===cat)?'':'none');
|
cards.forEach(c=>{
|
||||||
|
let show = cat==='all' || c.dataset.category===cat || c.dataset.type===cat;
|
||||||
|
c.style.display = show ? '' : 'none';
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelectorAll('.cat-tab,.tag').forEach(t=>t.onclick=function(){
|
document.querySelectorAll('.cat-tab,.tag').forEach(t=>t.onclick=function(){
|
||||||
@ -246,7 +377,7 @@ document.addEventListener('DOMContentLoaded',function(){
|
|||||||
</html>
|
</html>
|
||||||
FOOTER
|
FOOTER
|
||||||
|
|
||||||
rm -f "$SITES_FILE" "$CAT_FILE"
|
rm -f "$SITES_FILE" "$CAT_FILE" "$VIDEOS_FILE"
|
||||||
mv "$TEMP" "$OUTPUT"
|
mv "$TEMP" "$OUTPUT"
|
||||||
chmod 644 "$OUTPUT"
|
chmod 644 "$OUTPUT"
|
||||||
logger -t hub-generator "Hub v3: $TOTAL sites"
|
logger -t hub-generator "Hub v5: $TOTAL items ($TOTAL_META sites + $TOTAL_STREAMLIT streamlit + $TOTAL_VIDEOS videos)"
|
||||||
|
|||||||
47
package/secubox/secubox-app-talk-hpb/Makefile
Normal file
47
package/secubox/secubox-app-talk-hpb/Makefile
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=secubox-app-talk-hpb
|
||||||
|
PKG_VERSION:=1.0.0
|
||||||
|
PKG_RELEASE:=1
|
||||||
|
|
||||||
|
PKG_MAINTAINER:=SecuBox <contact@secubox.in>
|
||||||
|
PKG_LICENSE:=GPL-3.0
|
||||||
|
|
||||||
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
|
define Package/secubox-app-talk-hpb
|
||||||
|
SECTION:=secubox
|
||||||
|
CATEGORY:=SecuBox
|
||||||
|
TITLE:=Nextcloud Talk High Performance Backend
|
||||||
|
DEPENDS:=+docker +curl +openssl-util
|
||||||
|
PKGARCH:=all
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/secubox-app-talk-hpb/description
|
||||||
|
Nextcloud Talk High Performance Backend for SecuBox.
|
||||||
|
Provides signaling server and Janus WebRTC gateway for
|
||||||
|
improved video/audio call quality in Nextcloud Talk.
|
||||||
|
Runs as Docker container with automatic configuration.
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/secubox-app-talk-hpb/install
|
||||||
|
$(INSTALL_DIR) $(1)/etc/config
|
||||||
|
$(INSTALL_CONF) ./files/etc/config/talk-hpb $(1)/etc/config/talk-hpb
|
||||||
|
|
||||||
|
$(INSTALL_DIR) $(1)/etc/init.d
|
||||||
|
$(INSTALL_BIN) ./files/etc/init.d/talk-hpb $(1)/etc/init.d/talk-hpb
|
||||||
|
|
||||||
|
$(INSTALL_DIR) $(1)/usr/sbin
|
||||||
|
$(INSTALL_BIN) ./files/usr/sbin/talk-hpbctl $(1)/usr/sbin/talk-hpbctl
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/secubox-app-talk-hpb/postinst
|
||||||
|
#!/bin/sh
|
||||||
|
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||||
|
# Generate secrets if not set
|
||||||
|
/usr/sbin/talk-hpbctl generate-secrets 2>/dev/null || true
|
||||||
|
}
|
||||||
|
exit 0
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call BuildPackage,secubox-app-talk-hpb))
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
config talk-hpb 'main'
|
||||||
|
option enabled '0'
|
||||||
|
option container_name 'nextcloud-talk-hpb'
|
||||||
|
option image 'ghcr.io/nextcloud-releases/aio-talk:latest'
|
||||||
|
|
||||||
|
config server 'server'
|
||||||
|
option nc_domain ''
|
||||||
|
option signaling_domain ''
|
||||||
|
option signaling_port '8081'
|
||||||
|
option talk_port '3478'
|
||||||
|
|
||||||
|
config secrets 'secrets'
|
||||||
|
option turn_secret ''
|
||||||
|
option signaling_secret ''
|
||||||
|
option internal_secret ''
|
||||||
|
|
||||||
|
config turn 'turn'
|
||||||
|
option enabled '1'
|
||||||
|
option udp '1'
|
||||||
|
option tcp '1'
|
||||||
100
package/secubox/secubox-app-talk-hpb/files/etc/init.d/talk-hpb
Normal file
100
package/secubox/secubox-app-talk-hpb/files/etc/init.d/talk-hpb
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#!/bin/sh /etc/rc.common
|
||||||
|
|
||||||
|
START=99
|
||||||
|
STOP=10
|
||||||
|
USE_PROCD=1
|
||||||
|
|
||||||
|
CONTAINER_NAME="nextcloud-talk-hpb"
|
||||||
|
IMAGE="ghcr.io/nextcloud-releases/aio-talk:latest"
|
||||||
|
|
||||||
|
get_config() {
|
||||||
|
local key="$1"
|
||||||
|
local section="$2"
|
||||||
|
local default="$3"
|
||||||
|
uci -q get "talk-hpb.${section}.${key}" || echo "$default"
|
||||||
|
}
|
||||||
|
|
||||||
|
start_service() {
|
||||||
|
local enabled=$(get_config enabled main 0)
|
||||||
|
[ "$enabled" != "1" ] && return 0
|
||||||
|
|
||||||
|
local nc_domain=$(get_config nc_domain server "")
|
||||||
|
local signaling_domain=$(get_config signaling_domain server "")
|
||||||
|
local signaling_port=$(get_config signaling_port server 8081)
|
||||||
|
local talk_port=$(get_config talk_port server 3478)
|
||||||
|
|
||||||
|
local turn_secret=$(get_config turn_secret secrets "")
|
||||||
|
local signaling_secret=$(get_config signaling_secret secrets "")
|
||||||
|
local internal_secret=$(get_config internal_secret secrets "")
|
||||||
|
|
||||||
|
local turn_enabled=$(get_config enabled turn 1)
|
||||||
|
local turn_udp=$(get_config udp turn 1)
|
||||||
|
local turn_tcp=$(get_config tcp turn 1)
|
||||||
|
|
||||||
|
local container=$(get_config container_name main "$CONTAINER_NAME")
|
||||||
|
local image=$(get_config image main "$IMAGE")
|
||||||
|
|
||||||
|
# Validate required settings
|
||||||
|
if [ -z "$nc_domain" ]; then
|
||||||
|
logger -t talk-hpb "ERROR: nc_domain not configured"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$turn_secret" ] || [ -z "$signaling_secret" ] || [ -z "$internal_secret" ]; then
|
||||||
|
logger -t talk-hpb "ERROR: Secrets not configured. Run: talk-hpbctl generate-secrets"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop existing container
|
||||||
|
docker stop "$container" 2>/dev/null
|
||||||
|
docker rm "$container" 2>/dev/null
|
||||||
|
|
||||||
|
# Build docker run command
|
||||||
|
local docker_cmd="docker run --name=$container --restart=always --detach"
|
||||||
|
docker_cmd="$docker_cmd -e NC_DOMAIN=$nc_domain"
|
||||||
|
docker_cmd="$docker_cmd -e TALK_PORT=$talk_port"
|
||||||
|
docker_cmd="$docker_cmd -e TURN_SECRET=$turn_secret"
|
||||||
|
docker_cmd="$docker_cmd -e SIGNALING_SECRET=$signaling_secret"
|
||||||
|
docker_cmd="$docker_cmd -e INTERNAL_SECRET=$internal_secret"
|
||||||
|
|
||||||
|
# Signaling port
|
||||||
|
docker_cmd="$docker_cmd -p ${signaling_port}:8081"
|
||||||
|
|
||||||
|
# TURN ports if enabled
|
||||||
|
if [ "$turn_enabled" = "1" ]; then
|
||||||
|
[ -n "$signaling_domain" ] && docker_cmd="$docker_cmd -e TALK_HOST=$signaling_domain"
|
||||||
|
[ "$turn_tcp" = "1" ] && docker_cmd="$docker_cmd -p ${talk_port}:3478/tcp"
|
||||||
|
[ "$turn_udp" = "1" ] && docker_cmd="$docker_cmd -p ${talk_port}:3478/udp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker_cmd="$docker_cmd $image"
|
||||||
|
|
||||||
|
logger -t talk-hpb "Starting Nextcloud Talk HPB container..."
|
||||||
|
eval $docker_cmd
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
logger -t talk-hpb "Container started successfully"
|
||||||
|
else
|
||||||
|
logger -t talk-hpb "ERROR: Failed to start container"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_service() {
|
||||||
|
local container=$(get_config container_name main "$CONTAINER_NAME")
|
||||||
|
|
||||||
|
logger -t talk-hpb "Stopping container..."
|
||||||
|
docker stop "$container" 2>/dev/null
|
||||||
|
docker rm "$container" 2>/dev/null
|
||||||
|
logger -t talk-hpb "Container stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
status_service() {
|
||||||
|
local container=$(get_config container_name main "$CONTAINER_NAME")
|
||||||
|
docker inspect "$container" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
reload_service() {
|
||||||
|
stop_service
|
||||||
|
start_service
|
||||||
|
}
|
||||||
308
package/secubox/secubox-app-talk-hpb/files/usr/sbin/talk-hpbctl
Normal file
308
package/secubox/secubox-app-talk-hpb/files/usr/sbin/talk-hpbctl
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# talk-hpbctl - Nextcloud Talk High Performance Backend control
|
||||||
|
|
||||||
|
UCI_CONFIG="talk-hpb"
|
||||||
|
CONTAINER_NAME="nextcloud-talk-hpb"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: talk-hpbctl <command> [options]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
status Show service status
|
||||||
|
setup <nc_domain> <signaling_domain>
|
||||||
|
Configure and start the service
|
||||||
|
generate-secrets Generate random secrets
|
||||||
|
show-secrets Display current secrets
|
||||||
|
show-config Show Nextcloud Talk configuration
|
||||||
|
test Test signaling server connectivity
|
||||||
|
logs [lines] Show container logs
|
||||||
|
pull Pull latest Docker image
|
||||||
|
start Start the service
|
||||||
|
stop Stop the service
|
||||||
|
restart Restart the service
|
||||||
|
enable Enable autostart
|
||||||
|
disable Disable autostart
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
talk-hpbctl setup nextcloud.example.com signaling.example.com
|
||||||
|
talk-hpbctl status
|
||||||
|
talk-hpbctl logs 50
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
get_config() {
|
||||||
|
uci -q get "$UCI_CONFIG.$1.$2" || echo "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_config() {
|
||||||
|
uci set "$UCI_CONFIG.$1.$2=$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_secret() {
|
||||||
|
openssl rand -hex 32
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_generate_secrets() {
|
||||||
|
local turn_secret=$(generate_secret)
|
||||||
|
local signaling_secret=$(generate_secret)
|
||||||
|
local internal_secret=$(generate_secret)
|
||||||
|
|
||||||
|
set_config secrets turn_secret "$turn_secret"
|
||||||
|
set_config secrets signaling_secret "$signaling_secret"
|
||||||
|
set_config secrets internal_secret "$internal_secret"
|
||||||
|
uci commit "$UCI_CONFIG"
|
||||||
|
|
||||||
|
echo "Secrets generated and saved to UCI config"
|
||||||
|
echo ""
|
||||||
|
echo "TURN_SECRET: $turn_secret"
|
||||||
|
echo "SIGNALING_SECRET: $signaling_secret"
|
||||||
|
echo "INTERNAL_SECRET: $internal_secret"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_show_secrets() {
|
||||||
|
echo "Current secrets:"
|
||||||
|
echo ""
|
||||||
|
echo "TURN_SECRET: $(get_config secrets turn_secret '')"
|
||||||
|
echo "SIGNALING_SECRET: $(get_config secrets signaling_secret '')"
|
||||||
|
echo "INTERNAL_SECRET: $(get_config secrets internal_secret '')"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_setup() {
|
||||||
|
local nc_domain="$1"
|
||||||
|
local signaling_domain="$2"
|
||||||
|
|
||||||
|
if [ -z "$nc_domain" ] || [ -z "$signaling_domain" ]; then
|
||||||
|
echo "Usage: talk-hpbctl setup <nc_domain> <signaling_domain>"
|
||||||
|
echo ""
|
||||||
|
echo "Example: talk-hpbctl setup nextcloud.gk2.secubox.in signaling.gk2.secubox.in"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Setting up Nextcloud Talk HPB..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if secrets exist, generate if not
|
||||||
|
local signaling_secret=$(get_config secrets signaling_secret '')
|
||||||
|
if [ -z "$signaling_secret" ]; then
|
||||||
|
echo "Generating secrets..."
|
||||||
|
cmd_generate_secrets
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure domains
|
||||||
|
set_config server nc_domain "$nc_domain"
|
||||||
|
set_config server signaling_domain "$signaling_domain"
|
||||||
|
set_config main enabled 1
|
||||||
|
uci commit "$UCI_CONFIG"
|
||||||
|
|
||||||
|
echo "Configuration saved:"
|
||||||
|
echo " NC_DOMAIN: $nc_domain"
|
||||||
|
echo " SIGNALING_DOMAIN: $signaling_domain"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create HAProxy vhost if haproxyctl exists
|
||||||
|
if command -v haproxyctl >/dev/null 2>&1; then
|
||||||
|
echo "Creating HAProxy vhost for $signaling_domain..."
|
||||||
|
|
||||||
|
local signaling_port=$(get_config server signaling_port 8081)
|
||||||
|
local backend_name="talk_hpb_signaling"
|
||||||
|
|
||||||
|
# Create backend
|
||||||
|
uci set "haproxy.${backend_name}=backend"
|
||||||
|
uci set "haproxy.${backend_name}.name=$backend_name"
|
||||||
|
uci set "haproxy.${backend_name}.mode=http"
|
||||||
|
uci set "haproxy.${backend_name}.balance=roundrobin"
|
||||||
|
uci set "haproxy.${backend_name}.enabled=1"
|
||||||
|
|
||||||
|
# Create server
|
||||||
|
uci set "haproxy.${backend_name}_srv=server"
|
||||||
|
uci set "haproxy.${backend_name}_srv.backend=$backend_name"
|
||||||
|
uci set "haproxy.${backend_name}_srv.name=signaling"
|
||||||
|
uci set "haproxy.${backend_name}_srv.address=192.168.255.1"
|
||||||
|
uci set "haproxy.${backend_name}_srv.port=$signaling_port"
|
||||||
|
uci set "haproxy.${backend_name}_srv.enabled=1"
|
||||||
|
|
||||||
|
# Create vhost
|
||||||
|
local vhost_name=$(echo "$signaling_domain" | sed 's/[^a-zA-Z0-9]/_/g')
|
||||||
|
uci set "haproxy.${vhost_name}=vhost"
|
||||||
|
uci set "haproxy.${vhost_name}.domain=$signaling_domain"
|
||||||
|
uci set "haproxy.${vhost_name}.backend=$backend_name"
|
||||||
|
uci set "haproxy.${vhost_name}.waf_bypass=1"
|
||||||
|
uci set "haproxy.${vhost_name}.priority=50"
|
||||||
|
uci set "haproxy.${vhost_name}.ssl=1"
|
||||||
|
uci set "haproxy.${vhost_name}.ssl_redirect=1"
|
||||||
|
uci set "haproxy.${vhost_name}.acme=1"
|
||||||
|
uci set "haproxy.${vhost_name}.enabled=1"
|
||||||
|
|
||||||
|
uci commit haproxy
|
||||||
|
haproxyctl generate >/dev/null 2>&1
|
||||||
|
haproxyctl reload >/dev/null 2>&1
|
||||||
|
echo "HAProxy vhost created: https://$signaling_domain"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Starting service..."
|
||||||
|
/etc/init.d/talk-hpb restart
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Setup complete!"
|
||||||
|
echo ""
|
||||||
|
cmd_show_config
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_show_config() {
|
||||||
|
local nc_domain=$(get_config server nc_domain '')
|
||||||
|
local signaling_domain=$(get_config server signaling_domain '')
|
||||||
|
local signaling_secret=$(get_config secrets signaling_secret '')
|
||||||
|
local turn_secret=$(get_config secrets turn_secret '')
|
||||||
|
local talk_port=$(get_config server talk_port 3478)
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Nextcloud Talk Admin Settings"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
echo "High-performance backend:"
|
||||||
|
echo " URL: https://${signaling_domain}"
|
||||||
|
echo " Secret: ${signaling_secret}"
|
||||||
|
echo ""
|
||||||
|
echo "STUN/TURN servers:"
|
||||||
|
echo " Mode: turn: only"
|
||||||
|
echo " URL: ${signaling_domain}:${talk_port}"
|
||||||
|
echo " Secret: ${turn_secret}"
|
||||||
|
echo " Protocol: UDP and TCP"
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Verify in Nextcloud: /settings/admin/talk"
|
||||||
|
echo "=========================================="
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_status() {
|
||||||
|
local enabled=$(get_config main enabled 0)
|
||||||
|
local container=$(get_config main container_name "$CONTAINER_NAME")
|
||||||
|
local nc_domain=$(get_config server nc_domain '')
|
||||||
|
local signaling_domain=$(get_config server signaling_domain '')
|
||||||
|
|
||||||
|
echo "Nextcloud Talk HPB Status"
|
||||||
|
echo "========================="
|
||||||
|
echo ""
|
||||||
|
echo "Enabled: $([ "$enabled" = "1" ] && echo "Yes" || echo "No")"
|
||||||
|
echo "NC Domain: ${nc_domain:-Not configured}"
|
||||||
|
echo "Signaling Domain: ${signaling_domain:-Not configured}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then
|
||||||
|
echo "Container: Running"
|
||||||
|
echo ""
|
||||||
|
docker ps --filter "name=${container}" --format "table {{.Status}}\t{{.Ports}}"
|
||||||
|
elif docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then
|
||||||
|
echo "Container: Stopped"
|
||||||
|
else
|
||||||
|
echo "Container: Not created"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_test() {
|
||||||
|
local signaling_domain=$(get_config server signaling_domain '')
|
||||||
|
|
||||||
|
if [ -z "$signaling_domain" ]; then
|
||||||
|
echo "Error: Signaling domain not configured"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Testing signaling server..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local url="https://${signaling_domain}/api/v1/welcome"
|
||||||
|
echo "URL: $url"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local response=$(curl -s -m 10 "$url" 2>/dev/null)
|
||||||
|
if [ -n "$response" ]; then
|
||||||
|
echo "Response: $response"
|
||||||
|
if echo "$response" | grep -q "nextcloud-spreed-signaling"; then
|
||||||
|
echo ""
|
||||||
|
echo "SUCCESS: Signaling server is working!"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo "WARNING: Unexpected response"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "ERROR: No response from signaling server"
|
||||||
|
echo ""
|
||||||
|
echo "Check:"
|
||||||
|
echo " 1. Container is running: talk-hpbctl status"
|
||||||
|
echo " 2. HAProxy vhost is configured"
|
||||||
|
echo " 3. SSL certificate is valid"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_logs() {
|
||||||
|
local lines="${1:-100}"
|
||||||
|
local container=$(get_config main container_name "$CONTAINER_NAME")
|
||||||
|
docker logs --tail "$lines" "$container" 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_pull() {
|
||||||
|
local image=$(get_config main image 'ghcr.io/nextcloud-releases/aio-talk:latest')
|
||||||
|
echo "Pulling latest image: $image"
|
||||||
|
docker pull "$image"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main
|
||||||
|
case "$1" in
|
||||||
|
status)
|
||||||
|
cmd_status
|
||||||
|
;;
|
||||||
|
setup)
|
||||||
|
cmd_setup "$2" "$3"
|
||||||
|
;;
|
||||||
|
generate-secrets)
|
||||||
|
cmd_generate_secrets
|
||||||
|
;;
|
||||||
|
show-secrets)
|
||||||
|
cmd_show_secrets
|
||||||
|
;;
|
||||||
|
show-config)
|
||||||
|
cmd_show_config
|
||||||
|
;;
|
||||||
|
test)
|
||||||
|
cmd_test
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
cmd_logs "$2"
|
||||||
|
;;
|
||||||
|
pull)
|
||||||
|
cmd_pull
|
||||||
|
;;
|
||||||
|
start)
|
||||||
|
/etc/init.d/talk-hpb start
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
/etc/init.d/talk-hpb stop
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
/etc/init.d/talk-hpb restart
|
||||||
|
;;
|
||||||
|
enable)
|
||||||
|
/etc/init.d/talk-hpb enable
|
||||||
|
uci set "$UCI_CONFIG.main.enabled=1"
|
||||||
|
uci commit "$UCI_CONFIG"
|
||||||
|
echo "Talk HPB enabled"
|
||||||
|
;;
|
||||||
|
disable)
|
||||||
|
/etc/init.d/talk-hpb disable
|
||||||
|
uci set "$UCI_CONFIG.main.enabled=0"
|
||||||
|
uci commit "$UCI_CONFIG"
|
||||||
|
echo "Talk HPB disabled"
|
||||||
|
;;
|
||||||
|
-h|--help|help|"")
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command: $1"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Loading…
Reference in New Issue
Block a user