- Refactor in bot package.

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-10-18 12:01:39 -03:00
parent 79ac6df738
commit be1e2575f9
27 changed files with 233 additions and 1663 deletions

View file

@ -2,7 +2,7 @@
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$SCRIPT_DIR"
OUTPUT_FILE="$SCRIPT_DIR/prompt.out"
OUTPUT_FILE="/tmp/prompt.out"
rm -f "$OUTPUT_FILE"
echo "Consolidated LLM Context" > "$OUTPUT_FILE"
@ -10,7 +10,6 @@ echo "Consolidated LLM Context" > "$OUTPUT_FILE"
prompts=(
"./prompts/dev/shared.md"
"./Cargo.toml"
"./prompts/dev/generation.md"
)
for file in "${prompts[@]}"; do
@ -24,19 +23,19 @@ dirs=(
#"auth"
#"automation"
#"basic"
#"bot"
"bot"
#"channels"
"config"
#"context"
"context"
#"email"
#"file"
#"llm"
"file"
"llm"
#"llm_legacy"
#"org"
"session"
"shared"
#"tests"
#"tools"
"tools"
#"web_automation"
#"whatsapp"
)
@ -59,25 +58,10 @@ done
# Additional specific files
files=(
"$PROJECT_ROOT/src/main.rs"
"$PROJECT_ROOT/scripts/containers/proxy.sh"
"$PROJECT_ROOT/scripts/containers/directory.sh"
"$PROJECT_ROOT/scripts/containers/bot.sh"
"$PROJECT_ROOT/scripts/containers/system.sh"
"$PROJECT_ROOT/scripts/containers/social.sh"
"$PROJECT_ROOT/scripts/containers/alm-ci.sh"
"$PROJECT_ROOT/scripts/containers/drive.sh"
"$PROJECT_ROOT/scripts/containers/tables.sh"
"$PROJECT_ROOT/scripts/containers/dns.sh"
"$PROJECT_ROOT/scripts/containers/doc-editor.sh"
"$PROJECT_ROOT/scripts/containers/host.sh"
"$PROJECT_ROOT/scripts/containers/vector-db.sh"
"$PROJECT_ROOT/scripts/containers/cache.sh"
"$PROJECT_ROOT/scripts/containers/desktop.sh"
"$PROJECT_ROOT/scripts/containers/meeting.sh"
"$PROJECT_ROOT/scripts/containers/email.sh"
"$PROJECT_ROOT/scripts/containers/alm.sh"
"$PROJECT_ROOT/scripts/containers/table-editor.sh"
"$PROJECT_ROOT/scripts/containers/webmail.sh"
"$PROJECT_ROOT/src/basic/keywords/mod.rs"
"$PROJECT_ROOT/src/basic/keywords/get.rs"
"$PROJECT_ROOT/src/basic/keywords/find.rs"
"$PROJECT_ROOT/src/basic/keywords/hear_talk.rs"
)
@ -108,3 +92,4 @@ echo "Context size: $FILE_SIZE bytes"
cat "$OUTPUT_FILE" | xclip -selection clipboard
echo "Content copied to clipboard (xclip)"
rm -f "$OUTPUT_FILE"

View file

@ -1,16 +0,0 @@
do not comment or echo anything
keep lines condensed
always call it <kind> not own name. Eg.: proxy instead of Caddy. alm instead of forgejo.
use KISS priciple
use local /opt/gbo/{logs, data, conf} exposed as
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/<kind>"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
instead of using app original paths.
and use /opt/gbo/bin to put local binaries of installations
during sh exection, never touch files in /opt/gbo/{logs, data, conf}
use wget
use gbuser as system user

View file

@ -1,173 +0,0 @@
#!/bin/bash
# Configuration
ALM_CI_NAME="CI"
ALM_CI_LABELS="gbo"
FORGEJO_RUNNER_VERSION="v6.3.1"
FORGEJO_RUNNER_BINARY="forgejo-runner-6.3.1-linux-amd64"
CONTAINER_IMAGE="images:debian/12"
# Paths
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/alm-ci"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
BIN_PATH="/opt/gbo/bin"
CONTAINER_NAME="${PARAM_TENANT}-alm-ci"
# Create host directories
mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS" || exit 1
chmod -R 750 "$HOST_BASE" || exit 1
# Launch container
if ! lxc launch "$CONTAINER_IMAGE" "$CONTAINER_NAME" -c security.privileged=true; then
echo "Failed to launch container"
exit 1
fi
# Wait for container to be ready
for i in {1..10}; do
if lxc exec "$CONTAINER_NAME" -- bash -c "true"; then
break
fi
sleep 3
done
# Container setup
lxc exec "$CONTAINER_NAME" -- bash -c "
set -e
useradd --system --no-create-home --shell /bin/false $CONTAINER_NAME
# Update and install dependencies
apt-get update && apt-get install -y wget git || { echo 'Package installation failed'; exit 1; }
sudo apt update
sudo apt install -y curl gnupg ca-certificates git
apt-get update && apt-get install -y \
build-essential cmake git pkg-config libjpeg-dev libtiff-dev \
libpng-dev libavcodec-dev libavformat-dev libswscale-dev \
libv4l-dev libatlas-base-dev gfortran python3-dev cpulimit \
expect libxtst-dev libpng-dev
sudo apt-get install -y libcairo2-dev libpango1.0-dev libgif-dev librsvg2-dev
sudo apt install xvfb -y
sudo apt install -y \
libnss3 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libdrm2 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libasound2 \
libpangocairo-1.0-0
export OPENCV4NODEJS_DISABLE_AUTOBUILD=1
export OPENCV_LIB_DIR=/usr/lib/x86_64-linux-gnu
sudo apt install -y curl gnupg ca-certificates git
# Install Node.js 22.x
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -
sudo apt install -y nodejs
npm install -g pnpm@latest
# Install rust 1.85
apt-get install -y libssl-dev pkg-config
sudo apt-get install -y \
apt-transport-https \
software-properties-common \
gnupg \
cmake \
build-essential \
clang \
libclang-dev \
libz-dev \
libssl-dev \
pkg-config
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.85.1 -y
source ~/.cargo/env
rustc --version
# Install Xvfb and other dependencies
sudo apt install -y xvfb libgbm-dev lxd-client
# Create directories
mkdir -p \"$BIN_PATH\" /opt/gbo/data /opt/gbo/conf /opt/gbo/logs || { echo 'Directory creation failed'; exit 1; }
# Download and install forgejo-runner
wget -O \"$BIN_PATH/forgejo-runner\" \"https://code.forgejo.org/forgejo/runner/releases/download/$FORGEJO_RUNNER_VERSION/$FORGEJO_RUNNER_BINARY\" || { echo 'Download failed'; exit 1; }
chmod +x \"$BIN_PATH/forgejo-runner\" || { echo 'chmod failed'; exit 1; }
cd \"$BIN_PATH\"
# Register runner
\"$BIN_PATH/forgejo-runner\" register --no-interactive \\
--name \"$ALM_CI_NAME\" \\
--instance \"$PARAM_ALM_CI_INSTANCE\" \\
--token \"$PARAM_ALM_CI_TOKEN\" \\
--labels \"$ALM_CI_LABELS\" || { echo 'Runner registration failed'; exit 1; }
chown -R $CONTAINER_NAME:$CONTAINER_NAME /opt/gbo/bin /opt/gbo/data /opt/gbo/conf /opt/gbo/logs
"
# Set permissions
echo "[CONTAINER] Setting permissions..."
EMAIL_UID=$(lxc exec "$PARAM_TENANT"-alm-ci -- id -u $CONTAINER_NAME)
EMAIL_GID=$(lxc exec "$PARAM_TENANT"-alm-ci -- id -g $CONTAINER_NAME)
HOST_EMAIL_UID=$((100000 + EMAIL_UID))
HOST_EMAIL_GID=$((100000 + EMAIL_GID))
sudo chown -R "$HOST_EMAIL_UID:$HOST_EMAIL_GID" "$HOST_BASE"
# Add directory mappings
lxc config device add "$CONTAINER_NAME" almdata disk source="$HOST_DATA" path=/opt/gbo/data || exit 1
lxc config device add "$CONTAINER_NAME" almconf disk source="$HOST_CONF" path=/opt/gbo/conf || exit 1
lxc config device add "$CONTAINER_NAME" almlogs disk source="$HOST_LOGS" path=/opt/gbo/logs || exit 1
lxc exec "$CONTAINER_NAME" -- bash -c "
# Create systemd service
cat > /etc/systemd/system/alm-ci.service <<EOF
[Unit]
Description=ALM CI Runner
After=network.target
[Service]
Type=simple
User=$CONTAINER_NAME
Group=$CONTAINER_NAME
ExecStart=$BIN_PATH/forgejo-runner daemon
Restart=always
RestartSec=5
StandardOutput=append:/opt/gbo/logs/output.log
StandardError=append:/opt/gbo/logs/error.log
[Install]
WantedBy=multi-user.target
EOF
# Enable and start service
systemctl daemon-reload || { echo 'daemon-reload failed'; exit 1; }
systemctl enable alm-ci || { echo 'enable service failed'; exit 1; }
systemctl start alm-ci || { echo 'start service failed'; exit 1; }
"
LXC_BOT="/opt/gbo/tenants/$PARAM_TENANT/bot/data"
LXC_PROXY="/opt/gbo/tenants/$PARAM_TENANT/proxy/data/websites"
LXC_SYSTEM="/opt/gbo/tenants/$PARAM_TENANT/system/bin"
lxc config device add "$CONTAINER_NAME" almbot disk source="$LXC_BOT" path=/opt/gbo/bin/bot
lxc config device add "$CONTAINER_NAME" almproxy disk source="$LXC_PROXY" path=/opt/gbo/bin/proxy
lxc config device add "$CONTAINER_NAME" almsystem disk source="$LXC_SYSTEM" path=/opt/gbo/bin/syst em || exit 1

View file

@ -1,65 +0,0 @@
#!/bin/bash
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/alm"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
ALM_PATH=/opt/gbo/bin
mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
chmod -R 750 "$HOST_BASE"
lxc launch images:debian/12 "$PARAM_TENANT"-alm -c security.privileged=true
sleep 15
lxc exec "$PARAM_TENANT"-alm -- bash -c "
apt-get update && apt-get install -y git git-lfs wget
mkdir -p /opt/gbo/bin
wget https://codeberg.org/forgejo/forgejo/releases/download/v10.0.2/forgejo-10.0.2-linux-amd64 -O $ALM_PATH/forgejo
chmod +x $ALM_PATH/forgejo
useradd --system --no-create-home --shell /bin/false alm
"
FORGEJO_UID=$(lxc exec "$PARAM_TENANT"-alm -- id -u alm)
FORGEJO_GID=$(lxc exec "$PARAM_TENANT"-alm -- id -g alm)
HOST_FORGEJO_UID=$((100000 + FORGEJO_UID))
HOST_FORGEJO_GID=$((100000 + FORGEJO_GID))
chown -R "$HOST_FORGEJO_UID:$HOST_FORGEJO_GID" "$HOST_BASE"
lxc config device add "$PARAM_TENANT"-alm almdata disk source="$HOST_DATA" path=/opt/gbo/data
lxc config device add "$PARAM_TENANT"-alm almconf disk source="$HOST_CONF" path=/opt/gbo/conf
lxc config device add "$PARAM_TENANT"-alm almlogs disk source="$HOST_LOGS" path=/opt/gbo/logs
lxc exec "$PARAM_TENANT"-alm -- bash -c "
mkdir -p /opt/gbo/data /opt/gbo/conf /opt/gbo/logs
chown -R alm:alm /opt/gbo
cat > /etc/systemd/system/alm.service <<EOF
[Unit]
Description=alm
After=network.target
[Service]
User=alm
Group=alm
WorkingDirectory=/opt/gbo/data
ExecStart=/opt/gbo/bin/forgejo web --config /opt/gbo/conf/app.ini
Restart=always
Environment=USER=alm HOME=/opt/gbo/data
StandardOutput=append:/opt/gbo/logs/stdout.log
StandardError=append:/opt/gbo/logs/stderr.log
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable alm
systemctl start alm
"
lxc config device remove "$PARAM_TENANT"-alm alm-proxy 2>/dev/null || true
lxc config device add "$PARAM_TENANT"-alm alm-proxy proxy \
listen=tcp:0.0.0.0:"$PARAM_ALM_PORT" \
connect=tcp:127.0.0.1:"$PARAM_ALM_PORT"

View file

@ -1,113 +0,0 @@
#!/bin/bash
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/bot"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
chmod -R 750 "$HOST_BASE"
lxc launch images:debian/12 "$PARAM_TENANT"-bot -c security.privileged=true
sleep 15
lxc exec "$PARAM_TENANT"-bot -- bash -c "
apt-get update && apt-get install -y \
build-essential cmake git pkg-config libjpeg-dev libtiff-dev \
libpng-dev libavcodec-dev libavformat-dev libswscale-dev \
libv4l-dev libatlas-base-dev gfortran python3-dev cpulimit \
expect libxtst-dev libpng-dev
sudo apt-get install -y libcairo2-dev libpango1.0-dev libgif-dev librsvg2-dev
sudo apt install xvfb -y
sudo apt install -y \
libnss3 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libdrm2 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libasound2 \
libpangocairo-1.0-0
export OPENCV4NODEJS_DISABLE_AUTOBUILD=1
export OPENCV_LIB_DIR=/usr/lib/x86_64-linux-gnu
useradd --system --no-create-home --shell /bin/false gbuser
"
BOT_UID=$(lxc exec "$PARAM_TENANT"-bot -- id -u gbuser)
BOT_GID=$(lxc exec "$PARAM_TENANT"-bot -- id -g gbuser)
HOST_BOT_UID=$((100000 + BOT_UID))
HOST_BOT_GID=$((100000 + BOT_GID))
chown -R "$HOST_BOT_UID:$HOST_BOT_GID" "$HOST_BASE"
lxc config device add "$PARAM_TENANT"-bot botdata disk source="$HOST_DATA" path=/opt/gbo/data
lxc config device add "$PARAM_TENANT"-bot botconf disk source="$HOST_CONF" path=/opt/gbo/conf
lxc config device add "$PARAM_TENANT"-bot botlogs disk source="$HOST_LOGS" path=/opt/gbo/logs
lxc exec "$PARAM_TENANT"-bot -- bash -c '
mkdir -p /opt/gbo/data /opt/gbo/conf /opt/gbo/logs
sudo apt update
sudo apt install -y curl gnupg ca-certificates git
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -
sudo apt install -y nodejs
sudo apt install -y xvfb libgbm-dev
wget https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_128.0.6613.119-1_amd64.deb
sudo apt install ./google-chrome-stable_128.0.6613.119-1_amd64.deb
cd /opt/gbo/data
git clone https://alm.pragmatismo.com.br/generalbots/botserver.git
cd botserver
npm install
./node_modules/.bin/tsc
cd packages/default.gbui
npm install
npm run build
chown -R gbuser:gbuser /opt/gbo
# Create systemd service
sudo tee /etc/systemd/system/bot.service > /dev/null <<EOF
[Unit]
Description=Bot Server
After=network.target
[Service]
User=gbuser
Group=gbuser
Environment="DISPLAY=:99"
ExecStartPre=/bin/bash -c "/usr/bin/Xvfb :99 -screen 0 1024x768x24 -ac +extension GLX +render -noreset &"
WorkingDirectory=/opt/gbo/data/botserver
ExecStart=/usr/bin/node /opt/gbo/data/botserver/boot.mjs
Restart=always
RestartSec=5
StandardOutput=append:/opt/gbo/logs/stdout.log
StandardError=append:/opt/gbo/logs/stderr.log
[Install]
WantedBy=multi-user.target
EOF
# Reload and start service
sudo systemctl daemon-reload
sudo systemctl enable bot.service
sudo systemctl start bot.service
'
lxc config device remove "$PARAM_TENANT"-bot bot-proxy 2>/dev/null || true
lxc config device add "$PARAM_TENANT"-bot bot-proxy proxy \
listen=tcp:0.0.0.0:"$PARAM_BOT_PORT" \
connect=tcp:127.0.0.1:"$PARAM_BOT_PORT"

View file

@ -1,7 +0,0 @@
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/valkey.gpg
echo "deb [signed-by=/usr/share/keyrings/valkey.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/valkey.list
sudo apt update
sudo apt install valkey-server
sudo systemctl enable valkey-server
sudo systemctl start valkey-server

View file

@ -1,47 +0,0 @@
#!/bin/bash
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/desktop"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
chmod -R 750 "$HOST_BASE"
lxc launch images:debian/12 "$PARAM_TENANT"-desktop -c security.privileged=true
sleep 15
lxc exec "$PARAM_TENANT"-desktop -- bash -c "
apt-get update
apt-get install -y xvfb xrdp xfce4 xfce4-goodies
cat > /etc/xrdp/startwm.sh <<EOF
#!/bin/sh
if [ -r /etc/default/locale ]; then
. /etc/default/locale
export LANG LANGUAGE
fi
startxfce4
EOF
chmod +x /etc/xrdp/startwm.sh
systemctl restart xrdp
systemctl enable xrdp
# For the root user (since you're logging in as root)
echo "exec startxfce4" > /root/.xsession
chmod +x /root/.xsession
apt install -y curl apt-transport-https gnupg
curl -s https://brave-browser-apt-release.s3.brave.com/brave-core.asc | gpg --dearmor > /usr/share/keyrings/brave-browser-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/brave-browser-archive-keyring.gpg] https://brave-browser-apt-release.s3.brave.com/ stable main" > /etc/apt/sources.list.d/brave-browser-release.list
apt update && apt install -y brave-browser
sudo apt install gnome-tweaks
/etc/environment
GTK_IM_MODULE=cedilla
QT_IM_MODULE=cedilla
"
port=3389
lxc config device remove "$PARAM_TENANT"-desktop "port-$port" 2>/dev/null || true
lxc config device add "$PARAM_TENANT"-desktop "port-$port" proxy listen=tcp:0.0.0.0:$port connect=tcp:127.0.0.1:$port

View file

@ -1,67 +0,0 @@
#!/bin/bash
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/directory"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
sudo mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
sudo chmod -R 750 "$HOST_BASE"
lxc launch images:debian/12 "$PARAM_TENANT"-directory -c security.privileged=true
sleep 15
lxc exec "$PARAM_TENANT"-directory -- bash -c "
apt-get update && apt-get install -y wget libcap2-bin
wget -c https://github.com/zitadel/zitadel/releases/download/v2.71.2/zitadel-linux-amd64.tar.gz -O - | tar -xz -C /tmp
mkdir -p /opt/gbo/bin
mv /tmp/zitadel-linux-amd64/zitadel /opt/gbo/bin/zitadel
chmod +x /opt/gbo/bin/zitadel
sudo setcap 'cap_net_bind_service=+ep' /opt/gbo/bin/zitadel
useradd --system --no-create-home --shell /bin/false gbuser
mkdir -p /opt/gbo/data /opt/gbo/conf /opt/gbo/logs
chown -R gbuser:gbuser /opt/gbo/data /opt/gbo/conf /opt/gbo/logs /opt/gbo/bin
"
GBUSER_UID=$(lxc exec "$PARAM_TENANT"-directory -- id -u gbuser)
GBUSER_GID=$(lxc exec "$PARAM_TENANT"-directory -- id -g gbuser)
HOST_GBUSER_UID=$((100000 + GBUSER_UID))
HOST_GBUSER_GID=$((100000 + GBUSER_GID))
sudo chown -R "$HOST_GBUSER_UID:$HOST_GBUSER_GID" "$HOST_BASE"
lxc config device add "$PARAM_TENANT"-directory directorydata disk source="$HOST_DATA" path=/opt/gbo/data
lxc config device add "$PARAM_TENANT"-directory directoryconf disk source="$HOST_CONF" path=/opt/gbo/conf
lxc config device add "$PARAM_TENANT"-directory directorylogs disk source="$HOST_LOGS" path=/opt/gbo/logs
lxc exec "$PARAM_TENANT"-directory -- bash -c "
chown -R gbuser:gbuser /opt/gbo/data /opt/gbo/conf /opt/gbo/logs /opt/gbo/bin
cat > /etc/systemd/system/directory.service <<EOF
[Unit]
Description=Directory Service
After=network.target
[Service]
Type=simple
User=gbuser
Group=gbuser
ExecStart=/opt/gbo/bin/zitadel start --masterkey $PARAM_DIRECTORY_MASTERKEY --config /opt/gbo/conf/config.yaml --tlsMode external
WorkingDirectory=/opt/gbo/bin
StandardOutput=append:/opt/gbo/logs/output.log
StandardError=append:/opt/gbo/logs/error.log
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable directory
systemctl start directory
"
lxc config device remove "$PARAM_TENANT"-directory directory-proxy 2>/dev/null || true
lxc config device add "$PARAM_TENANT"-directory directory-proxy proxy \
listen=tcp:0.0.0.0:"$PARAM_DIRECTORY_PORT" \
connect=tcp:127.0.0.1:"$PARAM_DIRECTORY_PORT"

View file

@ -1,88 +0,0 @@
#!/bin/bash
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/dns"
HOST_CONF="$HOST_BASE/conf"
HOST_DATA="$HOST_BASE/data"
HOST_LOGS="$HOST_BASE/logs"
mkdir -p "$HOST_BASE" "$HOST_CONF" "$HOST_DATA" "$HOST_LOGS"
chmod -R 750 "$HOST_BASE"
lxc network set lxdbr0 user.dns.nameservers $PARAM_DNS_INTERNAL_IP,8.8.8.8,1.1.1.1
lxc network set lxdbr0 dns.mode managed
# Clear existing rules
sudo iptables -F
# Allow DNS traffic
sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 53 -j ACCEPT
sudo iptables -A FORWARD -p udp --dport 53 -j ACCEPT
sudo iptables -A FORWARD -p tcp --dport 53 -j ACCEPT
# Enable NAT
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# Save rules (if using iptables-persistent)
sudo netfilter-persistent save
lxc launch images:debian/12 "${PARAM_TENANT}-dns" -c security.privileged=true
until lxc exec "${PARAM_TENANT}-dns" -- true; do sleep 3; done
lxc config device remove pragmatismo-dns dns-udp
lxc config device remove pragmatismo-dns dns-tcp
# Forward HOST's public IP:53 → CONTAINER's 0.0.0.0:53
lxc config device add pragmatismo-dns dns-udp proxy listen=udp:$GB_PUBLIC_IP:53 connect=udp:0.0.0.0:53
lxc config device add pragmatismo-dns dns-tcp proxy listen=tcp:$GB_PUBLIC_IP:53 connect=tcp:0.0.0.0:53
lxc exec "${PARAM_TENANT}-dns" -- bash -c "
mkdir /opt/gbo
mkdir /opt/gbo/{bin,conf,data,logs}
echo 'nameserver 8.8.8.8' > /etc/resolv.conf
apt-get upgrade -y && apt-get install -y wget
wget -qO /opt/gbo/bin/coredns https://github.com/coredns/coredns/releases/download/v1.12.4/coredns_1.12.4_linux_amd64.tgz
tar -xzf /opt/gbo/bin/coredns -C /opt/gbo/bin/
useradd --system --no-create-home --shell /bin/false gbuser
setcap cap_net_bind_service=+ep /opt/gbo/bin/coredns
cat > /etc/systemd/system/dns.service <<EOF2
[Unit]
Description=DNS
After=network.target
[Service]
User=gbuser
ExecStart=/opt/gbo/bin/coredns -conf /opt/gbo/conf/Corefile
Restart=always
StandardOutput=append:/opt/gbo/logs/stdout.log
StandardError=append:/opt/gbo/logs/stderr.log
[Install]
WantedBy=multi-user.target
EOF2
systemctl stop systemd-resolved
systemctl disable systemd-resolved
rm /etc/resolv.conf
systemctl daemon-reload
systemctl enable dns
"
GBUSER_UID=$(lxc exec "${PARAM_TENANT}-dns" -- id -u gbuser)
HOST_UID=$((100000 + GBUSER_UID))
chown -R "$HOST_UID:$HOST_UID" "$HOST_BASE"
lxc exec "${PARAM_TENANT}-dns" -- bash -c "
chown -R gbuser:gbuser /opt/gbo
"
lxc config device add "${PARAM_TENANT}-dns" dnsdata disk source="$HOST_DATA" path=/opt/gbo/data
lxc config device add "${PARAM_TENANT}-dns" dnsconf disk source="$HOST_CONF" path=/opt/gbo/conf
lxc config device add "${PARAM_TENANT}-dns" dnslogs disk source="$HOST_LOGS" path=/opt/gbo/logs
lxc exec "${PARAM_TENANT}-dns" -- systemctl start dns

View file

@ -1,30 +0,0 @@
#!/bin/bash
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/doc-editor"
lxc launch images:debian/12 "${PARAM_TENANT}-doc-editor" \
-c security.privileged=true \
-c limits.cpu=2 \
-c limits.memory=4096MB \
sleep 10
lxc exec "$PARAM_TENANT"-doc-editor -- bash -c "
cd /usr/share/keyrings
wget https://collaboraoffice.com/downloads/gpg/collaboraonline-release-keyring.gpg
cat << EOF > /etc/apt/sources.list.d/collaboraonline.sources
Types: deb
URIs: https://www.collaboraoffice.com/repos/CollaboraOnline/24.04/customer-deb-$customer_hash
Suites: ./
Signed-By: /usr/share/keyrings/collaboraonline-release-keyring.gpg
EOF
apt update && apt install coolwsd collabora-online-brand
"
lxc config device remove "$PARAM_TENANT"-doc-editor doc-proxy 2>/dev/null || true
lxc config device add "$PARAM_TENANT"-doc-editor doc-proxy proxy \
listen=tcp:0.0.0.0:"$PARAM_DOC_PORT" \
connect=tcp:127.0.0.1:9980

View file

@ -1,60 +0,0 @@
#!/bin/bash
STORAGE_PATH="/opt/gbo/tenants/$PARAM_TENANT/drive/data"
LOGS_PATH="/opt/gbo/tenants/$PARAM_TENANT/drive/logs"
mkdir -p "${STORAGE_PATH}" "${LOGS_PATH}"
chmod -R 770 "${STORAGE_PATH}" "${LOGS_PATH}"
chown -R 100999:100999 "${STORAGE_PATH}" "${LOGS_PATH}"
lxc launch images:debian/12 "${PARAM_TENANT}-drive" -c security.privileged=true
sleep 15
lxc config device add "${PARAM_TENANT}-drive" storage disk source="${STORAGE_PATH}" path=/data
lxc config device add "${PARAM_TENANT}-drive" logs disk source="${LOGS_PATH}" path=/var/log/minio
lxc exec "${PARAM_TENANT}-drive" -- bash -c '
apt-get update && apt-get install -y wget
wget https://dl.min.io/server/minio/release/linux-amd64/minio -O /usr/local/bin/minio
chmod +x /usr/local/bin/minio
wget https://dl.min.io/client/mc/release/linux-amd64/mc -O /usr/local/bin/mc
chmod +x /usr/local/bin/mc
useradd -r -s /bin/false minio-user || true
mkdir -p /var/log/minio /data
chown -R minio-user:minio-user /var/log/minio /data
cat > /etc/systemd/system/minio.service <<EOF
[Unit]
Description=MinIO
After=network.target
[Service]
Type=simple
User=minio-user
Group=minio-user
Environment="MINIO_ROOT_USER='"${PARAM_DRIVE_USER}"'"
Environment="MINIO_ROOT_PASSWORD='"${PARAM_DRIVE_PASSWORD}"'"
ExecStart=/usr/local/bin/minio server --address ":'"${PARAM_DRIVE_PORT}"'" --console-address ":'"${PARAM_PORT}"'" /data
StandardOutput=append:/var/log/minio/output.log
StandardError=append:/var/log/minio/error.log
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable minio
systemctl start minio
'
lxc config device remove "${PARAM_TENANT}-drive" minio-proxy 2>/dev/null || true
lxc config device add "${PARAM_TENANT}-drive" minio-proxy proxy \
listen=tcp:0.0.0.0:"${PARAM_DRIVE_API_PORT}" \
connect=tcp:127.0.0.1:"${PARAM_DRIVE_API_PORT}"
lxc config device remove "${PARAM_TENANT}-drive" console-proxy 2>/dev/null || true
lxc config device add "${PARAM_TENANT}-drive" console-proxy proxy \
listen=tcp:0.0.0.0:"${PARAM_DRIVE_PORT}" \
connect=tcp:127.0.0.1:"${PARAM_DRIVE_PORT}"

View file

@ -1,107 +0,0 @@
#!/bin/bash
PUBLIC_INTERFACE="eth0" # Your host's public network interface
# Configure firewall
echo "[HOST] Configuring firewall..."
sudo iptables -A FORWARD -i $PUBLIC_INTERFACE -o lxcbr0 -p tcp -m multiport --dports 25,80,110,143,465,587,993,995,4190 -j ACCEPT
sudo iptables -A FORWARD -i lxcbr0 -o $PUBLIC_INTERFACE -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -t nat -A POSTROUTING -o $PUBLIC_INTERFACE -j MASQUERADE
# IPv6 firewall
sudo ip6tables -A FORWARD -i $PUBLIC_INTERFACE -o lxcbr0 -p tcp -m multiport --dports 25,80,110,143,465,587,993,995,4190 -j ACCEPT
sudo ip6tables -A FORWARD -i lxcbr0 -o $PUBLIC_INTERFACE -m state --state RELATED,ESTABLISHED -j ACCEPT
# Save iptables rules permanently (adjust based on your distro)
if command -v iptables-persistent >/dev/null; then
sudo iptables-save | sudo tee /etc/iptables/rules.v4
sudo ip6tables-save | sudo tee /etc/iptables/rules.v6
fi
# ------------------------- CONTAINER SETUP -------------------------
# Create directory structure
echo "[CONTAINER] Creating directories..."
HOST_BASE="/opt/email"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
sudo mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
sudo chmod -R 750 "$HOST_BASE"
# Launch container
echo "[CONTAINER] Launching LXC container..."
lxc launch images:debian/12 "$PARAM_TENANT"-email -c security.privileged=true
sleep 15
echo "[CONTAINER] Installing Stalwart Mail..."
lxc exec "$PARAM_TENANT"-email -- bash -c "
echo "nameserver $PARAM_DNS_INTERNAL_IP" > /etc/resolv.conf
apt install resolvconf -y
apt-get update && apt-get install -y wget libcap2-bin
wget -O /tmp/stalwart.tar.gz https://github.com/stalwartlabs/stalwart/releases/download/v0.13.1/stalwart-x86_64-unknown-linux-gnu.tar.gz
tar -xzf /tmp/stalwart.tar.gz -C /tmp
mkdir -p /opt/gbo/bin
mv /tmp/stalwart /opt/gbo/bin/stalwart
chmod +x /opt/gbo/bin/stalwart
sudo setcap 'cap_net_bind_service=+ep' /opt/gbo/bin/stalwart
rm /tmp/stalwart.tar.gz
useradd --system --no-create-home --shell /bin/false email
mkdir -p /opt/gbo/data /opt/gbo/conf /opt/gbo/logs
chown -R email:email /opt/gbo/data /opt/gbo/conf /opt/gbo/logs /opt/gbo/bin
"
# Set permissions
echo "[CONTAINER] Setting permissions..."
EMAIL_UID=$(lxc exec "$PARAM_TENANT"-email -- id -u email)
EMAIL_GID=$(lxc exec "$PARAM_TENANT"-email -- id -g email)
HOST_EMAIL_UID=$((100000 + EMAIL_UID))
HOST_EMAIL_GID=$((100000 + EMAIL_GID))
sudo chown -R "$HOST_EMAIL_UID:$HOST_EMAIL_GID" "$HOST_BASE"
# Mount directories
echo "[CONTAINER] Mounting directories..."
lxc config device add "$PARAM_TENANT"-email emaildata disk source="$HOST_DATA" path=/opt/gbo/data
lxc config device add "$PARAM_TENANT"-email emailconf disk source="$HOST_CONF" path=/opt/gbo/conf
lxc config device add "$PARAM_TENANT"-email emaillogs disk source="$HOST_LOGS" path=/opt/gbo/logs
# Create systemd service
echo "[CONTAINER] Creating email service..."
lxc exec "$PARAM_TENANT"-email -- bash -c "
chown -R email:email /opt/gbo/data /opt/gbo/conf /opt/gbo/logs /opt/gbo/bin
cat > /etc/systemd/system/email.service <<EOF
[Unit]
Description=Email Service
After=network.target
[Service]
Type=simple
User=email
Group=email
ExecStart=/opt/gbo/bin/stalwart --config /opt/gbo/conf/config.toml
WorkingDirectory=/opt/gbo/bin
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable email
systemctl start email
"
# FIXED: IPv4 + IPv6 proxy devices
for port in 25 80 110 143 465 587 993 995 4190; do
lxc config device remove "$PARAM_TENANT"-email "port-$port" 2>/dev/null || true
lxc config device add "$PARAM_TENANT"-email "port-$port" proxy \
listen=tcp:0.0.0.0:$port \
listen=tcp:[::]:$port \
connect=tcp:127.0.0.1:$port
done

View file

@ -1,30 +0,0 @@
sudo apt install sshfs -y
lxc init
lxc storage create default dir
lxc profile device add default root disk path=/ pool=default
sudo apt update && sudo apt install -y bridge-utils
# Enable IP forwarding
echo "[HOST] Enabling IP forwarding..."
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
sudo apt purge '^nvidia-*' # Clean existing drivers
sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt update
sudo apt install nvidia-driver-470-server # Most stable for Kepler GPUs
wget https://developer.download.nvidia.com/compute/cuda/11.0.3/local_installers/cuda_11.0.3_450.51.06_linux.run
sudo sh cuda_11.0.3_450.51.06_linux.run --override

View file

@ -1,89 +0,0 @@
#!/bin/bash
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/meeting"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
chmod -R 750 "$HOST_BASE"
lxc launch images:debian/12 "$PARAM_TENANT"-meeting -c security.privileged=true
sleep 15
lxc exec "$PARAM_TENANT"-meeting -- bash -c "
apt-get update && apt-get install -y wget coturn
mkdir -p /opt/gbo/bin
cd /opt/gbo/bin
wget -q https://github.com/livekit/livekit/releases/download/v1.8.4/livekit_1.8.4_linux_amd64.tar.gz
tar -xzf livekit*.tar.gz
rm livekit_1.8.4_linux_amd64.tar.gz
chmod +x livekit-server
while netstat -tuln | grep -q \":$PARAM_MEETING_TURN_PORT \"; do
((PARAM_MEETING_TURN_PORT++))
done
useradd --system --no-create-home --shell /bin/false gbuser
"
MEETING_UID=$(lxc exec "$PARAM_TENANT"-meeting -- id -u gbuser)
MEETING_GID=$(lxc exec "$PARAM_TENANT"-meeting -- id -g gbuser)
HOST_MEETING_UID=$((100000 + MEETING_UID))
HOST_MEETING_GID=$((100000 + MEETING_GID))
chown -R "$HOST_MEETING_UID:$HOST_MEETING_GID" "$HOST_BASE"
lxc config device add "$PARAM_TENANT"-meeting meetingdata disk source="$HOST_DATA" path=/opt/gbo/data
lxc config device add "$PARAM_TENANT"-meeting meetingconf disk source="$HOST_CONF" path=/opt/gbo/conf
lxc config device add "$PARAM_TENANT"-meeting meetinglogs disk source="$HOST_LOGS" path=/opt/gbo/logs
lxc exec "$PARAM_TENANT"-meeting -- bash -c "
mkdir -p /opt/gbo/data /opt/gbo/conf /opt/gbo/logs
chown -R gbuser:gbuser /opt/gbo/data /opt/gbo/conf /opt/gbo/logs
sudo chown gbuser:gbuser /var/run/turnserver.pid
cat > /etc/systemd/system/meeting.service <<EOF
[Unit]
Description=LiveKit Server
After=network.target
[Service]
User=gbuser
Group=gbuser
ExecStart=/opt/gbo/bin/livekit-server --config /opt/gbo/conf/config.yaml
Restart=always
Environment=TURN_PORT=$PARAM_MEETING_TURN_PORT
[Install]
WantedBy=multi-user.target
EOF
cat > /etc/systemd/system/meeting-turn.service <<EOF
[Unit]
Description=TURN Server
After=network.target
[Service]
User=gbuser
Group=gbuser
ExecStart=/usr/bin/turnserver -c /opt/gbo/conf/turnserver.conf
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable meeting meeting-turn
systemctl start meeting meeting-turn
"
lxc config device remove "$PARAM_TENANT"-meeting meeting-proxy 2>/dev/null || true
lxc config device add "$PARAM_TENANT"-meeting meeting-proxy proxy \
listen=tcp:0.0.0.0:"$PARAM_MEETING_PORT" \
connect=tcp:127.0.0.1:"$PARAM_MEETING_PORT"

View file

@ -1,56 +0,0 @@
#!/bin/bash
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/proxy"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
mkdir -p "$HOST_BASE" "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
chmod 750 "$HOST_BASE" "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
lxc launch images:debian/12 "$PARAM_TENANT"-proxy -c security.privileged=true
sleep 15
lxc exec "$PARAM_TENANT"-proxy -- bash -c "
mkdir -p /opt/gbo/{bin,data,conf,logs}
apt-get update && apt-get install -y wget libcap2-bin
wget -q https://github.com/caddyserver/caddy/releases/download/v2.10.0-beta.3/caddy_2.10.0-beta.3_linux_amd64.tar.gz
tar -xzf caddy_2.10.0-beta.3_linux_amd64.tar.gz -C /opt/gbo/bin
rm caddy_2.10.0-beta.3_linux_amd64.tar.gz
chmod 750 /opt/gbo/bin/caddy
setcap 'cap_net_bind_service=+ep' /opt/gbo/bin/caddy
useradd --create-home --system --shell /usr/sbin/nologin gbuser
chown -R gbuser:gbuser /opt/gbo/{bin,data,conf,logs}
"
lxc config device add "$PARAM_TENANT"-proxy data disk source="$HOST_DATA" path=/opt/gbo/data
lxc config device add "$PARAM_TENANT"-proxy conf disk source="$HOST_CONF" path=/opt/gbo/conf
lxc config device add "$PARAM_TENANT"-proxy logs disk source="$HOST_LOGS" path=/opt/gbo/logs
lxc exec "$PARAM_TENANT"-proxy -- bash -c "
cat > /etc/systemd/system/proxy.service <<EOF
[Unit]
Description=Proxy
After=network.target
[Service]
User=gbuser
Group=gbuser
Environment=XDG_DATA_HOME=/opt/gbo/data
ExecStart=/opt/gbo/bin/caddy run --config /opt/gbo/conf/config --adapter caddyfile
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
chown -R gbuser:gbuser /opt/gbo/{bin,data,conf,logs}
systemctl enable proxy
"
for port in 80 443; do
lxc config device remove "$PARAM_TENANT"-proxy "port-$port" 2>/dev/null || true
lxc config device add "$PARAM_TENANT"-proxy "port-$port" proxy listen=tcp:0.0.0.0:$port connect=tcp:127.0.0.1:$port
done
lxc config set "$PARAM_TENANT"-proxy security.syscalls.intercept.mknod true
lxc config set "$PARAM_TENANT"-proxy security.syscalls.intercept.setxattr true

View file

@ -1 +0,0 @@
https://www.brasil247.com/mundo/meta-quer-automatizar-totalmente-publicidade-com-ia-ate-2026-diz-wsj

View file

@ -1,94 +0,0 @@
#!/bin/bash
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/system"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
HOST_BIN="$HOST_BASE/bin"
BIN_PATH="/opt/gbo/bin"
CONTAINER_NAME="${PARAM_TENANT}-system"
# Create host directories
mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS" || exit 1
chmod -R 750 "$HOST_BASE" || exit 1
lxc launch images:debian/12 $CONTAINER_NAME -c security.privileged=true
sleep 15
lxc exec $CONTAINER_NAME -- bash -c '
apt-get update && apt-get install -y wget curl unzip git
useradd -r -s /bin/false gbuser || true
mkdir -p /opt/gbo/logs /opt/gbo/bin /opt/gbo/data /opt/gbo/conf
chown -R gbuser:gbuser /opt/gbo/
wget https://github.com/ggml-org/llama.cpp/releases/download/b6148/llama-b6148-bin-ubuntu-x64.zip
mkdir llm
mv llama-b6148-bin-ubuntu-x64.zip llm
cd llm
unzip llama-b6148-bin-ubuntu-x64.zip
mv build/bin/* .
rm build/bin -r
rm llama-b6148-bin-ubuntu-x64.zip
sudo apt install lib-pq
wget https://huggingface.co/bartowski/DeepSeek-R1-Distill-Qwen-1.5B-GGUF/resolve/main/DeepSeek-R1-Distill-Qwen-1.5B-Q3_K_M.gguf
wget https://huggingface.co/CompendiumLabs/bge-small-en-v1.5-gguf/resolve/main/bge-small-en-v1.5-f32.gguf
sudo curl -fsSLo /usr/share/keyrings/brave-browser-beta-archive-keyring.gpg https://brave-browser-apt-beta.s3.brave.com/brave-browser-beta-archive-keyring.gpg
sudo curl -fsSLo /etc/apt/sources.list.d/brave-browser-beta.sources https://brave-browser-apt-beta.s3.brave.com/brave-browser.sources
sudo apt update
sudo apt install brave-browser-beta
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
git clone https://alm.pragmatismo.com.br/generalbots/gbserver
apt install -y build-essential \
pkg-config \
libssl-dev \
gcc-multilib \
g++-multilib \
clang \
lld \
binutils-dev \
libudev-dev \
libdbus-1-dev
cat > /etc/systemd/system/system.service <<EOF
[Unit]
Description=General Bots System Service
After=network.target
[Service]
Type=simple
User=gbuser
Group=gbuser
ExecStart=/opt/gbo/bin/gbserver
StandardOutput=append:/opt/gbo/logs/output.log
StandardError=append:/opt/gbo/logs/error.log
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable system
systemctl start system
'
lxc config device add $CONTAINER_NAME bin disk source="${HOST_BIN}" path=/opt/gbo/bin
lxc config device add $CONTAINER_NAME data disk source="${HOST_DATA}" path=/opt/gbo/data
lxc config device add $CONTAINER_NAME conf disk source="${HOST_CONF}" path=/opt/gbo/conf
lxc config device add $CONTAINER_NAME logs disk source="${HOST_LOGS}" path=/opt/gbo/logs
lxc config device add $CONTAINER_NAME system-proxy disk source="/opt/gbo/tenants/$PARAM_TENANT/proxy" path=/opt/gbo/refs/proxy
lxc config device remove $CONTAINER_NAME proxy 2>/dev/null || true
lxc config device add $CONTAINER_NAME proxy proxy \
listen=tcp:0.0.0.0:"${PARAM_SYSTEM_PORT}" \
connect=tcp:127.0.0.1:"${PARAM_SYSTEM_PORT}"

View file

@ -1,86 +0,0 @@
#!/bin/bash
# Fixed container name
CONTAINER_NAME="$PARAM_TENANT-table-editor"
TABLE_EDITOR_PORT="5757"
# Paths
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/table-editor"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
BIN_PATH="/opt/gbo/bin"
# Create host directories
mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
chmod -R 750 "$HOST_BASE"
# Launch container
lxc launch images:debian/12 "$CONTAINER_NAME" -c security.privileged=true
# Wait for container to be ready
sleep 10
# Container setup
lxc exec "$CONTAINER_NAME" -- bash -c "
useradd --system --no-create-home --shell /bin/false gbuser
apt-get update
apt-get install -y wget curl
# Create directories
mkdir -p \"$BIN_PATH\" /opt/gbo/data /opt/gbo/conf /opt/gbo/logs
# Download and install NocoDB binary
cd \"$BIN_PATH\"
curl http://get.nocodb.com/linux-x64 -o nocodb -L
chmod +x nocodb
"
# Set permissions
TE_UID=$(lxc exec "$CONTAINER_NAME" -- id -u gbuser)
TE_GID=$(lxc exec "$CONTAINER_NAME" -- id -g gbuser)
HOST_TE_UID=$((100000 + TE_UID))
HOST_TE_GID=$((100000 + TE_GID))
chown -R "$HOST_TE_UID:$HOST_TE_GID" "$HOST_BASE"
# Add directory mappings
lxc config device add "$CONTAINER_NAME" tedata disk source="$HOST_DATA" path=/opt/gbo/data
lxc config device add "$CONTAINER_NAME" teconf disk source="$HOST_CONF" path=/opt/gbo/conf
lxc config device add "$CONTAINER_NAME" telogs disk source="$HOST_LOGS" path=/opt/gbo/logs
# Create systemd service
lxc exec "$CONTAINER_NAME" -- bash -c "
cat > /etc/systemd/system/table-editor.service <<EOF
[Unit]
Description=NocoDB Table Editor
After=network.target
[Service]
Type=simple
User=gbuser
Group=gbuser
WorkingDirectory=$BIN_PATH
Environment=PORT=${PARAM_TABLE_EDITOR_PORT}
Environment=DATABASE_URL=postgres://${PARAM_TABLES_USER}:${PARAM_TABLES_PASSWORD}@${PARAM_TABLES_HOST}:${PARAM_TABLES_PORT}/${PARAM_TABLE_EDITOR_DATABASE}
ExecStart=$BIN_PATH/nocodb
Restart=always
StandardOutput=append:/opt/gbo/logs/out.log
StandardError=append:/opt/gbo/logs/err.log
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable table-editor
systemctl start table-editor
"
# Expose the NocoDB port
lxc config device add "$CONTAINER_NAME" http proxy listen=tcp:0.0.0.0:$TABLE_EDITOR_PORT connect=tcp:127.0.0.1:$TABLE_EDITOR_PORT

View file

@ -1,50 +0,0 @@
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/tables"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
lxc launch images:debian/12 "$PARAM_TENANT"-tables -c security.privileged=true
until lxc exec "$PARAM_TENANT"-tables -- test -f /bin/bash; do
sleep 5
done
sleep 10
lxc exec "$PARAM_TENANT"-tables -- bash -c "
set -e
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y wget gnupg2 sudo lsb-release curl
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
apt install -y postgresql
# TODO: Open listener on *.
until sudo -u postgres psql -p $PARAM_TABLES_PORT -c '\q' 2>/dev/null; do
echo \"Waiting for PostgreSQL to start on port $PARAM_TABLES_PORT...\"
sleep 3
done
sudo -u postgres psql -p $PARAM_TABLES_PORT -c \"CREATE USER $PARAM_TENANT WITH PASSWORD '$PARAM_TABLES_PASSWORD';\"
sudo -u postgres psql -p $PARAM_TABLES_PORT -c \"CREATE DATABASE ${PARAM_TENANT}_db OWNER $PARAM_TENANT;\"
sudo -u postgres psql -p $PARAM_TABLES_PORT -c \"GRANT ALL PRIVILEGES ON DATABASE ${PARAM_TENANT}_db TO $PARAM_TENANT;\"
"
lxc config device remove "$PARAM_TENANT"-tables postgres-proxy 2>/dev/null || true
lxc config device add "$PARAM_TENANT"-tables postgres-proxy proxy \
listen=tcp:0.0.0.0:"$PARAM_TABLES_PORT" \
connect=tcp:127.0.0.1:"$PARAM_TABLES_PORT"
echo "PostgreSQL setup completed successfully!"
echo "Database: ${PARAM_TENANT}_db"
echo "User: $PARAM_TENANT"
echo "Password: $PARAM_TABLES_PASSWORD"
echo "Port: $PARAM_TABLES_PORT"

View file

@ -1,4 +0,0 @@
#!/bin/bash
wget https://github.com/qdrant/qdrant/releases/latest/download/qdrant-x86_64-unknown-linux-gnu.tar.gz
tar -xzf qdrant-x86_64-unknown-linux-gnu.tar.gz
./qdrant

View file

@ -1,103 +0,0 @@
#!/bin/bash
HOST_BASE="/opt/gbo/tenants/$PARAM_TENANT/webmail"
HOST_DATA="$HOST_BASE/data"
HOST_CONF="$HOST_BASE/conf"
HOST_LOGS="$HOST_BASE/logs"
PARAM_RC_VERSION="1.6.6"
mkdir -p "$HOST_DATA" "$HOST_CONF" "$HOST_LOGS"
chmod -R 750 "$HOST_BASE"
lxc launch images:debian/12 "$PARAM_TENANT"-webmail -c security.privileged=true
sleep 15
RC_PATH="/opt/gbo/data"
lxc exec "$PARAM_TENANT"-webmail -- bash -c '
# Install prerequisites
apt install -y ca-certificates apt-transport-https lsb-release gnupg wget
# Add the Sury PHP repository (official for Debian)
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
sh -c '\''echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'\''
# Update and install PHP 8.1
apt update
apt install -y \
php8.1 \
php8.1-fpm \
php8.1-imap \
php8.1-pgsql \
php8.1-mbstring \
php8.1-xml \
php8.1-curl \
php8.1-zip \
php8.1-cli \
php8.1-intl \
php8.1-dom
# Restart PHP-FPM
systemctl restart php8.1-fpm
mkdir -p '"$RC_PATH"'
wget -q https://github.com/roundcube/roundcubemail/releases/download/'"$PARAM_RC_VERSION"'/roundcubemail-'"$PARAM_RC_VERSION"'-complete.tar.gz
tar -xzf roundcubemail-*.tar.gz
mv roundcubemail-'"$PARAM_RC_VERSION"'/* '"$RC_PATH"'
rm -rf roundcubemail-*
mkdir -p /opt/gbo/logs
chmod 750 '"$RC_PATH"'
find '"$RC_PATH"' -type d -exec chmod 750 {} \;
find '"$RC_PATH"' -type f -exec chmod 640 {} \;
'
WEBMAIL_UID=$(lxc exec "$PARAM_TENANT"-webmail -- id -u www-data)
WEBMAIL_GID=$(lxc exec "$PARAM_TENANT"-webmail -- id -g www-data)
HOST_WEBMAIL_UID=$((100000 + WEBMAIL_UID))
HOST_WEBMAIL_GID=$((100000 + WEBMAIL_GID))
chown -R "$HOST_WEBMAIL_UID:$HOST_WEBMAIL_GID" "$HOST_BASE"
lxc config device add "$PARAM_TENANT"-webmail webmaildata disk source="$HOST_DATA" path="$RC_PATH"
lxc config device add "$PARAM_TENANT"-webmail webmaillogs disk source="$HOST_LOGS" path=/opt/gbo/logs
lxc exec "$PARAM_TENANT"-webmail -- bash -c "
chown -R www-data:www-data '"$RC_PATH"' /opt/gbo/logs
cat > /etc/systemd/system/webmail.service <<EOF
[Unit]
Description=Roundcube Webmail
After=network.target php8.1-fpm.service
[Service]
User=www-data
Group=www-data
WorkingDirectory=$RC_PATH
ExecStart=/usr/bin/php -S 0.0.0.0:$PARAM_WEBMAIL_PORT -t $RC_PATH/wwwroot/public_html
Restart=always
StandardOutput=append:/opt/gbo/logs/stdout.log
StandardError=append:/opt/gbo/logs/stderr.log
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable webmail
systemctl restart php8.1-fpm
systemctl start webmail
"
# Check if port is available before adding proxy
if lsof -i :$PARAM_WEBMAIL_PORT >/dev/null; then
echo "Port $PARAM_WEBMAIL_PORT is already in use. Please choose a different port."
exit 1
fi
lxc config device remove "$PARAM_TENANT"-webmail webmail-proxy 2>/dev/null || true
lxc config device add "$PARAM_TENANT"-webmail webmail-proxy proxy \
listen=tcp:0.0.0.0:"$PARAM_WEBMAIL_PORT" \
connect=tcp:127.0.0.1:"$PARAM_WEBMAIL_PORT"

View file

@ -1,14 +1,18 @@
use actix_web::{web, HttpResponse, Result};
use argon2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2,
};
use diesel::pg::PgConnection;
use diesel::prelude::*;
use log::{error, warn};
use redis::Client;
use std::collections::HashMap;
use std::sync::Arc;
use uuid::Uuid;
use crate::shared;
use crate::shared::state::AppState;
pub struct AuthService {
pub conn: PgConnection,
@ -141,3 +145,91 @@ impl AuthService {
Ok(user)
}
}
#[actix_web::get("/api/auth")]
async fn auth_handler(
data: web::Data<AppState>,
web::Query(params): web::Query<HashMap<String, String>>,
) -> Result<HttpResponse> {
let _token = params.get("token").cloned().unwrap_or_default();
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap();
let bot_id = if let Ok(bot_guid) = std::env::var("BOT_GUID") {
match Uuid::parse_str(&bot_guid) {
Ok(uuid) => uuid,
Err(e) => {
warn!("Invalid BOT_GUID from env: {}", e);
return Ok(HttpResponse::BadRequest()
.json(serde_json::json!({"error": "Invalid BOT_GUID"})));
}
}
} else {
warn!("BOT_GUID not set in environment, using nil UUID");
Uuid::nil()
};
let session = {
let mut sm = data.session_manager.lock().await;
match sm.get_or_create_user_session(user_id, bot_id, "Auth Session") {
Ok(Some(s)) => s,
Ok(None) => {
error!("Failed to create session");
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": "Failed to create session"})));
}
Err(e) => {
error!("Failed to create session: {}", e);
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})));
}
}
};
let session_id_clone = session.id.clone();
let auth_script_path = "./templates/annoucements.gbai/annoucements.gbdialog/auth.bas";
let auth_script = match std::fs::read_to_string(auth_script_path) {
Ok(content) => content,
Err(_) => r#"SET_USER "00000000-0000-0000-0000-000000000001""#.to_string(),
};
let script_service = crate::basic::ScriptService::new(Arc::clone(&data), session.clone());
match script_service
.compile(&auth_script)
.and_then(|ast| script_service.run(&ast))
{
Ok(result) => {
if result.to_string() == "false" {
error!("Auth script returned false, authentication failed");
return Ok(HttpResponse::Unauthorized()
.json(serde_json::json!({"error": "Authentication failed"})));
}
}
Err(e) => {
error!("Failed to run auth script: {}", e);
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": "Auth failed"})));
}
}
let session = {
let mut sm = data.session_manager.lock().await;
match sm.get_session_by_id(session_id_clone) {
Ok(Some(s)) => s,
Ok(None) => {
error!("Failed to retrieve session");
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": "Failed to retrieve session"})));
}
Err(e) => {
error!("Failed to retrieve session: {}", e);
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})));
}
}
};
Ok(HttpResponse::Ok().json(serde_json::json!({
"user_id": session.user_id,
"session_id": session.id,
"status": "authenticated"
})))
}

View file

@ -7,7 +7,6 @@ use chrono::Utc;
use log::{debug, error, info, warn};
use serde_json;
use std::collections::HashMap;
use std::fs;
use std::sync::Arc;
use tokio::sync::mpsc;
use uuid::Uuid;
@ -857,186 +856,6 @@ async fn websocket_handler(
Ok(res)
}
#[actix_web::get("/api/auth")]
async fn auth_handler(
data: web::Data<AppState>,
web::Query(params): web::Query<HashMap<String, String>>,
) -> Result<HttpResponse> {
let _token = params.get("token").cloned().unwrap_or_default();
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap();
let bot_id = if let Ok(bot_guid) = std::env::var("BOT_GUID") {
match Uuid::parse_str(&bot_guid) {
Ok(uuid) => uuid,
Err(e) => {
warn!("Invalid BOT_GUID from env: {}", e);
return Ok(HttpResponse::BadRequest()
.json(serde_json::json!({"error": "Invalid BOT_GUID"})));
}
}
} else {
warn!("BOT_GUID not set in environment, using nil UUID");
Uuid::nil()
};
let session = {
let mut sm = data.session_manager.lock().await;
match sm.get_or_create_user_session(user_id, bot_id, "Auth Session") {
Ok(Some(s)) => s,
Ok(None) => {
error!("Failed to create session");
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": "Failed to create session"})));
}
Err(e) => {
error!("Failed to create session: {}", e);
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})));
}
}
};
let session_id_clone = session.id.clone();
let auth_script_path = "./templates/annoucements.gbai/annoucements.gbdialog/auth.bas";
let auth_script = match std::fs::read_to_string(auth_script_path) {
Ok(content) => content,
Err(_) => r#"SET_USER "00000000-0000-0000-0000-000000000001""#.to_string(),
};
let script_service = crate::basic::ScriptService::new(Arc::clone(&data), session.clone());
match script_service
.compile(&auth_script)
.and_then(|ast| script_service.run(&ast))
{
Ok(result) => {
if result.to_string() == "false" {
error!("Auth script returned false, authentication failed");
return Ok(HttpResponse::Unauthorized()
.json(serde_json::json!({"error": "Authentication failed"})));
}
}
Err(e) => {
error!("Failed to run auth script: {}", e);
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": "Auth failed"})));
}
}
let session = {
let mut sm = data.session_manager.lock().await;
match sm.get_session_by_id(session_id_clone) {
Ok(Some(s)) => s,
Ok(None) => {
error!("Failed to retrieve session");
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": "Failed to retrieve session"})));
}
Err(e) => {
error!("Failed to retrieve session: {}", e);
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})));
}
}
};
Ok(HttpResponse::Ok().json(serde_json::json!({
"user_id": session.user_id,
"session_id": session.id,
"status": "authenticated"
})))
}
#[actix_web::get("/api/whatsapp/webhook")]
async fn whatsapp_webhook_verify(
data: web::Data<AppState>,
web::Query(params): web::Query<HashMap<String, String>>,
) -> Result<HttpResponse> {
let empty = String::new();
let mode = params.get("hub.mode").unwrap_or(&empty);
let token = params.get("hub.verify_token").unwrap_or(&empty);
let challenge = params.get("hub.challenge").unwrap_or(&empty);
info!(
"Verification params - mode: {}, token: {}, challenge: {}",
mode, token, challenge
);
match data.whatsapp_adapter.verify_webhook(mode, token, challenge) {
Ok(challenge_response) => Ok(HttpResponse::Ok().body(challenge_response)),
Err(_) => {
warn!("WhatsApp webhook verification failed");
Ok(HttpResponse::Forbidden().body("Verification failed"))
}
}
}
#[actix_web::post("/api/voice/start")]
async fn voice_start(
data: web::Data<AppState>,
info: web::Json<serde_json::Value>,
) -> Result<HttpResponse> {
let session_id = info
.get("session_id")
.and_then(|s| s.as_str())
.unwrap_or("");
let user_id = info
.get("user_id")
.and_then(|u| u.as_str())
.unwrap_or("user");
info!(
"Voice session start request - session: {}, user: {}",
session_id, user_id
);
match data
.voice_adapter
.start_voice_session(session_id, user_id)
.await
{
Ok(token) => {
info!(
"Voice session started successfully for session {}",
session_id
);
Ok(HttpResponse::Ok().json(serde_json::json!({"token": token, "status": "started"})))
}
Err(e) => {
error!(
"Failed to start voice session for session {}: {}",
session_id, e
);
Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})))
}
}
}
#[actix_web::post("/api/voice/stop")]
async fn voice_stop(
data: web::Data<AppState>,
info: web::Json<serde_json::Value>,
) -> Result<HttpResponse> {
let session_id = info
.get("session_id")
.and_then(|s| s.as_str())
.unwrap_or("");
match data.voice_adapter.stop_voice_session(session_id).await {
Ok(()) => {
info!(
"Voice session stopped successfully for session {}",
session_id
);
Ok(HttpResponse::Ok().json(serde_json::json!({"status": "stopped"})))
}
Err(e) => {
error!(
"Failed to stop voice session for session {}: {}",
session_id, e
);
Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})))
}
}
}
#[actix_web::post("/api/start")]
async fn start_session(
data: web::Data<AppState>,
@ -1110,130 +929,6 @@ async fn start_session(
}
}
#[actix_web::post("/api/sessions")]
async fn create_session(data: web::Data<AppState>) -> Result<HttpResponse> {
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
let bot_id = if let Ok(bot_guid) = std::env::var("BOT_GUID") {
match Uuid::parse_str(&bot_guid) {
Ok(uuid) => uuid,
Err(e) => {
warn!("Invalid BOT_GUID from env: {}", e);
return Ok(HttpResponse::BadRequest()
.json(serde_json::json!({"error": "Invalid BOT_GUID"})));
}
}
} else {
warn!("BOT_GUID not set in environment, using nil UUID");
Uuid::nil()
};
let session = {
let mut session_manager = data.session_manager.lock().await;
match session_manager.get_or_create_user_session(user_id, bot_id, "New Conversation") {
Ok(Some(s)) => s,
Ok(None) => {
error!("Failed to create session");
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": "Failed to create session"})));
}
Err(e) => {
error!("Failed to create session: {}", e);
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})));
}
}
};
Ok(HttpResponse::Ok().json(serde_json::json!({
"session_id": session.id,
"title": "New Conversation",
"created_at": Utc::now()
})))
}
#[actix_web::get("/api/sessions")]
async fn get_sessions(data: web::Data<AppState>) -> Result<HttpResponse> {
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
match orchestrator.get_user_sessions(user_id).await {
Ok(sessions) => Ok(HttpResponse::Ok().json(sessions)),
Err(e) => {
error!("Failed to get sessions: {}", e);
Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})))
}
}
}
#[actix_web::get("/api/sessions/{session_id}")]
async fn get_session_history(
data: web::Data<AppState>,
path: web::Path<String>,
) -> Result<HttpResponse> {
let session_id = path.into_inner();
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
match Uuid::parse_str(&session_id) {
Ok(session_uuid) => {
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
match orchestrator
.get_conversation_history(session_uuid, user_id)
.await
{
Ok(history) => {
info!(
"Retrieved {} history entries for session {}",
history.len(),
session_id
);
Ok(HttpResponse::Ok().json(history))
}
Err(e) => {
error!("Failed to get session history for {}: {}", session_id, e);
Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})))
}
}
}
Err(_) => {
warn!("Invalid session ID format: {}", session_id);
Ok(HttpResponse::BadRequest().json(serde_json::json!({"error": "Invalid session ID"})))
}
}
}
#[actix_web::post("/api/set_mode")]
async fn set_mode_handler(
data: web::Data<AppState>,
info: web::Json<HashMap<String, String>>,
) -> Result<HttpResponse> {
let default_user = "default_user".to_string();
let default_bot = "default_bot".to_string();
let default_mode = "0".to_string();
let user_id = info.get("user_id").unwrap_or(&default_user);
let bot_id = info.get("bot_id").unwrap_or(&default_bot);
let mode_str = info.get("mode").unwrap_or(&default_mode);
let mode = mode_str.parse::<i32>().unwrap_or(0);
info!(
"Setting mode - user: {}, bot: {}, mode: {}",
user_id, bot_id, mode
);
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
if let Err(e) = orchestrator
.set_user_answer_mode(user_id, bot_id, mode)
.await
{
error!("Failed to set answer mode: {}", e);
return Ok(
HttpResponse::InternalServerError().json(serde_json::json!({"error": e.to_string()}))
);
}
Ok(HttpResponse::Ok().json(serde_json::json!({"status": "mode_updated"})))
}
#[actix_web::post("/api/warn")]
async fn send_warning_handler(
data: web::Data<AppState>,
@ -1264,41 +959,3 @@ async fn send_warning_handler(
Ok(HttpResponse::Ok().json(serde_json::json!({"status": "warning_sent"})))
}
#[actix_web::get("/")]
async fn index() -> Result<HttpResponse> {
match fs::read_to_string("web/index.html") {
Ok(html) => Ok(HttpResponse::Ok().content_type("text/html").body(html)),
Err(e) => {
error!("Failed to load index page: {}", e);
Ok(HttpResponse::InternalServerError().body("Failed to load index page"))
}
}
}
#[actix_web::get("/static/{filename:.*}")]
async fn static_files(req: HttpRequest) -> Result<HttpResponse> {
let filename = req.match_info().query("filename");
let path = format!("web/static/{}", filename);
match fs::read(&path) {
Ok(content) => {
debug!(
"Static file {} loaded successfully, size: {} bytes",
filename,
content.len()
);
let content_type = match filename {
f if f.ends_with(".js") => "application/javascript",
f if f.ends_with(".css") => "text/css",
f if f.ends_with(".png") => "image/png",
f if f.ends_with(".jpg") | f.ends_with(".jpeg") => "image/jpeg",
_ => "text/plain",
};
Ok(HttpResponse::Ok().content_type(content_type).body(content))
}
Err(e) => {
warn!("Static file not found: {} - {}", filename, e);
Ok(HttpResponse::NotFound().body("File not found"))
}
}
}

View file

@ -18,18 +18,17 @@ mod email;
mod file;
mod llm;
mod llm_legacy;
mod meet;
mod org;
mod package_manager;
mod session;
mod shared;
mod tools;
mod web_server;
mod whatsapp;
use crate::auth::auth_handler;
use crate::automation::AutomationService;
use crate::bot::{
auth_handler, create_session, get_session_history, get_sessions, index, set_mode_handler,
start_session, static_files, voice_start, voice_stop, websocket_handler,
whatsapp_webhook_verify,
};
use crate::bot::{start_session, websocket_handler};
use crate::channels::{VoiceAdapter, WebChannelAdapter};
use crate::config::AppConfig;
#[cfg(feature = "email")]
@ -40,7 +39,11 @@ use crate::file::{init_drive, upload_file};
use crate::llm_legacy::llm_local::{
chat_completions_local, embeddings_local, ensure_llama_servers_running,
};
use crate::meet::{voice_start, voice_stop};
use crate::session::{create_session, get_session_history, get_sessions};
use crate::shared::state::AppState;
use crate::web_server::{index, static_files};
use crate::whatsapp::whatsapp_webhook_verify;
use crate::whatsapp::WhatsAppAdapter;
#[actix_web::main]
@ -269,7 +272,6 @@ async fn main() -> std::io::Result<()> {
.service(get_sessions)
.service(start_session)
.service(get_session_history)
.service(set_mode_handler)
.service(chat_completions_local)
.service(embeddings_local);

View file

@ -1,4 +1,7 @@
use crate::bot::BotOrchestrator;
use crate::shared::models::UserSession;
use crate::shared::state::AppState;
use actix_web::{web, HttpResponse, Result};
use chrono::Utc;
use diesel::prelude::*;
use diesel::PgConnection;
@ -333,3 +336,95 @@ impl SessionManager {
Ok(())
}
}
#[actix_web::post("/api/sessions")]
async fn create_session(data: web::Data<AppState>) -> Result<HttpResponse> {
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
let bot_id = if let Ok(bot_guid) = std::env::var("BOT_GUID") {
match Uuid::parse_str(&bot_guid) {
Ok(uuid) => uuid,
Err(e) => {
warn!("Invalid BOT_GUID from env: {}", e);
return Ok(HttpResponse::BadRequest()
.json(serde_json::json!({"error": "Invalid BOT_GUID"})));
}
}
} else {
warn!("BOT_GUID not set in environment, using nil UUID");
Uuid::nil()
};
let session = {
let mut session_manager = data.session_manager.lock().await;
match session_manager.get_or_create_user_session(user_id, bot_id, "New Conversation") {
Ok(Some(s)) => s,
Ok(None) => {
error!("Failed to create session");
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": "Failed to create session"})));
}
Err(e) => {
error!("Failed to create session: {}", e);
return Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})));
}
}
};
Ok(HttpResponse::Ok().json(serde_json::json!({
"session_id": session.id,
"title": "New Conversation",
"created_at": Utc::now()
})))
}
#[actix_web::get("/api/sessions")]
async fn get_sessions(data: web::Data<AppState>) -> Result<HttpResponse> {
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
match orchestrator.get_user_sessions(user_id).await {
Ok(sessions) => Ok(HttpResponse::Ok().json(sessions)),
Err(e) => {
error!("Failed to get sessions: {}", e);
Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})))
}
}
}
#[actix_web::get("/api/sessions/{session_id}")]
async fn get_session_history(
data: web::Data<AppState>,
path: web::Path<String>,
) -> Result<HttpResponse> {
let session_id = path.into_inner();
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
match Uuid::parse_str(&session_id) {
Ok(session_uuid) => {
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
match orchestrator
.get_conversation_history(session_uuid, user_id)
.await
{
Ok(history) => {
info!(
"Retrieved {} history entries for session {}",
history.len(),
session_id
);
Ok(HttpResponse::Ok().json(history))
}
Err(e) => {
error!("Failed to get session history for {}: {}", session_id, e);
Ok(HttpResponse::InternalServerError()
.json(serde_json::json!({"error": e.to_string()})))
}
}
}
Err(_) => {
warn!("Invalid session ID format: {}", session_id);
Ok(HttpResponse::BadRequest().json(serde_json::json!({"error": "Invalid session ID"})))
}
}
}

View file

@ -1,5 +1,6 @@
use actix_web::{web, HttpResponse, Result};
use async_trait::async_trait;
use log::info;
use log::{info, warn};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
@ -7,6 +8,7 @@ use std::sync::Arc;
use tokio::sync::Mutex;
use crate::shared::models::BotResponse;
use crate::shared::state::AppState;
#[derive(Debug, Deserialize)]
pub struct WhatsAppMessage {
@ -198,3 +200,26 @@ impl crate::channels::ChannelAdapter for WhatsAppAdapter {
.await
}
}
#[actix_web::get("/api/whatsapp/webhook")]
async fn whatsapp_webhook_verify(
data: web::Data<AppState>,
web::Query(params): web::Query<HashMap<String, String>>,
) -> Result<HttpResponse> {
let empty = String::new();
let mode = params.get("hub.mode").unwrap_or(&empty);
let token = params.get("hub.verify_token").unwrap_or(&empty);
let challenge = params.get("hub.challenge").unwrap_or(&empty);
info!(
"Verification params - mode: {}, token: {}, challenge: {}",
mode, token, challenge
);
match data.whatsapp_adapter.verify_webhook(mode, token, challenge) {
Ok(challenge_response) => Ok(HttpResponse::Ok().body(challenge_response)),
Err(_) => {
warn!("WhatsApp webhook verification failed");
Ok(HttpResponse::Forbidden().body("Verification failed"))
}
}
}

View file

@ -4,4 +4,4 @@ TALK resume
let text = GET "default.gbdrive/default.pdf"
SET_CONTEXT "Este é o documento que você deve usar para responder dúvidas: " + text
TALK "Olá, pode me perguntar sobre qualquer coisa desta circular..."
TALK "Olá, pode me perguntar sobre qualquer coisa destas circulares..."