feat: daemon mode with named socket, scripts/run for IP:PORT
This commit is contained in:
@@ -17,12 +17,14 @@ simple (one language, two packages) and is adequate for Spine's complexity level
|
||||
|---------|---------|--------|---------|
|
||||
| `simple-httpd` | MELPA latest | MELPA | HTTP server, `defservlet` routing |
|
||||
| `mustache` | MELPA latest | MELPA | Mustache template rendering |
|
||||
| `ht` | — | transitive via `mustache` | Hash table for template context |
|
||||
| `ht` | MELPA latest | MELPA | Hash table for template context |
|
||||
|
||||
## Project structure
|
||||
|
||||
```
|
||||
spine/
|
||||
├── scripts/
|
||||
│ └── run # start the server as a daemon
|
||||
├── spine.el # entry point: bootstrap, server start, handlers
|
||||
├── templates/
|
||||
│ └── hello.mustache # smoke-test template
|
||||
@@ -45,7 +47,7 @@ packages from MELPA; subsequent starts skip the install step.
|
||||
(require 'package)
|
||||
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
|
||||
(package-initialize)
|
||||
(dolist (pkg '(simple-httpd mustache))
|
||||
(dolist (pkg '(simple-httpd mustache ht))
|
||||
(unless (package-installed-p pkg)
|
||||
(package-refresh-contents)
|
||||
(package-install pkg)))
|
||||
@@ -60,16 +62,24 @@ start.
|
||||
(defvar spine-port 8080
|
||||
"Port for the Spine HTTP server.")
|
||||
|
||||
(defvar spine-host nil
|
||||
"Host for the Spine HTTP server.
|
||||
nil means localhost only. Set to a string like \"0.0.0.0\" to listen on
|
||||
all interfaces.")
|
||||
|
||||
(defvar spine-template-dir
|
||||
(expand-file-name "templates/" (file-name-directory load-file-name))
|
||||
"Directory containing .mustache templates.")
|
||||
|
||||
(setq httpd-host spine-host)
|
||||
(setq httpd-port spine-port)
|
||||
(httpd-start)
|
||||
(message "Spine listening on http://localhost:%d" spine-port)
|
||||
(message "Spine listening on http://%s:%d"
|
||||
(or spine-host "localhost") spine-port)
|
||||
```
|
||||
|
||||
- Port defaults to 8080, overridable by setting `spine-port` before loading.
|
||||
- Port defaults to 8080, overridable via `spine-port`.
|
||||
- Host defaults to nil (localhost-only), overridable via `spine-host`.
|
||||
- `spine-template-dir` resolves relative to `spine.el`'s directory so the app
|
||||
works regardless of `default-directory`.
|
||||
|
||||
@@ -124,6 +134,23 @@ Returns the rendered string."
|
||||
|
||||
## Invocation
|
||||
|
||||
Production use — Emacs daemon with a named socket, no GUI frame:
|
||||
|
||||
```bash
|
||||
scripts/run [HOST:]PORT
|
||||
```
|
||||
|
||||
- `scripts/run 9090` → `http://localhost:9090/hello`
|
||||
- `scripts/run 0.0.0.0:8080` → `http://0.0.0.0:8080/hello` (all interfaces)
|
||||
- `scripts/run` → `http://localhost:8080/hello`
|
||||
|
||||
Stop: `emacsclient --socket-name=spine --eval '(kill-emacs)'`
|
||||
|
||||
The socket name `spine` is separate from the default Emacs daemon socket,
|
||||
so your personal daemon is unaffected.
|
||||
|
||||
Development use — interactive Emacs in the terminal:
|
||||
|
||||
```bash
|
||||
emacs --quick --load spine.el
|
||||
```
|
||||
@@ -141,5 +168,4 @@ emacs --quick --load spine.el
|
||||
|
||||
- Book data, Org file integration, any handler beyond `/hello`.
|
||||
- Static file serving (CSS, JS, icons).
|
||||
- Emacs daemon mode, process management, systemd units.
|
||||
- Tests — the scaffold is small enough to smoke-test manually.
|
||||
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
HOST=""
|
||||
PORT="8080"
|
||||
|
||||
if [ $# -ge 1 ] && [ -n "$1" ]; then
|
||||
ARG="$1"
|
||||
if [[ "$ARG" == *:* ]]; then
|
||||
HOST="${ARG%:*}"
|
||||
PORT="${ARG##*:}"
|
||||
else
|
||||
PORT="$ARG"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Stop any existing spine daemon
|
||||
emacsclient --socket-name=spine --eval '(kill-emacs)' 2>/dev/null || true
|
||||
|
||||
# Build emacs args
|
||||
EMACS_ARGS=(emacs --quick --daemon=spine)
|
||||
|
||||
if [ -n "$HOST" ]; then
|
||||
EMACS_ARGS+=(--eval "(setq spine-host \"$HOST\")")
|
||||
fi
|
||||
|
||||
EMACS_ARGS+=(--eval "(setq spine-port $PORT)")
|
||||
EMACS_ARGS+=(--load "$ROOT_DIR/spine.el")
|
||||
|
||||
"${EMACS_ARGS[@]}"
|
||||
|
||||
DISPLAY_HOST="${HOST:-localhost}"
|
||||
echo "Spine running at http://${DISPLAY_HOST}:${PORT}/hello"
|
||||
echo "Stop: emacsclient --socket-name=spine --eval '(kill-emacs)'"
|
||||
@@ -21,6 +21,10 @@
|
||||
|
||||
(defvar spine-port 8080
|
||||
"Port for the Spine HTTP server.")
|
||||
(defvar spine-host nil
|
||||
"Host for the Spine HTTP server.
|
||||
nil means localhost only. Set to a string like \"0.0.0.0\" to listen on
|
||||
all interfaces.")
|
||||
|
||||
(defvar spine-template-dir
|
||||
(expand-file-name "templates/"
|
||||
@@ -47,10 +51,11 @@ Returns the rendered string."
|
||||
("message" "Hello from Emacs.")))))
|
||||
|
||||
;; --- start ------------------------------------------------------------
|
||||
|
||||
(setq httpd-host spine-host)
|
||||
(setq httpd-port spine-port)
|
||||
(httpd-start)
|
||||
(message "Spine listening on http://localhost:%d" spine-port)
|
||||
(message "Spine listening on http://%s:%d"
|
||||
(or spine-host "localhost") spine-port)
|
||||
|
||||
(provide 'spine)
|
||||
;;; spine.el ends here
|
||||
|
||||
Reference in New Issue
Block a user