- Refactor in bot package.
This commit is contained in:
parent
79ac6df738
commit
be1e2575f9
27 changed files with 233 additions and 1663 deletions
37
add-req.sh
37
add-req.sh
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
PROJECT_ROOT="$SCRIPT_DIR"
|
PROJECT_ROOT="$SCRIPT_DIR"
|
||||||
OUTPUT_FILE="$SCRIPT_DIR/prompt.out"
|
OUTPUT_FILE="/tmp/prompt.out"
|
||||||
|
|
||||||
rm -f "$OUTPUT_FILE"
|
rm -f "$OUTPUT_FILE"
|
||||||
echo "Consolidated LLM Context" > "$OUTPUT_FILE"
|
echo "Consolidated LLM Context" > "$OUTPUT_FILE"
|
||||||
|
|
@ -10,7 +10,6 @@ echo "Consolidated LLM Context" > "$OUTPUT_FILE"
|
||||||
prompts=(
|
prompts=(
|
||||||
"./prompts/dev/shared.md"
|
"./prompts/dev/shared.md"
|
||||||
"./Cargo.toml"
|
"./Cargo.toml"
|
||||||
"./prompts/dev/generation.md"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for file in "${prompts[@]}"; do
|
for file in "${prompts[@]}"; do
|
||||||
|
|
@ -24,19 +23,19 @@ dirs=(
|
||||||
#"auth"
|
#"auth"
|
||||||
#"automation"
|
#"automation"
|
||||||
#"basic"
|
#"basic"
|
||||||
#"bot"
|
"bot"
|
||||||
#"channels"
|
#"channels"
|
||||||
"config"
|
"config"
|
||||||
#"context"
|
"context"
|
||||||
#"email"
|
#"email"
|
||||||
#"file"
|
"file"
|
||||||
#"llm"
|
"llm"
|
||||||
#"llm_legacy"
|
#"llm_legacy"
|
||||||
#"org"
|
#"org"
|
||||||
"session"
|
"session"
|
||||||
"shared"
|
"shared"
|
||||||
#"tests"
|
#"tests"
|
||||||
#"tools"
|
"tools"
|
||||||
#"web_automation"
|
#"web_automation"
|
||||||
#"whatsapp"
|
#"whatsapp"
|
||||||
)
|
)
|
||||||
|
|
@ -59,25 +58,10 @@ done
|
||||||
# Additional specific files
|
# Additional specific files
|
||||||
files=(
|
files=(
|
||||||
"$PROJECT_ROOT/src/main.rs"
|
"$PROJECT_ROOT/src/main.rs"
|
||||||
"$PROJECT_ROOT/scripts/containers/proxy.sh"
|
"$PROJECT_ROOT/src/basic/keywords/mod.rs"
|
||||||
"$PROJECT_ROOT/scripts/containers/directory.sh"
|
"$PROJECT_ROOT/src/basic/keywords/get.rs"
|
||||||
"$PROJECT_ROOT/scripts/containers/bot.sh"
|
"$PROJECT_ROOT/src/basic/keywords/find.rs"
|
||||||
"$PROJECT_ROOT/scripts/containers/system.sh"
|
"$PROJECT_ROOT/src/basic/keywords/hear_talk.rs"
|
||||||
"$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"
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -108,3 +92,4 @@ echo "Context size: $FILE_SIZE bytes"
|
||||||
|
|
||||||
cat "$OUTPUT_FILE" | xclip -selection clipboard
|
cat "$OUTPUT_FILE" | xclip -selection clipboard
|
||||||
echo "Content copied to clipboard (xclip)"
|
echo "Content copied to clipboard (xclip)"
|
||||||
|
rm -f "$OUTPUT_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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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}"
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
https://www.brasil247.com/mundo/meta-quer-automatizar-totalmente-publicidade-com-ia-ate-2026-diz-wsj
|
|
||||||
|
|
@ -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}"
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
|
use actix_web::{web, HttpResponse, Result};
|
||||||
use argon2::{
|
use argon2::{
|
||||||
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
|
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
|
||||||
Argon2,
|
Argon2,
|
||||||
};
|
};
|
||||||
use diesel::pg::PgConnection;
|
use diesel::pg::PgConnection;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
use log::{error, warn};
|
||||||
use redis::Client;
|
use redis::Client;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::shared;
|
use crate::shared;
|
||||||
|
use crate::shared::state::AppState;
|
||||||
|
|
||||||
pub struct AuthService {
|
pub struct AuthService {
|
||||||
pub conn: PgConnection,
|
pub conn: PgConnection,
|
||||||
|
|
@ -141,3 +145,91 @@ impl AuthService {
|
||||||
Ok(user)
|
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"
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
|
||||||
343
src/bot/mod.rs
343
src/bot/mod.rs
|
|
@ -7,7 +7,6 @@ use chrono::Utc;
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
@ -857,186 +856,6 @@ async fn websocket_handler(
|
||||||
Ok(res)
|
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")]
|
#[actix_web::post("/api/start")]
|
||||||
async fn start_session(
|
async fn start_session(
|
||||||
data: web::Data<AppState>,
|
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")]
|
#[actix_web::post("/api/warn")]
|
||||||
async fn send_warning_handler(
|
async fn send_warning_handler(
|
||||||
data: web::Data<AppState>,
|
data: web::Data<AppState>,
|
||||||
|
|
@ -1264,41 +959,3 @@ async fn send_warning_handler(
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(serde_json::json!({"status": "warning_sent"})))
|
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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
14
src/main.rs
14
src/main.rs
|
|
@ -18,18 +18,17 @@ mod email;
|
||||||
mod file;
|
mod file;
|
||||||
mod llm;
|
mod llm;
|
||||||
mod llm_legacy;
|
mod llm_legacy;
|
||||||
|
mod meet;
|
||||||
mod org;
|
mod org;
|
||||||
mod package_manager;
|
mod package_manager;
|
||||||
mod session;
|
mod session;
|
||||||
mod shared;
|
mod shared;
|
||||||
mod tools;
|
mod tools;
|
||||||
|
mod web_server;
|
||||||
mod whatsapp;
|
mod whatsapp;
|
||||||
|
use crate::auth::auth_handler;
|
||||||
use crate::automation::AutomationService;
|
use crate::automation::AutomationService;
|
||||||
use crate::bot::{
|
use crate::bot::{start_session, websocket_handler};
|
||||||
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::channels::{VoiceAdapter, WebChannelAdapter};
|
use crate::channels::{VoiceAdapter, WebChannelAdapter};
|
||||||
use crate::config::AppConfig;
|
use crate::config::AppConfig;
|
||||||
#[cfg(feature = "email")]
|
#[cfg(feature = "email")]
|
||||||
|
|
@ -40,7 +39,11 @@ use crate::file::{init_drive, upload_file};
|
||||||
use crate::llm_legacy::llm_local::{
|
use crate::llm_legacy::llm_local::{
|
||||||
chat_completions_local, embeddings_local, ensure_llama_servers_running,
|
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::shared::state::AppState;
|
||||||
|
use crate::web_server::{index, static_files};
|
||||||
|
use crate::whatsapp::whatsapp_webhook_verify;
|
||||||
use crate::whatsapp::WhatsAppAdapter;
|
use crate::whatsapp::WhatsAppAdapter;
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
|
|
@ -269,7 +272,6 @@ async fn main() -> std::io::Result<()> {
|
||||||
.service(get_sessions)
|
.service(get_sessions)
|
||||||
.service(start_session)
|
.service(start_session)
|
||||||
.service(get_session_history)
|
.service(get_session_history)
|
||||||
.service(set_mode_handler)
|
|
||||||
.service(chat_completions_local)
|
.service(chat_completions_local)
|
||||||
.service(embeddings_local);
|
.service(embeddings_local);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
|
use crate::bot::BotOrchestrator;
|
||||||
use crate::shared::models::UserSession;
|
use crate::shared::models::UserSession;
|
||||||
|
use crate::shared::state::AppState;
|
||||||
|
use actix_web::{web, HttpResponse, Result};
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel::PgConnection;
|
use diesel::PgConnection;
|
||||||
|
|
@ -333,3 +336,95 @@ impl SessionManager {
|
||||||
Ok(())
|
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"})))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
use actix_web::{web, HttpResponse, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use log::info;
|
use log::{info, warn};
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -7,6 +8,7 @@ use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::shared::models::BotResponse;
|
use crate::shared::models::BotResponse;
|
||||||
|
use crate::shared::state::AppState;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct WhatsAppMessage {
|
pub struct WhatsAppMessage {
|
||||||
|
|
@ -198,3 +200,26 @@ impl crate::channels::ChannelAdapter for WhatsAppAdapter {
|
||||||
.await
|
.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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ TALK resume
|
||||||
|
|
||||||
let text = GET "default.gbdrive/default.pdf"
|
let text = GET "default.gbdrive/default.pdf"
|
||||||
SET_CONTEXT "Este é o documento que você deve usar para responder dúvidas: " + text
|
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..."
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue