Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .air.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#:schema https://json.schemastore.org/any.json

env_files = []
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ./cmd/red"
delay = 1000
entrypoint = ["./tmp/main"]
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
ignore_dangerous_root_dir = false
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false

[build.windows]
args_bin = []
bin = "tmp\\main.exe"
cmd = "go build -o ./tmp/main.exe ./cmd/red"
entrypoint = ["tmp\\main.exe"]
full_bin = ""
post_cmd = []
pre_cmd = []

[color]
app = ""
build = "yellow"
main = "magenta"
mode = ""
runner = "green"
watcher = "cyan"

[log]
main_only = false
silent = false
time = false

[misc]
clean_on_exit = false

[proxy]
app_port = 0
app_start_timeout = 0
enabled = false
proxy_port = 0

[screen]
clear_on_rebuild = false
keep_scroll = true
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ Thumbs.db

.vscode/
.idea/

# remove py venv
venv-podman

tmp
40 changes: 23 additions & 17 deletions cmd/red/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ func main() {
cfg = loaded
}

// --- NEW: Security Token Warning ---
if cfg.AdminToken == "" || cfg.AdminToken == "secret123" {
log.Println("=================================================================")
log.Println("⚠️ SECURITY WARNING: Using default or missing Admin Token! ⚠️")
Expand All @@ -41,7 +40,6 @@ func main() {
log.Println("Windows: .\\manage-token.ps1")
log.Println("=================================================================")
}
// -----------------------------------

// 1. Core Knowledge Base Pulling
if *pull && cfg.SourceURL != "" {
Expand All @@ -52,11 +50,11 @@ func main() {
log.Println("fetch complete")
}

// 2. Startup Sync (Ported from Legacy Gateway)
// 2. Startup Sync
if len(cfg.StartupSync) > 0 {
// Calculate the absolute path based on the config (e.g., /app/data/remote)
remoteDir := filepath.Join(cfg.DataDir, "remote")

// Check for permission errors right here before proceeding
if err := os.MkdirAll(remoteDir, 0755); err != nil {
log.Fatalf("CRITICAL: Failed to create remote directory. Check volume permissions: %v", err)
}
Expand All @@ -65,7 +63,16 @@ func main() {

for _, sync := range cfg.StartupSync {
log.Printf("Startup Sync: Fetching %s...", sync.Filename)
if err := executeSync(client, sync.URL, filepath.Join(remoteDir, sync.Filename)); err != nil {

// Auto-convert awesome-markdown shortcut to raw GitHub URL
downloadURL := sync.URL
if downloadURL == "https://github.com/mundimark/awesome-markdown" {
downloadURL = "https://raw.githubusercontent.com/mundimark/awesome-markdown/master/README.md"
}

// Pass the absolute target path directly to avoid double-appending "data"
targetPath := filepath.Join(remoteDir, sync.Filename)
if err := executeSync(client, downloadURL, targetPath); err != nil {
log.Printf("Startup Sync Error (%s): %v", sync.Filename, err)
} else {
log.Printf("Startup Sync: Successfully downloaded %s", sync.Filename)
Expand All @@ -79,29 +86,28 @@ func main() {
log.Fatalf("store: %v", err)
}

// 4. Start HTTP Server with the Refactored Router
// Start Hot Reload Watcher
if err := s.Watch(); err != nil {
log.Printf("⚠️ Warning: Could not start hot reloader: %v", err)
}

// 4. Start HTTP Server
h := router.New(s, &cfg, *cfgPath)
log.Printf("RED listening on %s", cfg.Addr)
log.Fatal(http.ListenAndServe(cfg.Addr, h))
}

func executeSync(client *http.Client, targetURL, destSubPath string) error {
// Reconstruct target file paths relative to data root directory
// Note: main.go has context of cfg.DataDir

// Let's resolve the path correctly depending on the initialization parameters
func executeSync(client *http.Client, targetURL, destPath string) error {
lowerURL := strings.ToLower(targetURL)

if strings.HasSuffix(lowerURL, ".tar.gz") || strings.HasSuffix(lowerURL, ".zip") {
srcType := "tar.gz"
if strings.HasSuffix(lowerURL, ".zip") {
srcType = "zip"
}
// Pull the dynamic folder contents using the internal archive worker
return fetch.Pull(targetURL, srcType, filepath.Join("data", destSubPath))
return fetch.Pull(targetURL, srcType, destPath)
}

// Otherwise, proceed with single file retrieval flow
req, err := http.NewRequest(http.MethodGet, targetURL, nil)
if err != nil {
return err
Expand All @@ -118,12 +124,12 @@ func executeSync(client *http.Client, targetURL, destSubPath string) error {
return os.ErrPermission
}

fullFilePath := filepath.Join("data", destSubPath)
if err := os.MkdirAll(filepath.Dir(fullFilePath), 0755); err != nil {
// Use destPath exactly as provided, removing the hardcoded "data" string
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
return err
}

outFile, err := os.Create(fullFilePath)
outFile, err := os.Create(destPath)
if err != nil {
return err
}
Expand Down
5 changes: 3 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ networks:

services:
red_engine:
build: .
image: red-engine-image
container_name: red_engine_node
restart: unless-stopped
Expand All @@ -20,8 +21,8 @@ services:
container_name: caddy_proxy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8080:80"
- "8443:443"
networks:
- clearnet-tier
volumes:
Expand Down
13 changes: 10 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ module github.com/RED-Collective/red-engine

go 1.26.2

require github.com/yuin/goldmark v1.8.2
require (
github.com/microcosm-cc/bluemonday v1.0.27
github.com/yuin/goldmark v1.8.2
)

require (
github.com/fsnotify/fsnotify v1.10.1 // direct
golang.org/x/sys v0.45.0 // indirect
)

require (
github.com/aymerick/douceur v0.2.0 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/microcosm-cc/bluemonday v1.0.27 // direct
golang.org/x/net v0.26.0 // indirect
golang.org/x/net v0.55.0 // indirect
)
8 changes: 6 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE=
github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
2 changes: 1 addition & 1 deletion install-red-engine.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "🚀 Installing RED Engine..." -ForegroundColor Cyan
Write-Host "🚀 Installing RED Engine (Production Mode)..." -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan

if (-Not (Test-Path "docker-compose.yml")) {
Expand Down
42 changes: 3 additions & 39 deletions install-red-engine.sh
Original file line number Diff line number Diff line change
@@ -1,27 +1,12 @@
#!/bin/bash
echo "========================================"
echo "🚀 Installing RED Engine..."
echo "🚀 Installing RED Engine (Production Mode)..."
echo "========================================"

if [ ! -f "docker-compose.yml" ]; then
echo "[*] Repository not detected in current directory."

if ! command -v git &> /dev/null; then
echo "❌ Error: 'git' is not installed. Please install git to continue."
exit 1
fi

echo "[*] Cloning RED Engine repository..."
git clone https://github.com/RED-Collective/red-engine.git
if [ $? -ne 0 ]; then
echo "❌ Error: Failed to clone repository."
exit 1
fi

echo "[*] Navigating into red-engine directory..."
cd red-engine || exit 1
else
echo "[*] Running from inside existing repository."
fi

if [ ! -d "./data" ]; then
Expand All @@ -34,7 +19,6 @@ fi
if [ ! -f "config.json" ]; then
echo "[*] Generating default config.json..."
NEW_TOKEN=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 24 | head -n 1)

cat <<EOF > config.json
{
"addr": ":8080",
Expand All @@ -44,19 +28,16 @@ if [ ! -f "config.json" ]; then
"startupSync": []
}
EOF
echo "[*] Generated secure Admin Token: $NEW_TOKEN"
echo "⚠️ PLEASE SAVE THIS TOKEN! You will need it to log in to the admin panel."
else
echo "[*] config.json already exists. Skipping default generation."
echo "[*] Generated Admin Token: $NEW_TOKEN"
fi

if [ ! -f "contributors.json" ]; then
echo "[*] Generating default contributors.json..."
echo "[]" > contributors.json
else
echo "[*] contributors.json already exists."
fi

# 5. Detect the container engine
if command -v podman-compose &> /dev/null; then
COMPOSE_CMD="podman-compose up --build -d"
elif command -v docker-compose &> /dev/null; then
Expand All @@ -72,23 +53,6 @@ fi
echo "[*] Starting RED Engine using container engine..."
$COMPOSE_CMD

if [ $? -ne 0 ]; then
echo "❌ Error: Failed to start containers."
exit 1
fi

CONFIG_PORT=$(grep '"addr"' config.json | sed -E 's/.*:([0-9]+).*/\1/')

if [ -z "$CONFIG_PORT" ]; then
CONFIG_PORT="8080"
fi

HOST_IP="localhost"
if command -v hostname &> /dev/null; then
HOST_IP=$(hostname -I | awk '{print $1}')
[ -z "$HOST_IP" ] && HOST_IP="localhost"
fi

echo "========================================"
echo "✅ Installation Complete!"
echo "🌐 Your node is running at: http://${HOST_IP}:${CONFIG_PORT}"
Expand Down
3 changes: 3 additions & 0 deletions internal/router/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# For tailwind

node_modules
Loading
Loading