WIP: Fixing installer

This commit is contained in:
John Haverlack 2026-07-04 18:31:26 -08:00
parent 198637a407
commit 6065d1db3f
17 changed files with 372 additions and 524 deletions

View File

@ -1,81 +1,11 @@
{ {
"releases": [ "releases": [
{ {
"version": "0.3.10", "version": "0.1.0",
"date": "2026-02-08", "date": "2026-06-28",
"maturity": "ALPHA", "maturity": "INIT",
"summary": "", "summary": "",
"notes": "" "notes": ""
},
{
"version": "0.3.9",
"date": "2026-02-08",
"maturity": "ALPHA",
"summary": "",
"notes": ""
},
{
"version": "0.3.8",
"date": "2026-02-01",
"maturity": "ALPHA",
"summary": "",
"notes": ""
},
{
"version": "0.3.7",
"date": "2026-02-01",
"maturity": "ALPHA",
"summary": "sdl-wkr Telemetry",
"notes": ""
},
{
"version": "0.3.6",
"date": "2026-02-01",
"maturity": "ALPHA",
"summary": "Light/Dark Mode, Wkr Install, Cluster Stats",
"notes": ""
},
{
"version": "0.3.5",
"date": "2026-02-01",
"maturity": "ALPHA",
"summary": "",
"notes": ""
},
{
"version": "0.3.4",
"date": "2026-01-31",
"maturity": "ALPHA",
"summary": "",
"notes": ""
},
{
"version": "0.3.3",
"date": "2026-01-31",
"maturity": "ALPHA",
"summary": "",
"notes": ""
},
{
"version": "0.3.2",
"date": "2026-01-31",
"maturity": "ALPHA",
"summary": "",
"notes": ""
},
{
"version": "0.3.1",
"date": "2026-01-31",
"maturity": "ALPHA",
"summary": "README Cleanup",
"notes": ""
},
{
"version": "0.3.0",
"date": "2026-01-31",
"maturity": "ALPHA",
"summary": "Initial Codebase",
"notes": "Initial GitHub Release"
} }
] ]
} }

View File

@ -1,21 +0,0 @@
{
"name": "Project Name",
"desc": "Project Description",
"parameters" : {
"parm1": {
"name": "Parameter Name",
"desc": "Parameter Description",
"type": "integer",
"min": 0,
"max": 100
},
"parm2": {
"name": "Parameter Name",
"desc": "Parameter Description",
"type": "integer",
"min": 0,
"max": 100
}
},
"iterations": 1000
}

View File

@ -1,31 +0,0 @@
{
"id": "nks-ca",
"name": "NKS 1D CA",
"desc": "Exploration of 1D elementary New Kind of Science (NKS) Cellular Automata (CA)",
"date": "2026-02-09",
"version": "0.0.0",
"parameters" : {
"x": {
"name": "X Cells",
"desc": "Number of Binary Cells on the X Dimension",
"type": "integer",
"min": 3,
"max": 15
},
"rule": {
"name": "Rule",
"desc": "Update Rule Index",
"type": "integer",
"min": 0,
"max": 255
},
"init": {
"name": "Initial State",
"desc": "Initial Binary State",
"type": "integer",
"min": 0,
"max": "2^x"
}
},
"iterations": 100
}

View File

@ -1,34 +0,0 @@
{
"id": "ssl-evo-rnd",
"name": "SSL Random Evolution",
"desc": "State Space Locality (SSL) Random Perturbation Evolution Update Rule",
"date": "2026-02-09",
"version": "0.0.0",
"parameters" : {
"N": {
"name": "Nodes",
"desc": "N Node Directional Graph",
"type": "integer",
"min": 1,
"max": 1000
},
"rule": {
"name": "Rule",
"desc": "Proximity Update Rule",
"type": "text",
"eunum": [
"Pii",
"Poo",
"Pio",
"Poi"
]
},
"init": {
"name": "Initial State",
"desc": "NxN Adjacency Matrix",
"type": "matrix"
}
},
"iterations": 1000,
"permutations": {}
}

View File

@ -14,12 +14,12 @@ resolve_dirs() {
raw["$key"]="$val" raw["$key"]="$val"
done < <(jq -r '.DIRS | to_entries[] | "\(.key)=\(.value)"' "$json") done < <(jq -r '.DIRS | to_entries[] | "\(.key)=\(.value)"' "$json")
if [[ -z "${raw[HOME]:-}" ]]; then if [[ -z "${raw[SITE]:-}" ]]; then
echo "ERROR: DIRS.HOME is not defined in config.json" echo "ERROR: DIRS.SITE is not defined in nwa-deploy-config.json"
exit 1 exit 1
fi fi
resolved["HOME"]="${raw[HOME]/#\~/$HOME}" resolved["SITE"]="${raw[SITE]/#\~/$HOME}"
local changed=true local changed=true
while $changed; do while $changed; do
@ -32,7 +32,21 @@ resolve_dirs() {
val="${val/$rkey/${resolved[$rkey]:-}}" val="${val/$rkey/${resolved[$rkey]:-}}"
done done
if [[ "$val" != ** ]]; then # if [[ "$val" != ** ]]; then
# resolved["$key"]="$val"
# changed=true
# fi
local unresolved=false
for unresolved_key in "${!raw[@]}"; do
if [[ -z "${resolved[$unresolved_key]:-}" && "$val" == *"$unresolved_key"* ]]; then
unresolved=true
break
fi
done
if [[ "$unresolved" == false ]]; then
resolved["$key"]="$val" resolved["$key"]="$val"
changed=true changed=true
fi fi
@ -61,6 +75,93 @@ use_systemd() {
return 1 # Use manual scripts return 1 # Use manual scripts
} }
install_nodejs() {
NODE_TARGET="${OS_PLATFORM}:${OS_ARCH}"
NODE_PLATFORM="${OS_PLATFORM}-${OS_ARCH}"
echo ""
echo "Target NodeJS:"
echo " Target: $NODE_TARGET"
echo " Platform: $NODE_PLATFORM"
if ! jq -e --arg target "$NODE_TARGET" '.NODEJS.TARGETS[] | select(. == $target)' "$CONFIG_FILE" >/dev/null; then
echo "ERROR: NodeJS target not listed in config: $NODE_TARGET"
exit 1
fi
case "$OS_PLATFORM" in
linux)
EXT="tar.xz"
TAR_OPTS="-xJf"
;;
darwin)
EXT="tar.gz"
TAR_OPTS="-xzf"
;;
win)
echo "ERROR: win32 host install not supported by this installer"
exit 1
;;
*)
echo "ERROR: Unsupported OS platform: $OS_PLATFORM"
exit 1
;;
esac
NODE_DIR="node-v${NODE_VERSION}-${NODE_PLATFORM}"
NODE_TARBALL="${NODE_DIR}.${EXT}"
NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TARBALL}"
SHASUM_URL="https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt"
NODE_BIN="$NODEJS/current/bin/node"
if [[ -e "$NODE_BIN" ]]; then
NODE_BIN_VERSION="$("$NODE_BIN" --version)"
if [[ "$NODE_BIN_VERSION" == "v$NODE_VERSION" ]]; then
echo ""
echo "NodeJS $NODE_PLATFORM v$NODE_VERSION already installed"
return 0
fi
fi
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' RETURN
echo ""
echo "Installing NodeJS:"
echo " Version: $NODE_VERSION"
echo " Archive: $NODE_TARBALL"
echo " To: $NODEJS"
curl -sSL "$SHASUM_URL" -o "$TMP_DIR/SHASUMS256.txt"
curl -sSL "$NODE_URL" -o "$TMP_DIR/$NODE_TARBALL"
EXPECTED_SHA="$(grep " $NODE_TARBALL\$" "$TMP_DIR/SHASUMS256.txt" | awk '{print $1}')"
if [[ -z "$EXPECTED_SHA" ]]; then
echo "ERROR: SHA256 not found for $NODE_TARBALL"
exit 1
fi
ACTUAL_SHA="$(sha256sum "$TMP_DIR/$NODE_TARBALL" | awk '{print $1}')"
if [[ "$ACTUAL_SHA" != "$EXPECTED_SHA" ]]; then
echo "ERROR: SHA mismatch for $NODE_TARBALL"
exit 1
fi
rm -rf "$NODEJS/$NODE_DIR"
tar $TAR_OPTS "$TMP_DIR/$NODE_TARBALL" -C "$NODEJS"
ln -sfn "$NODEJS/$NODE_DIR" "$NODEJS/current"
echo "NodeJS installed:"
echo " $NODEJS/current/bin/node"
}
# ------------------------------------------------------------ # ------------------------------------------------------------
# Main # Main
# ------------------------------------------------------------ # ------------------------------------------------------------
@ -89,7 +190,7 @@ done
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$SCRIPT_DIR" && pwd)" ROOT="$(cd "$SCRIPT_DIR" && pwd)"
CONFIG_FILE="$ROOT/config.json" CONFIG_FILE="$ROOT/nwa-deploy-config.json"
META_FILE="$ROOT/metadata.json" META_FILE="$ROOT/metadata.json"
[[ -f "$CONFIG_FILE" ]] || { echo "ERROR: config.json not found"; exit 1; } [[ -f "$CONFIG_FILE" ]] || { echo "ERROR: config.json not found"; exit 1; }
@ -175,7 +276,7 @@ VERSION_DATE="$(jq -r '.METADATA.version_date' "$META_FILE")"
COPYRIGHT="$(jq -r '.METADATA.copyright' "$META_FILE")" COPYRIGHT="$(jq -r '.METADATA.copyright' "$META_FILE")"
AUTHOR="$(jq -r '.METADATA.author' "$META_FILE")" AUTHOR="$(jq -r '.METADATA.author' "$META_FILE")"
LICENSE="$(jq -r '.METADATA.license' "$META_FILE")" LICENSE="$(jq -r '.METADATA.license' "$META_FILE")"
HOMEPAGE="$(jq -r '.METADATA.homepage' "$META_FILE")" SITEPAGE="$(jq -r '.METADATA.SITEpage' "$META_FILE")"
REPO="$(jq -r '.METADATA.git_repo' "$META_FILE")" REPO="$(jq -r '.METADATA.git_repo' "$META_FILE")"
@ -195,7 +296,7 @@ echo " Version Date: $VERSION_DATE"
echo " Copyright: (C) $COPYRIGHT" echo " Copyright: (C) $COPYRIGHT"
echo " Author: $AUTHOR" echo " Author: $AUTHOR"
echo " License: $LICENSE" echo " License: $LICENSE"
echo " Homepage: $HOMEPAGE" echo " SITEpage: $SITEPAGE"
echo " Repository: $REPO" echo " Repository: $REPO"
echo "" echo ""
@ -226,106 +327,80 @@ echo "Directories:"
echo " ROOT: $ROOT" echo " ROOT: $ROOT"
resolve_dirs "$CONFIG_FILE" resolve_dirs "$CONFIG_FILE"
# ------------------------------------------------------------ # ------------------------------------------------------------
# Build sdl-mgr tarball to DIST # Copy nwa to Prod Dir
# Always rebuild sdl-mgr_version.tgz from source
# ------------------------------------------------------------ # ------------------------------------------------------------
echo "" echo ""
echo "Generating: $DIST/sdl-mgr_$VERSION.tgz" echo "Installing nwa version $VERSION to $VERSIONS/nwa_$VERSION"
tar -czf "$DIST/sdl-mgr_$VERSION.tgz" -C "$ROOT" sdl-mgr rsync -av $ROOT/nwa --exclude='node_modules' $VERSIONS/nwa_$VERSION
sha256sum "$DIST/sdl-mgr_$VERSION.tgz" | awk '{sub(".*/","",$2); print}' > "$DIST/sdl-mgr_$VERSION.tgz.sha256" # ln -s $VERSIONS/nwa_$VERSION $VERSIONS/current
ln -sfnT "$VERSIONS/nwa_$VERSION" "$VERSIONS/current"
# ------------------------------------------------------------ NWA="$VERSIONS/current/nwa"
# Build sdl-wkr tarball to DIST
# Always rebuild sdl-wkr_version.tgz from source
# ------------------------------------------------------------
echo ""
echo "Generating: $DIST/sdl-wkr_$VERSION.tgz"
tar -czf "$DIST/sdl-wkr_$VERSION.tgz" -C "$ROOT" sdl-wkr
sha256sum "$DIST/sdl-wkr_$VERSION.tgz" | awk '{sub(".*/","",$2); print}' > "$DIST/sdl-wkr_$VERSION.tgz.sha256"
# ------------------------------------------------------------
# Copy install-sdl-wkr.sh to DIST
# ------------------------------------------------------------
echo ""
echo "Copying: $DIST/install-sdl-wkr.sh"
cp "$ROOT/sdl-wkr/scripts/install-sdl-wkr.sh" "$DIST/install-sdl-wkr.sh"
sha256sum "$DIST/install-sdl-wkr.sh" | awk '{sub(".*/","",$2); print}' > "$DIST/install-sdl-wkr.sh.sha256"
# ------------------------------------------------------------ # ------------------------------------------------------------
# Fetch NodeJS Tarballs / Zips to DIST # Fetch NodeJS Tarballs / Zips to DIST
# ------------------------------------------------------------ # ------------------------------------------------------------
echo "" install_nodejs
echo "Fetching NodeJS Binaries to $DIST"
SHASUM_URL="https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt"
curl -sSL "$SHASUM_URL" -o "$DIST/NODE_SHASUMS256.txt"
# Download NodeJS tarball # echo ""
# echo "Fetching NodeJS Binaries to $DIST"
# SHASUM_URL="https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt"
# curl -sSL "$SHASUM_URL" -o "$DIST/NODE_SHASUMS256.txt"
for np in $NODE_PLATFORMS; do # # Download NodeJS tarball
IFS=":" read -r OS ARCH <<< "$np"
case "$OS" in # for np in $NODE_PLATFORMS; do
linux) EXT="tar.xz" ;; # IFS=":" read -r OS ARCH <<< "$np"
darwin) EXT="tar.gz" ;;
win) EXT="zip" ;;
*) echo "ERROR: Unknown NodeJS target OS: $OS"; exit 1 ;;
esac
PLATFORM="${OS}-${ARCH}" # case "$OS" in
NODE_DIR="node-v${NODE_VERSION}-${PLATFORM}" # linux) EXT="tar.xz" ;;
NODE_TARBALL="${NODE_DIR}.$EXT" # darwin) EXT="tar.gz" ;;
NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TARBALL}" # win) EXT="zip" ;;
# *) echo "ERROR: Unknown NodeJS target OS: $OS"; exit 1 ;;
# esac
echo " $np: $NODE_TARBALL" # PLATFORM="${OS}-${ARCH}"
# NODE_DIR="node-v${NODE_VERSION}-${PLATFORM}"
# NODE_TARBALL="${NODE_DIR}.$EXT"
# NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TARBALL}"
if [ ! -e "$DIST/$NODE_TARBALL" ]; then # echo " $np: $NODE_TARBALL"
curl -sSL "$NODE_URL" -o "$DIST/$NODE_TARBALL" # if [ ! -e "$DIST/$NODE_TARBALL" ]; then
EXPECTED_SHA="$(grep " $NODE_TARBALL\$" "$DIST/NODE_SHASUMS256.txt" | awk '{print $1}')" # curl -sSL "$NODE_URL" -o "$DIST/$NODE_TARBALL"
if [[ -z "$EXPECTED_SHA" ]]; then # EXPECTED_SHA="$(grep " $NODE_TARBALL\$" "$DIST/NODE_SHASUMS256.txt" | awk '{print $1}')"
echo "Error: SHA256 not found for $NODE_TARBALL"
exit 1
fi
ACTUAL_SHA="$(sha256sum "$DIST/$NODE_TARBALL" | awk '{print $1}')" # if [[ -z "$EXPECTED_SHA" ]]; then
# echo "Error: SHA256 not found for $NODE_TARBALL"
# exit 1
# fi
if [[ "$ACTUAL_SHA" != "$EXPECTED_SHA" ]]; then # ACTUAL_SHA="$(sha256sum "$DIST/$NODE_TARBALL" | awk '{print $1}')"
echo "SHA mismatch $NODE_TARBALL"
rm -f "$DIST/$NODE_TARBALL"
exit 1
fi
echo "$EXPECTED_SHA $NODE_TARBALL" > "$DIST/$NODE_TARBALL.sha256" # if [[ "$ACTUAL_SHA" != "$EXPECTED_SHA" ]]; then
fi # echo "SHA mismatch $NODE_TARBALL"
done # rm -f "$DIST/$NODE_TARBALL"
# exit 1
# fi
# echo "$EXPECTED_SHA $NODE_TARBALL" > "$DIST/$NODE_TARBALL.sha256"
# fi
# done
unset OS ARCH unset OS ARCH
# ------------------------------------------------------------
# Copy NWA/current/conf/efault-nwa-config.json to CONF/nwa-config.json
# ------------------------------------------------------------
# ------------------------------------------------------------ if [ ! -e "$CONF/nwa-config.json" ]; then
# Extract sdl-mgr-VERSION tarball from DIST to MGR
# Symlink to MGR/current
# ------------------------------------------------------------
echo "" echo ""
echo "Extracting: $DIST/sdl-mgr_$VERSION.tgz to $MGR/sdl-mgr_$VERSION" # echo "Copying: $NWA/current/conf/default-nwa-config.json to $CONF/nwa-config.json"
rm -rf "$MGR/sdl-mgr_$VERSION" # cp "$NWA/current/conf/default-nwa-config.json" "$CONF/nwa-config.json"
tar -xzf "$DIST/sdl-mgr_$VERSION.tgz" -C "$MGR" echo "Copying: $NWA/conf/nwa-config.json to $CONF/nwa-config.json"
mv "$MGR/sdl-mgr" "$MGR/sdl-mgr_$VERSION" rsync -av "$NWA/conf/nwa-config.json" "$CONF/nwa-config.json"
# rm "$MGR/current"
ln -sfn "$MGR/sdl-mgr_$VERSION" "$MGR/current"
# ------------------------------------------------------------
# Copy MGR/current/conf/efault-sdl-mgr-config.json to CONF/sdl-mgr-config.json
# ------------------------------------------------------------
if [ ! -e "$CONF/sdl-mgr-config.json" ]; then
echo ""
echo "Copying: $MGR/current/conf/default-sdl-mgr-config.json to $CONF/sdl-mgr-config.json"
cp "$MGR/current/conf/default-sdl-mgr-config.json" "$CONF/sdl-mgr-config.json"
fi fi
# ------------------------------------------------------------ # ------------------------------------------------------------
@ -333,56 +408,56 @@ fi
# Symlink to NODEJS/current # Symlink to NODEJS/current
# ------------------------------------------------------------ # ------------------------------------------------------------
# Check if NodeJS is already installed # # Check if NodeJS is already installed
NODE_BIN="$NODEJS/current/bin/node" NODE_BIN="$NODEJS/current/bin/node"
NPM_BIN="$NODEJS/current/bin/npm" NPM_BIN="$NODEJS/current/bin/npm"
# echo "NodeJS binary: $NODE_BIN" # echo "NodeJS binary: $NODE_BIN"
if [ -e "$NODE_BIN" ]; then # if [ -e "$NODE_BIN" ]; then
NODE_BIN_VERSION="$("$NODE_BIN" --version)" # NODE_BIN_VERSION="$("$NODE_BIN" --version)"
# echo "NodeJS bin version: $NODE_BIN_VERSION" # # echo "NodeJS bin version: $NODE_BIN_VERSION"
# echo "NodeJS version: v$NODE_VERSION" # # echo "NodeJS version: v$NODE_VERSION"
case "$OS_PLATFORM" in # case "$OS_PLATFORM" in
linux) EXT="tar.xz"; TAR_OPTS="-xJf" ;; # linux) EXT="tar.xz"; TAR_OPTS="-xJf" ;;
darwin) EXT="tar.gz"; TAR_OPTS="-xzf" ;; # darwin) EXT="tar.gz"; TAR_OPTS="-xzf" ;;
win) EXT="zip" ;; # win) EXT="zip" ;;
*) echo "ERROR: Unsupported OS platform: $OS_PLATFORM"; exit 1 ;; # *) echo "ERROR: Unsupported OS platform: $OS_PLATFORM"; exit 1 ;;
esac # esac
if [ "$NODE_BIN_VERSION" != "v$NODE_VERSION" ]; then # if [ "$NODE_BIN_VERSION" != "v$NODE_VERSION" ]; then
echo "" # echo ""
echo "Installing NodeJS: node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}" # echo "Installing NodeJS: node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}"
echo "Extracting: $DIST/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}.$EXT" # echo "Extracting: $DIST/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}.$EXT"
if [ $OS_PLATFORM == "win32" ]; then # if [ $OS_PLATFORM == "win32" ]; then
echo "ERROR: win32 host install not supported by this installer" # echo "ERROR: win32 host install not supported by this installer"
exit 1 # exit 1
# unzip "$DIST/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}.$EXT" -d "$NODEJS" # # unzip "$DIST/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}.$EXT" -d "$NODEJS"
else # else
tar $TAR_OPTS "$DIST/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}.$EXT" -C "$NODEJS" # tar $TAR_OPTS "$DIST/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}.$EXT" -C "$NODEJS"
fi # fi
# rm "$NODEJS/current" # # rm "$NODEJS/current"
ln -sfn "$NODEJS/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}" "$NODEJS/current" # ln -sfn "$NODEJS/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}" "$NODEJS/current"
else # else
echo "" # echo ""
echo "NodeJS $OS_PLATFORM-$OS_ARCH v$NODE_VERSION already installed" # echo "NodeJS $OS_PLATFORM-$OS_ARCH v$NODE_VERSION already installed"
fi # fi
else # else
echo "" # echo ""
echo "Installing NodeJS $NODE_VERSION" # echo "Installing NodeJS $NODE_VERSION"
echo "Extracting: $DIST/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}.tar.xz" # echo "Extracting: $DIST/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}.tar.xz"
tar -xJf "$DIST/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}.tar.xz" -C "$NODEJS" # tar -xJf "$DIST/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}.tar.xz" -C "$NODEJS"
ln -sfn "$NODEJS/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}" "$NODEJS/current" # ln -sfn "$NODEJS/node-v${NODE_VERSION}-${OS_PLATFORM}-${OS_ARCH}" "$NODEJS/current"
fi # fi
# ------------------------------------------------------------ # ------------------------------------------------------------
# Install sdl-mgr Node Dependencies # Install nwa Node Dependencies
# ------------------------------------------------------------ # ------------------------------------------------------------
echo "" echo ""
echo "Installing NodeJS Dependencies" echo "Installing NodeJS Dependencies"
cd "$MGR/current/app" cd "$NWA/app"
export PATH="$NODEJS/current/bin:$PATH" export PATH="$NODEJS/current/bin:$PATH"
$NPM_BIN install $NPM_BIN install
@ -390,40 +465,40 @@ $NPM_BIN install
# ------------------------------------------------------------ # ------------------------------------------------------------
# Copy Start / Stop Scripts # Copy Start / Stop Scripts
# ------------------------------------------------------------ # ------------------------------------------------------------
mkdir -p "$HOME/scripts/" mkdir -p "$SITE/scripts/"
cp "$MGR/current/scripts/start-sdl-mgr.sh" "$HOME/scripts/" cp "$NWA/scripts/start-nwa.sh" "$SITE/scripts/"
cp "$MGR/current/scripts/stop-sdl-mgr.sh" "$HOME/scripts/" cp "$NWA/scripts/stop-nwa.sh" "$SITE/scripts/"
cp "$MGR/current/scripts/status-sdl-mgr.sh" "$HOME/scripts/" cp "$NWA/scripts/status-nwa.sh" "$SITE/scripts/"
chmod u+x "$HOME/scripts/"* chmod u+x "$SITE/scripts/"*
# ------------------------------------------------------------ # ------------------------------------------------------------
# Install Systemd Unit Files # Install Systemd Unit Files
# Copy MGR/current/scripts/sdl-mgr.service to ~/.config/systemd/user # Copy NWA/current/scripts/nwa.service to ~/.config/systemd/user
# ------------------------------------------------------------ # ------------------------------------------------------------
if use_systemd; then if use_systemd; then
echo "" echo ""
echo "Installing SystemD Unit Files" echo "Installing SystemD Unit Files"
mkdir -p ~/.config/systemd/user mkdir -p ~/.config/systemd/user
cp "$MGR/current/scripts/sdl-mgr.service" ~/.config/systemd/user/ cp "$NWA/scripts/nwa.service" ~/.config/systemd/user/
"${HOME}/scripts/stop-sdl-mgr.sh" "${SITE}/scripts/stop-nwa.sh"
sleep 1 sleep 1
systemctl --user daemon-reload --no-pager systemctl --user daemon-reload --no-pager
fi fi
# ------------------------------------------------------------ # ------------------------------------------------------------
# Start SDL Manager # Start NWA
# ------------------------------------------------------------ # ------------------------------------------------------------
"${HOME}/scripts/start-sdl-mgr.sh" "${SITE}/scripts/start-nwa.sh"
sleep 2 sleep 2
"${HOME}/scripts/status-sdl-mgr.sh" "${SITE}/scripts/status-nwa.sh"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "" echo ""
echo "ERROR: SDL Manager failed to start" echo "ERROR: NWA failed to start"
exit 1 exit 1
fi fi
@ -432,6 +507,6 @@ fi
echo "" echo ""
echo "SDL Manager deployed:" echo "NWA deployed:"
echo " to: $HOME" echo " to: $SITE"

View File

@ -4,14 +4,14 @@
"description": "Node Web App", "description": "Node Web App",
"abbr": "NWA", "abbr": "NWA",
"version": "0.1.0", "version": "0.1.0",
"version_date": "2026-02-08", "version_date": "2026-06-28",
"maturity": "PROD", "maturity": "PROD",
"author": "John Haverlack", "author": "John Haverlack",
"copyright": "2026 John Haverlack", "copyright": "2026 John Haverlack",
"license": "MIT", "license": "MIT",
"license_url": "https://opensource.org/license/MIT", "license_url": "https://opensource.org/license/MIT",
"homepage": "https://github.com/jehaverlack/sdl", "homepage": "https://github.com/jehaverlack/nwa",
"git_repo": "https://github.com/jehaverlack/sdl.git" "git_repo": "https://github.com/jehaverlack/nwa.git"
}, },
"META_MAPS": { "META_MAPS": {
"package.json": { "package.json": {

View File

@ -1,12 +1,13 @@
{ {
"DIRS": { "DIRS": {
"HOME": "~/.nwa", "SITE": "~/.nwa",
"CONF": "HOME/conf", "CONF": "SITE/conf",
"DOCS": "HOME/docs", "DOCS": "SITE/docs",
"LOGS": "HOME/logs", "LOGS": "SITE/logs",
"DATA": "HOME/data", "DATA": "SITE/data",
"SCRIPTS": "HOME/scripts", "SCRIPTS": "SITE/scripts",
"NODEJS": "HOME/nodejs" "NODEJS": "SITE/nodejs",
"VERSIONS": "SITE/versions"
}, },
"NODEJS": { "NODEJS": {
"VERSION": "24.18.0", "VERSION": "24.18.0",

View File

@ -34,11 +34,14 @@ function load_config() {
.argv; .argv;
// console.log("DEBUG: dirname: " + __dirname); // console.log("DEBUG: dirname: " + __dirname);
let home = path.join(__dirname, '..', '..', '..'); // HOME Default let site = path.join(__dirname, '..', '..', '..', '..', '..', '..'); // site Default
let mgr_cfg_file = path.join(home, 'conf', 'nwa-config.json'); // let base = path.join(__dirname, '..', '..', '..', '..'); // base Default
// let mgr_cfg_file = path.join(base, 'nwa', 'conf', 'nwa-config.json');
let mgr_cfg_file = path.join(site, 'conf', 'nwa-config.json');
// console.log("DEBUG: HOME: " + home); // console.log("DEBUG: site: " + site);
// console.log("DEBUG: MGR_CFG_FILE: " + mgr_cfg_file); // console.log("DEBUG: MGR_CFG_FILE: " + mgr_cfg_file);
try { try {
fs.accessSync(mgr_cfg_file, fs.constants.R_OK); fs.accessSync(mgr_cfg_file, fs.constants.R_OK);
} catch (err) { } catch (err) {
@ -46,38 +49,6 @@ function load_config() {
process.exit(1); process.exit(1);
} }
// // Load from ENV
// if (process.env.HOME) {
// home = process.env.HOME;
// mgr_cfg_file = path.join(home, 'conf', '-mgr-config.json');
// // console.log("DEBUG3: HOME: " + home);
// // console.log("DEBUG3: MGR_CFG_FILE: " + mgr_cfg_file);
// try {
// fs.accessSync(mgr_cfg_file, fs.constants.R_OK);
// } catch (err) {
// console.error(err);
// process.exit(1);
// }
// }
// // Load from ARGV
// if (argv.configfile) {
// home = path.dirname(argv.configfile);
// mgr_cfg_file = path.join(home, 'conf', '-mgr-config.json');
// // console.log("DEBUG4: HOME: " + home);
// // console.log("DEBUG4: MGR_CFG_FILE: " + mgr_cfg_file);
// try {
// fs.accessSync(mgr_cfg_file, fs.constants.R_OK);
// } catch (err) {
// console.error(err);
// process.exit(1);
// }
// }
// console.log("DEBUG: HOME: " + home);
// console.log("DEBUG: MGR_CFG_FILE: " + mgr_cfg_file);
// Load Config // Load Config
try { try {
@ -87,13 +58,13 @@ function load_config() {
console.error(err); console.error(err);
} }
// console.log("DEBUG: home: " + home); // console.log("DEBUG: site: " + site);
// Expand Data Directory // Expand Data Directory
let search_replace = {} let search_replace = {}
search_replace['DIRNAME'] = __dirname search_replace['DIRNAME'] = __dirname
// search_replace['HOME'] = home // search_replace['site'] = site
config.dirs['home'] = home config.dirs['site'] = site
for (let d in config.dirs) { for (let d in config.dirs) {
search_replace[d.toUpperCase()] = d search_replace[d.toUpperCase()] = d
} }
@ -131,23 +102,13 @@ function load_config() {
fs.mkdirSync(config.dirs[d], { recursive: true }); fs.mkdirSync(config.dirs[d], { recursive: true });
} }
} }
// for (let k in config.dependencies[d]) {
// // if k matches case insensitive "dependencies" the remove elemend k.
// if (k.match(/[Dd]ependencies/)) {
// delete config.dependencies[d][k]
// }
// if (k.match(/scripts/)) {
// delete config.dependencies[d][k]
// }
// }
// Load Package Info // Load Package Info
config.package = JSON.parse(fs.readFileSync(path.join(config.dirs.app, 'package.json'), 'utf8')); config.package = JSON.parse(fs.readFileSync(path.join(config.dirs.app, 'package.json'), 'utf8'));
config.dependencies = {} config.dependencies = {}
// Version // Version
config.cluster.version = config.package.version // config.nwa.version = config.package.version
for (let d in config.package.dependencies) { for (let d in config.package.dependencies) {
config.dependencies[d] = JSON.parse(fs.readFileSync(path.join(config.dirs.app, 'node_modules', d, 'package.json'), 'utf8')); config.dependencies[d] = JSON.parse(fs.readFileSync(path.join(config.dirs.app, 'node_modules', d, 'package.json'), 'utf8'));
@ -186,7 +147,8 @@ function load_config() {
}; };
config.nwa = { config.nwa = {
version: config.package.version version: config.package.version,
config_file: mgr_cfg_file
} }
config.identity = { config.identity = {
@ -271,7 +233,7 @@ function load_config() {
try { try {
// console.log(JSON.stringify(config.dirs, null, 2)); // console.log(JSON.stringify(config.dirs, null, 2));
const idinfo = load_or_create_id(config.dirs.home); const idinfo = load_or_create_id(config.dirs.site);
config.identity.id = idinfo.id; config.identity.id = idinfo.id;
config.identity.created_at = idinfo.created_at; config.identity.created_at = idinfo.created_at;
config.identity.hostname = config.host.hostname; config.identity.hostname = config.host.hostname;
@ -381,9 +343,9 @@ function computeBroadcast(address, netmask) {
} }
} }
function load_or_create_id(home) { function load_or_create_id(site) {
// console.log('DEBUG: load_or_create_id() home: ' + home); // console.log('DEBUG: load_or_create_id() site: ' + site);
const id_dir = path.join(home, 'conf'); const id_dir = path.join(site, 'conf');
const id_file = path.join(id_dir, 'nwa-id.json'); const id_file = path.join(id_dir, 'nwa-id.json');
try { try {

View File

@ -1,19 +1,16 @@
{ {
"cluster": { "site": {
"id": "haverlab", "id": "nwa",
"name": "Haverlab", "name": "Node Web App",
"desc": "John Haverlack's Home Lab" "desc": "A Node.json Web App Template"
}, },
"dirs": { "dirs": {
"base": "DIRNAME/../..", "base": "DIRNAME/../..",
"app": "BASE/app", "app": "BASE/app",
"modules": "APP/modules", "modules": "APP/modules",
"logs": "HOME/logs", "logs": "SITE/logs",
"data": "HOME/data", "data": "SITE/data",
"clstr": "DATA/cluster", "conf": "SITE/conf",
"proj": "DATA/proj",
"jobs": "DATA/jobs",
"conf": "HOME/conf",
"modconf": "BASE/conf/modules", "modconf": "BASE/conf/modules",
"html": "BASE/html" "html": "BASE/html"
}, },

31
nwa/scripts/nwa.service Normal file
View File

@ -0,0 +1,31 @@
[Unit]
Description=Node Web App
After=network.target
[Service]
Type=simple
# Environment
Environment=NWA_HOME=%h/.nwa
Environment=NODE_ENV=production
# Paths
WorkingDirectory=%h/.nwa/versions/current/nwa/app
# Start command
ExecStart=%h/.nwa/nodejs/current/bin/node index.js
# Restart behavior
Restart=on-failure
RestartSec=3
# Logging
StandardOutput=append:%h/.nwa/logs/nwa.log
StandardError=append:%h/.nwa/logs/nwa.log
# Clean shutdown
KillSignal=SIGTERM
TimeoutStopSec=15
[Install]
WantedBy=default.target

View File

@ -1,29 +0,0 @@
[Unit]
Description=SDL Manager
After=network.target
[Service]
Type=simple
# Paths
Environment=SDL_HOME=%h/.sdl
WorkingDirectory=%h/.sdl/sdl-mgr/current/app
# Start command
ExecStart=%h/.sdl/nodejs/current/bin/node index.js
# Restart behavior
Restart=on-failure
RestartSec=3
# Logging
StandardOutput=append:%h/.sdl/logs/sdl-mgr.out.log
StandardError=append:%h/.sdl/logs/sdl-mgr.err.log
# Clean shutdown
KillSignal=SIGTERM
TimeoutStopSec=15
[Install]
WantedBy=default.target

65
nwa/scripts/start-nwa.sh Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env bash
# start-nwa.sh - Script to start Node Web App
set -euo pipefail
use_systemd() {
# Check if systemd user mode is available and service exists
if systemctl --user status >/dev/null 2>&1; then
# Check if our service file exists
if systemctl --user list-unit-files | grep -q "^nwa.service"; then
return 0 # Use systemd
fi
fi
return 1 # Use manual scripts
}
# Get $NWA_HOME directory from SCRIPT PATH
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
NWA_HOME="$(cd "$SCRIPT_DIR/.." && pwd)"
if use_systemd; then
# Systemd mode - let systemd handle it
echo "Starting NWA (systemd)..."
systemctl --user start nwa
exit 0
fi
# Manual mode - continue with checks
NODE_BIN_DIR="${NWA_HOME}/nodejs/current/bin"
NODE_BIN="${NODE_BIN_DIR}/node"
NPM_BIN="${NODE_BIN_DIR}/npm"
NWA_APP_DIR="${NWA_HOME}/current/app"
# Check that nwa is not already running
NWA_PID=""
for pid in $(pgrep -f 'node' 2>/dev/null || true); do
cwd=$(readlink /proc/$pid/cwd 2>/dev/null || true)
if [[ "$cwd" == *"nwa"* ]]; then
NWA_PID="$pid"
break
fi
done
if [[ -n "$NWA_PID" ]]; then
echo "ERROR: NWA is already running with PID ${NWA_PID}"
echo " Stop it first: ${NWA_HOME}/scripts/stop-nwa.sh"
exit 1
fi
# Verify paths exist
if [[ ! -f "$NODE_BIN" ]]; then
echo "ERROR: Node.js not found at: $NODE_BIN"
echo " Run install.sh first"
exit 1
fi
if [[ ! -d "$NWA_APP_DIR" ]]; then
echo "ERROR: NWA app not found at: $NWA_APP_DIR"
echo " Run install.sh first"
exit 1
fi
echo "Starting NWA..."
echo " App Dir: ${NWA_APP_DIR}"
echo " Node:

View File

@ -1,65 +0,0 @@
#!/usr/bin/env bash
# start-sdl-mgr.sh - Script to start SDL Manager
set -euo pipefail
use_systemd() {
# Check if systemd user mode is available and service exists
if systemctl --user status >/dev/null 2>&1; then
# Check if our service file exists
if systemctl --user list-unit-files | grep -q "^sdl-mgr.service"; then
return 0 # Use systemd
fi
fi
return 1 # Use manual scripts
}
# Get $SDL_HOME directory from SCRIPT PATH
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SDL_HOME="$(cd "$SCRIPT_DIR/.." && pwd)"
if use_systemd; then
# Systemd mode - let systemd handle it
echo "Starting SDL Manager (systemd)..."
systemctl --user start sdl-mgr
exit 0
fi
# Manual mode - continue with checks
NODE_BIN_DIR="${SDL_HOME}/nodejs/current/bin"
NODE_BIN="${NODE_BIN_DIR}/node"
NPM_BIN="${NODE_BIN_DIR}/npm"
SDL_MGR_APP_DIR="${SDL_HOME}/sdl-mgr/current/app"
# Check that sdl-mgr is not already running
SDL_MGR_PID=""
for pid in $(pgrep -f 'node' 2>/dev/null || true); do
cwd=$(readlink /proc/$pid/cwd 2>/dev/null || true)
if [[ "$cwd" == *"sdl-mgr"* ]]; then
SDL_MGR_PID="$pid"
break
fi
done
if [[ -n "$SDL_MGR_PID" ]]; then
echo "ERROR: SDL Manager is already running with PID ${SDL_MGR_PID}"
echo " Stop it first: ${SDL_HOME}/scripts/stop-sdl-mgr.sh"
exit 1
fi
# Verify paths exist
if [[ ! -f "$NODE_BIN" ]]; then
echo "ERROR: Node.js not found at: $NODE_BIN"
echo " Run install-sdl.sh first"
exit 1
fi
if [[ ! -d "$SDL_MGR_APP_DIR" ]]; then
echo "ERROR: SDL Manager app not found at: $SDL_MGR_APP_DIR"
echo " Run install-sdl.sh first"
exit 1
fi
echo "Starting SDL Manager..."
echo " App Dir: ${SDL_MGR_APP_DIR}"
echo " Node:

View File

@ -1,12 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# status-sdl-mgr.sh - Script to show status of SDL Manager # status-nwa.sh - Script to show status of NWA
set -euo pipefail set -euo pipefail
use_systemd() { use_systemd() {
# Check if systemd user mode is available and service exists # Check if systemd user mode is available and service exists
if systemctl --user status >/dev/null 2>&1; then if systemctl --user status >/dev/null 2>&1; then
# Check if our service file exists # Check if our service file exists
if systemctl --user list-unit-files | grep -q "^sdl-mgr.service"; then if systemctl --user list-unit-files | grep -q "^nwa.service"; then
return 0 # Use systemd return 0 # Use systemd
fi fi
fi fi
@ -14,28 +14,28 @@ use_systemd() {
} }
if use_systemd; then if use_systemd; then
systemctl --user status sdl-mgr systemctl --user status nwa
else else
# Get sdl-mgr PID # Get nwa PID
SDL_MGR_PID="" NWA_PID=""
for pid in $(pgrep -f 'node' 2>/dev/null || true); do for pid in $(pgrep -f 'node' 2>/dev/null || true); do
cwd=$(readlink /proc/$pid/cwd 2>/dev/null || true) cwd=$(readlink /proc/$pid/cwd 2>/dev/null || true)
if [[ "$cwd" == *"sdl-mgr"* ]]; then if [[ "$cwd" == *"nwa"* ]]; then
SDL_MGR_PID="$pid" NWA_PID="$pid"
break break
fi fi
done done
if [[ -z "$SDL_MGR_PID" ]]; then if [[ -z "$NWA_PID" ]]; then
echo "SDL Manager is not running" echo "NWA is not running"
exit 0 exit 0
fi fi
# Get process uptime # Get process uptime
PROCESS_START=$(ps -p "$SDL_MGR_PID" -o lstart= 2>/dev/null || echo "unknown") PROCESS_START=$(ps -p "$NWA_PID" -o lstart= 2>/dev/null || echo "unknown")
echo "SDL Manager is running" echo "NWA is running"
echo " PID: ${SDL_MGR_PID}" echo " PID: ${NWA_PID}"
echo " Started: ${PROCESS_START}" echo " Started: ${PROCESS_START}"
exit 0 exit 0
fi fi

View File

@ -1,12 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# stop-sdl-mgr.sh - Script to stop SDL Manager # stop-nwa.sh - Script to stop NWA
set -euo pipefail set -euo pipefail
use_systemd() { use_systemd() {
# Check if systemd user mode is available and service exists # Check if systemd user mode is available and service exists
if systemctl --user status >/dev/null 2>&1; then if systemctl --user status >/dev/null 2>&1; then
# Check if our service file exists # Check if our service file exists
if systemctl --user list-unit-files | grep -q "^sdl-mgr.service"; then if systemctl --user list-unit-files | grep -q "^nwa.service"; then
return 0 # Use systemd return 0 # Use systemd
fi fi
fi fi
@ -15,51 +15,51 @@ use_systemd() {
if use_systemd; then if use_systemd; then
# Systemd mode - let systemd handle it # Systemd mode - let systemd handle it
echo "Stopping SDL Manager (systemd)..." echo "Stopping NWA (systemd)..."
systemctl --user stop sdl-mgr --quiet 2>/dev/null || true systemctl --user stop nwa --quiet 2>/dev/null || true
echo "SDL Manager stopped" echo "NWA stopped"
exit 0 exit 0
fi fi
# Manual mode - find and kill process # Manual mode - find and kill process
SDL_MGR_PID="" NWA_PID=""
for pid in $(pgrep -f 'node' 2>/dev/null || true); do for pid in $(pgrep -f 'node' 2>/dev/null || true); do
cwd=$(readlink /proc/$pid/cwd 2>/dev/null || true) cwd=$(readlink /proc/$pid/cwd 2>/dev/null || true)
if [[ "$cwd" == *"sdl-mgr"* ]]; then if [[ "$cwd" == *"nwa"* ]]; then
SDL_MGR_PID="$pid" NWA_PID="$pid"
break break
fi fi
done done
if [[ -z "$SDL_MGR_PID" ]]; then if [[ -z "$NWA_PID" ]]; then
echo "SDL Manager is not running" echo "NWA is not running"
exit 0 exit 0
fi fi
echo "Stopping SDL Manager (PID: ${SDL_MGR_PID})..." echo "Stopping NWA (PID: ${NWA_PID})..."
# Send SIGTERM for graceful shutdown # Send SIGTERM for graceful shutdown
kill "$SDL_MGR_PID" kill "$NWA_PID"
# Wait up to 10 seconds for process to exit # Wait up to 10 seconds for process to exit
for i in {1..10}; do for i in {1..10}; do
if ! kill -0 "$SDL_MGR_PID" 2>/dev/null; then if ! kill -0 "$NWA_PID" 2>/dev/null; then
echo "SDL Manager stopped successfully" echo "NWA stopped successfully"
exit 0 exit 0
fi fi
sleep 1 sleep 1
done done
# If still running after 10 seconds, force kill # If still running after 10 seconds, force kill
if kill -0 "$SDL_MGR_PID" 2>/dev/null; then if kill -0 "$NWA_PID" 2>/dev/null; then
echo "WARNING: Graceful shutdown failed, forcing kill..." echo "WARNING: Graceful shutdown failed, forcing kill..."
kill -9 "$SDL_MGR_PID" kill -9 "$NWA_PID"
sleep 1 sleep 1
if kill -0 "$SDL_MGR_PID" 2>/dev/null; then if kill -0 "$NWA_PID" 2>/dev/null; then
echo "ERROR: Failed to stop SDL Manager" echo "ERROR: Failed to stop NWA"
exit 1 exit 1
fi fi
fi fi
echo "SDL Manager stopped" echo "NWA stopped"

View File

@ -1,33 +0,0 @@
import socket
import sys
def main():
if len(sys.argv) != 2:
print("Usage: python udp_listener.py <port>")
return
port = int(sys.argv[1])
# Create a datagram socket
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
except socket.error as msg:
print('Failed to create socket. ' + str(msg))
return
# Enable broadcasting mode
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
try:
# Bind the socket to a specific port
sock.bind(('', port))
except socket.error as msg:
print('Bind failed. ' + str(msg))
return
while True:
data, addr = sock.recvfrom(1024)
print(data.decode())
if __name__ == "__main__":
main()