#
# shaterd — the single Shater v0.2 Go daemon (PREBUILT binary package).
#
# `shaterd` embeds the sing-box engine (box.New, in-process), the control-plane,
# the in-process DNS filter, the stats aggregator AND the admin-panel SPA
# (//go:embed all:webroot). shater-core's procd init supervises `shaterd run`;
# shater-core DEPENDS:=+shaterd, so THIS package is what resolves that dep.
#
# WHY PREBUILT (not from-source in the SDK)
# -----------------------------------------
# The shipped binary is the product of a toolchain the OpenWrt SDK cannot easily
# reproduce:
#   * a Vite/npm build of the React SPA (Node is not guaranteed in an SDK env),
#   * that SPA embedded via //go:embed all:webroot at `go build` time,
#   * the D9 musl-static router tag set (CGO_ENABLED=0, fully static ET_EXEC),
#   * a UPX --lzma --best pass (D10) that takes ~42 MB → ~10 MB.
# Reproducing npm + embed + UPX inside the SDK is fragile; instead we build the
# binary out-of-tree with scripts/build-shaterd.sh (host or CI) and package the
# arch-matched artifact. This mirrors the common Go+asset+UPX prebuilt pattern.
#
# HOW CI STAGES THE BINARY
# ------------------------
# scripts/build-shaterd.sh copies its output into this package's files/ dir:
#   dist/shaterd-<a>.upx  ->  openwrt/shaterd/files/shaterd-<a>.upx   (a ∈ amd64,arm64)
# The SDK build then picks files/shaterd-$(ARCH-mapped).upx below. So CI order is:
#   1) scripts/build-shaterd.sh           (produces + stages both arches)
#   2) copy openwrt/* into the SDK feed, `make package/shaterd/compile`
# The staged binaries are gitignored (they are release artifacts, not source).
#
# The binary is a fully static musl-safe ELF, so DEPENDS is empty (no libc/shared
# deps). The data-plane kmods + ip-full live on shater-core.
#

include $(TOPDIR)/rules.mk

PKG_NAME:=shaterd

# VERSIONING — derived from the git tag, NOT hand-maintained here (bug B4).
# ci/version.sh turns `git describe` into SHATER_PKG_VERSION/SHATER_PKG_RELEASE
# (tag vX.Y.Z -> X.Y.Z + r1; off-tag -> last tag + r<commits+1>), and
# ci/build-feed-apk.sh exports them into the SDK build env. ci/sdk-build-apk.sh
# then ASSERTS that the produced .apk really carries that version, so a lost env
# can never silently ship a stale one again.
# The literals below are ONLY the manual/offline fallback (no CI, no git) — they
# are not "the release version"; releases are named by the tag.
PKG_VERSION:=$(if $(SHATER_PKG_VERSION),$(SHATER_PKG_VERSION),0.2.0)
PKG_RELEASE:=$(if $(SHATER_PKG_RELEASE),$(SHATER_PKG_RELEASE),1)

PKG_MAINTAINER:=Shater <maqrota@icloud.com>
PKG_LICENSE:=GPL-3.0-or-later

include $(INCLUDE_DIR)/package.mk

# Map the OpenWrt target $(ARCH) to the scripts/build-shaterd.sh artifact suffix.
# Extend BOTH this map and ARCHES in build-shaterd.sh to publish more router arches.
#   x86_64          -> amd64   (x86 routers / the test VM)
#   aarch64         -> arm64   (both BPI routers are aarch64_cortex-a53)
SHATERD_ARTIFACT:=$(strip \
  $(if $(filter x86_64,$(ARCH)),amd64,\
  $(if $(filter aarch64,$(ARCH)),arm64,)))

SHATERD_BIN:=shaterd-$(SHATERD_ARTIFACT).upx

# The staged binary is already UPX-compressed; the SDK's default RSTRIP pass would
# corrupt a packed executable, so disable stripping for this package (no-op `:`).
RSTRIP:=:
STRIP:=:

define Package/shaterd
  SECTION:=net
  CATEGORY:=Network
  TITLE:=Shater v0.2 daemon (prebuilt static musl, SPA-embedded, UPX)
  URL:=https://github.com/shater
  # Static musl ELF (CGO_ENABLED=0): no shared-lib deps beyond the kernel.
  DEPENDS:=
endef

define Package/shaterd/description
  The single Shater v0.2 daemon. One long-lived Go process that embeds the
  sing-box engine (in-process, box.New), the control-plane, the in-process DNS
  filter, the statistics aggregator and the embedded Faceplate admin-panel SPA.
  Supervised by shater-core's procd init as `shaterd run`. This package ships a
  prebuilt, statically-linked (musl-safe), UPX-compressed binary produced out of
  tree by scripts/build-shaterd.sh (npm SPA build + //go:embed + D9 tags + D10 UPX).
endef

# Nothing to fetch. Build/Compile only VALIDATES that the arch-matched prebuilt
# artifact was staged (scripts/build-shaterd.sh) before the SDK build.
define Build/Prepare
	mkdir -p $(PKG_BUILD_DIR)
endef

define Build/Compile
	$(if $(SHATERD_ARTIFACT),,$(error shaterd: no prebuilt artifact mapped for OpenWrt ARCH '$(ARCH)'. Add it to scripts/build-shaterd.sh (ARCHES) and the ARCH map in openwrt/shaterd/Makefile))
	@test -f $(CURDIR)/files/$(SHATERD_BIN) || { \
		echo "shaterd: staged binary files/$(SHATERD_BIN) not found."; \
		echo "  Run scripts/build-shaterd.sh first — it stages dist/shaterd-$(SHATERD_ARTIFACT).upx"; \
		echo "  into openwrt/shaterd/files/$(SHATERD_BIN) for ARCH=$(ARCH)."; \
		exit 1; }
endef

define Package/shaterd/install
	$(INSTALL_DIR) $(1)/usr/bin
	$(INSTALL_BIN) $(CURDIR)/files/$(SHATERD_BIN) $(1)/usr/bin/shaterd
endef

# This package ships ONLY the binary — no init script — so the package manager's
# postinst never touches the running service. On `apk upgrade shaterd` the new
# ELF lands at /usr/bin/shaterd while the OLD image keeps running from its
# unlinked inode: the upgrade silently has no effect until the next reboot, and
# meanwhile the new CLI (`shaterd reconcile`, `status`, `mint-token` — invoked by
# cron/hotplug/rpcd) talks over the control socket to an old daemon. Restart the
# service here, but ONLY if it was actually running, so a first install (where
# shater-core may not be unpacked yet) and offline image builds stay untouched.
define Package/shaterd/postinst
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] && exit 0
if [ -x /etc/init.d/shater ] && pidof shaterd >/dev/null 2>&1; then
	logger -t shaterd -p daemon.notice "binary upgraded — restarting the shater service"
	/etc/init.d/shater restart >/dev/null 2>&1
fi
exit 0
endef

$(eval $(call BuildPackage,shaterd))
