8 Commits
18 changed files with 214 additions and 162 deletions

No files matched your search

+1 -6
View File
@@ -2,9 +2,4 @@
target = "armv7-unknown-linux-musleabihf"
[target.armv7-unknown-linux-musleabihf]
linker = "rust-lld"
[alias]
ldabr = "b -r --target=target.armv7-unknown-linux-musleabihf"
t = "test -- --nocapture --test-threads=1"
tdebug = "test -- --nocapture --test-threads=1 --show-output"
linker = "rust-lld"
File renamed without changes.
+1 -3
View File
@@ -1,10 +1,8 @@
you should use block code to refence code, like so:
```rust
hello_world!(println);
// indented lines
```
in the chat. Else it fucks up formatting.
We work towards clean, maintainable design. im not the best at this thing.
We work towards clean, maintainable design. im not the best at this thing.
+1 -1
View File
@@ -1,4 +1,4 @@
{
"rust-analyzer.cargo.target": "armv7-unknown-linux-musleabihf",
"rust-analyzer.diagnostics.disabled": ["unlinked-file"]
}
}
Generated
+1 -1
View File
@@ -1179,7 +1179,7 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "wakey"
version = "0.1.6"
version = "0.1.5"
dependencies = [
"axum",
"axum-extra",
+3 -9
View File
@@ -1,6 +1,6 @@
[package]
name = "wakey"
version = "0.1.6"
version = "0.1.5"
edition = "2024"
publish = ["gitea"]
@@ -16,12 +16,7 @@ serde_json = "1.0.143"
serde_with = { version = "3.14.0", features = ["json"] }
strum = { version = "0.27.2", features = ["derive", "strum_macros"] }
thiserror = "2.0.16"
tokio = { version = "1.47.1", features = [
"fs",
"process",
"rt-multi-thread",
"io-util",
] }
tokio = { version = "1.47.1", features = ["fs", "process", "rt-multi-thread", "io-util"] }
urlencoding = "2.1.3"
[profile.release]
@@ -30,5 +25,4 @@ strip = true
[features]
default = ["very-smart-parsing"]
very-smart-parsing = [
] # this is the a-bit-redundant parse thing that copilot made
very-smart-parsing = [] # this is the a-bit-redundant parse thing that copilot made
+60
View File
@@ -0,0 +1,60 @@
# taking back my code AHHHH
this is going to be lengthy. ci is spotless but idk how it works cuz powershell. this is good but i cant afford VPN on the router; we will need to do some bullshit.
## overview
we need a:
- small ahh bin in the router.
- forwards a shell and some functions.
- may be shell calling fns maybe some unsafe c. i cant unsafe c.
- big ahh bin in the vps.
- connect to the small ahh bin thru the wide ass internet.
- forwards some APIs.
- static site
- now need no hosts; apis can be called anywhere anyway.
- do offer these in the big ahh bins tho lets not miss out some shit.
- automation
- gitea
- on the vps or the uh idk.
- ABSOLUTELY can auto build main:latest every day / other day.
- and releases.
- router
- a script to pull the tar. from actions artifacts or from releases. (lua or shell yo)
- a script for the bin and the init.d scripts for these two.
- vps
- a systemd service (ima use ai for ts ngl)
- an auto updater. maybe we overkill and dnf. maybe go easy and git clone + cargo install. maybe we pull from release or nightly. idk
i think idk
## router
### current
everything.
we have some functions that call ip neigh a bajillion times.
we have some other functions that read the same file/folder in /sys or sum shit.
we have a function that broadcast to a set ahh address.
we have some routes; and some data structures acting as schema for them ahh. we dont do posts with json but gets with query strings for some ahh reasons.
these are carryover from the early days.
also from the early days are the js.
static was 100% ai with 0 intervention.
we have a search bar of sort that hooks through a smart endpoint that searches for everything.
we have some bullshit. and two buttons to check and wake. that pings `/api/smart/{query}` and `/wake?name=query`. why.
we have the result of the wake and or status and the errors in the first text box.
the list of cliets with names connected to the router the second box.
thats cool.
### changes?
idk changes.
+5 -5
View File
@@ -10,12 +10,12 @@
START=50 # Run before Tailscale (typically START~80)
start() {
LOGFILE=/var/log/update_tailscale.log
MAX_RETRIES=10
RETRY_COUNT=0
LOGFILE=/var/log/update_tailscale.log
MAX_RETRIES=10
RETRY_COUNT=0
# shellcheck disable=SC2016
sh -c '
# shellcheck disable=SC2016
sh -c '
while [ "$RETRY_COUNT" -lt "$MAX_RETRIES" ]; do
if fn; then
echo "[update_tailscale] Success at $(date)" >>"$LOGFILE"
+7 -7
View File
@@ -8,14 +8,14 @@ NAME=wakey
BIN=/root/.bin/wakey
start_service() {
procd_open_instance
procd_set_param command "$BIN"
procd_set_param respawn 5 1 0
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
procd_open_instance
procd_set_param command "$BIN"
procd_set_param respawn 5 1 0
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}
stop_service() {
: # procd manages the process; nothing to do here
: # procd manages the process; nothing to do here
}
+2 -2
View File
@@ -6,7 +6,7 @@ pids="$(pidof wakey 2>/dev/null)"
# 2) Fallback: ps | awk (avoid matching awk/grep themselves)
if [ -z "$pids" ]; then
pids="$(ps w 2>/dev/null | awk '/\/\.bin\/wakey/ && $0 !~ /awk/ {print $1}')"
pids="$(ps w 2>/dev/null | awk '/\/\.bin\/wakey/ && $0 !~ /awk/ {print $1}')"
fi
[ -n "$pids" ] || exit 0
@@ -18,7 +18,7 @@ kill -TERM "$pids" 2>/dev/null || true
usleep 250000 # uhhh sleep is stupid
remain=""
for p in $pids; do
kill -0 "$p" 2>/dev/null && remain="$remain $p"
kill -0 "$p" 2>/dev/null && remain="$remain $p"
done
[ -z "$remain" ] || kill -KILL "$remain" 2>/dev/null || true
+8 -8
View File
@@ -3,22 +3,22 @@
set -e
# 0th step from lda is to move the pre assed resolv.conf to the real resolv.conf
if [ -f /tmp/resolv.conf ]; then
cp -af /tmp/resolv.conf /etc/resolv.conf
cp -af /tmp/resolv.conf /etc/resolv.conf
elif [ -f /rom/etc/resolv.conf ]; then
cp -af /rom/etc/resolv.conf /etc/resolv.conf
cp -af /rom/etc/resolv.conf /etc/resolv.conf
fi
if [ -x "$(which tailscale)" ]; then
tailscale update
exit 0
tailscale update
exit 0
fi
# 1. Fetch the latest version number from Tailscale's site
LATEST=$(curl -s https://pkgs.tailscale.com/stable/ | grep -Eo 'tailscale_[0-9\.]+_arm.tgz' | head -n1)
[ -z "$LATEST" ] && {
echo "❌ Couldn't find latest ARM binary."
exit 1
echo "❌ Couldn't find latest ARM binary."
exit 1
}
URL="https://pkgs.tailscale.com/stable/${LATEST}"
@@ -26,8 +26,8 @@ URL="https://pkgs.tailscale.com/stable/${LATEST}"
cd /var/tmp
if [ -f "$LATEST" ]; then
echo "file exists"
rm "$LATEST"
echo "file exists"
rm "$LATEST"
fi
echo "Downloading $LATEST..."
+88 -88
View File
@@ -24,113 +24,113 @@ STAGING="$TMPDIR/wakey-rootfs.$$.$ARCH"
log() { echo "[update_wakey] $*"; }
fail() {
echo "[update_wakey] ERROR: $*" >&2
exit 1
echo "[update_wakey] ERROR: $*" >&2
exit 1
}
http_get() {
# http_get <url>
if command -v uclient-fetch >/dev/null 2>&1; then
# uclient-fetch supports -O -, write to stdout
uclient-fetch -O - "$1" 2>/dev/null || return 1
elif command -v wget >/dev/null 2>&1; then
# shellcheck disable=SC2086
wget ${WAKEY_INSECURE:+--no-check-certificate} -qO- "$1" || return 1
elif command -v curl >/dev/null 2>&1; then
if [ -n "${WAKEY_INSECURE:-}" ]; then
curl -fsSL -k "$1" || return 1
else
curl -fsSL "$1" || return 1
fi
else
return 2
fi
# http_get <url>
if command -v uclient-fetch >/dev/null 2>&1; then
# uclient-fetch supports -O -, write to stdout
uclient-fetch -O - "$1" 2>/dev/null || return 1
elif command -v wget >/dev/null 2>&1; then
# shellcheck disable=SC2086
wget ${WAKEY_INSECURE:+--no-check-certificate} -qO- "$1" || return 1
elif command -v curl >/dev/null 2>&1; then
if [ -n "${WAKEY_INSECURE:-}" ]; then
curl -fsSL -k "$1" || return 1
else
curl -fsSL "$1" || return 1
fi
else
return 2
fi
}
fetch() {
# fetch <url> <out>
if command -v uclient-fetch >/dev/null 2>&1; then
uclient-fetch -O "$2" "$1" || return 1
elif command -v wget >/dev/null 2>&1; then
wget ${WAKEY_INSECURE:+--no-check-certificate} -O "$2" "$1" || return 1
elif command -v curl >/dev/null 2>&1; then
if [ -n "${WAKEY_INSECURE:-}" ]; then
curl -fSL -k -o "$2" "$1" || return 1
else
curl -fSL -o "$2" "$1" || return 1
fi
else
return 2
fi
# fetch <url> <out>
if command -v uclient-fetch >/dev/null 2>&1; then
uclient-fetch -O "$2" "$1" || return 1
elif command -v wget >/dev/null 2>&1; then
wget ${WAKEY_INSECURE:+--no-check-certificate} -O "$2" "$1" || return 1
elif command -v curl >/dev/null 2>&1; then
if [ -n "${WAKEY_INSECURE:-}" ]; then
curl -fSL -k -o "$2" "$1" || return 1
else
curl -fSL -o "$2" "$1" || return 1
fi
else
return 2
fi
}
latest_asset_url() {
# prints URL to stdout, returns 0 on success (public release only)
HOST=$1 OWNER=$2 REPO=$3 ARCH=$4
API="https://$HOST/api/v1/repos/$OWNER/$REPO/releases/latest"
RESP=$(http_get "$API") || return 1
# Extract the first browser_download_url ending with our ARCH .tgz (BusyBox-friendly)
echo "$RESP" |
grep -o '"browser_download_url"[[:space:]]*:[[:space:]]*"[^"]*'"$ARCH"'\.tgz"' |
head -n1 |
cut -d '"' -f 4
# prints URL to stdout, returns 0 on success (public release only)
HOST=$1 OWNER=$2 REPO=$3 ARCH=$4
API="https://$HOST/api/v1/repos/$OWNER/$REPO/releases/latest"
RESP=$(http_get "$API") || return 1
# Extract the first browser_download_url ending with our ARCH .tgz (BusyBox-friendly)
echo "$RESP" |
grep -o '"browser_download_url"[[:space:]]*:[[:space:]]*"[^"]*'"$ARCH"'\.tgz"' |
head -n1 |
cut -d '"' -f 4
}
main() {
[ -f "$FLAG" ] && return
URL="${WAKEY_TGZ_URL:-}"
if [ -z "$URL" ]; then
HOST=${WAKEY_HOST:-git.ldlda.com}
OWNER=${WAKEY_OWNER:-lda}
REPO=${WAKEY_REPO:-wakey}
if [ -n "${WAKEY_VERSION:-}" ]; then
FILE="wakey-rootfs-${WAKEY_VERSION}-${ARCH}.tgz"
URL="https://$HOST/$OWNER/$REPO/releases/download/${WAKEY_VERSION}/$FILE"
else
URL=$(latest_asset_url "$HOST" "$OWNER" "$REPO" "$ARCH") || fail "unable to resolve latest asset URL"
[ -n "$URL" ] || fail "no asset URL found for arch $ARCH"
fi
fi
[ -f "$FLAG" ] && return
URL="${WAKEY_TGZ_URL:-}"
if [ -z "$URL" ]; then
HOST=${WAKEY_HOST:-git.ldlda.com}
OWNER=${WAKEY_OWNER:-lda}
REPO=${WAKEY_REPO:-wakey}
if [ -n "${WAKEY_VERSION:-}" ]; then
FILE="wakey-rootfs-${WAKEY_VERSION}-${ARCH}.tgz"
URL="https://$HOST/$OWNER/$REPO/releases/download/${WAKEY_VERSION}/$FILE"
else
URL=$(latest_asset_url "$HOST" "$OWNER" "$REPO" "$ARCH") || fail "unable to resolve latest asset URL"
[ -n "$URL" ] || fail "no asset URL found for arch $ARCH"
fi
fi
log "fetching $URL"
if ! fetch "$URL" "$TMPFILE"; then
fail "download failed"
fi
log "fetching $URL"
if ! fetch "$URL" "$TMPFILE"; then
fail "download failed"
fi
log "installing"
mkdir -p "$TMPDIR" "$STAGING"
tar -xz -f "$TMPFILE" -C "$STAGING" || fail "extract failed"
log "installing"
mkdir -p "$TMPDIR" "$STAGING"
tar -xz -f "$TMPFILE" -C "$STAGING" || fail "extract failed"
# Ensure execute bits on staged files we know should be executable
for f in \
"$STAGING/etc/init.d/"* \
"$STAGING/etc/ldlda_help/"*.sh \
"$STAGING/root/.bin/wakey" \
"$STAGING/root/.bin/kill_wakey.sh" \
"$STAGING/root/.bin/remote_deploy_wakey.sh"; do
[ -e "$f" ] && chmod +x "$f" 2>/dev/null || true
done
# Ensure execute bits on staged files we know should be executable
for f in \
"$STAGING/etc/init.d/"* \
"$STAGING/etc/ldlda_help/"*.sh \
"$STAGING/root/.bin/wakey" \
"$STAGING/root/.bin/kill_wakey.sh" \
"$STAGING/root/.bin/remote_deploy_wakey.sh"; do
[ -e "$f" ] && chmod +x "$f" 2>/dev/null || true
done
# Normalize line endings for shell scripts (avoid CRLF issues on OpenWrt)
for f in \
"$STAGING/etc/init.d/"* \
"$STAGING/etc/ldlda_help/"*.sh \
"$STAGING/root/.bin/"*.sh; do
[ -f "$f" ] && sed -i 's/\r$//' "$f" 2>/dev/null || true
done
# Normalize line endings for shell scripts (avoid CRLF issues on OpenWrt)
for f in \
"$STAGING/etc/init.d/"* \
"$STAGING/etc/ldlda_help/"*.sh \
"$STAGING/root/.bin/"*.sh; do
[ -f "$f" ] && sed -i 's/\r$//' "$f" 2>/dev/null || true
done
# Copy staged tree into /
tar -C "$STAGING" -cf - . | tar -C / -xpf - || fail "install copy failed"
# Copy staged tree into /
tar -C "$STAGING" -cf - . | tar -C / -xpf - || fail "install copy failed"
rm -f "$TMPFILE"
rm -rf "$STAGING"
rm -f "$TMPFILE"
rm -rf "$STAGING"
if [ -f /etc/init.d/wakey ]; then
/etc/init.d/wakey enable || true
/etc/init.d/wakey restart || /etc/init.d/wakey start || true
fi
touch "$FLAG"
log "done"
if [ -f /etc/init.d/wakey ]; then
/etc/init.d/wakey enable || true
/etc/init.d/wakey restart || /etc/init.d/wakey start || true
fi
touch "$FLAG"
log "done"
}
main "$@"
+1 -1
View File
@@ -52,7 +52,7 @@ class RsAssetModule:
body = "\n".join(files + subs)
return (
f"pub mod {sanitize(self.folder.name).lower()} {{" * self.full
+ f"\n{indent(body, 4 * self.full)}\n"
+ f"\n{indent(body, 4*self.full)}\n"
+ self.full * "}"
)
+14 -14
View File
@@ -10,32 +10,32 @@ INIT="/etc/init.d/wakey"
KILL="/root/.bin/kill_wakey.sh"
if [ -z "$BIN_TMP" ] || [ -z "$DEST" ]; then
echo "usage: $0 <bin_tmp> <dest_path> [restart_flag]" >&2
exit 2
echo "usage: $0 <bin_tmp> <dest_path> [restart_flag]" >&2
exit 2
fi
[ -f "$BIN_TMP" ] || {
echo "tmp binary not found: $BIN_TMP" >&2
exit 1
echo "tmp binary not found: $BIN_TMP" >&2
exit 1
}
chmod +x "$BIN_TMP" || true
if [ "$RESTART" = "1" ]; then
if [ -x "$INIT" ]; then
"$INIT" stop || true
elif [ -x "$KILL" ]; then
sh "$KILL" || true
fi
if [ -x "$INIT" ]; then
"$INIT" stop || true
elif [ -x "$KILL" ]; then
sh "$KILL" || true
fi
fi
mv -f "$BIN_TMP" "$DEST"
if [ "$RESTART" = "1" ]; then
if [ -x "$INIT" ]; then
"$INIT" start || "$INIT" restart || true
else
nohup "$DEST" >/dev/null 2>&1 &
fi
if [ -x "$INIT" ]; then
"$INIT" start || "$INIT" restart || true
else
nohup "$DEST" >/dev/null 2>&1 &
fi
fi
exit 0
-12
View File
@@ -6,7 +6,6 @@ pub mod status;
pub mod wake;
use crate::assets;
use crate::dhcpparse::load_mac_name_cache;
use crate::route::api::ip;
use crate::route::api::status_redirect;
use crate::route::api::status_smart_redirect;
@@ -15,8 +14,6 @@ use crate::route::dhcp::get_dhcp_leases;
use crate::route::status::get_status_json;
use crate::route::wake::wake_multi;
use axum::Json;
use axum::response::IntoResponse;
use axum::routing::post;
use axum::{Router, http::header, response::Html, routing::get};
@@ -60,13 +57,4 @@ pub fn api_router() -> Router {
.route("/devs", get(devs_router))
.route("/wake", post(wake_multi))
.route("/ips/{name}", get(ip))
.route(
"/mac-cache",
get(|| async {
match load_mac_name_cache().await {
Ok(h) => Json(h).into_response(),
Err(e) => e.to_string().into_response(),
}
}),
)
}
+8
View File
@@ -47,6 +47,14 @@ pub struct Filters {
pub macs: Vec<MacAddr>,
}
#[deprecated = "use ApiError"]
#[skip_serializing_none]
#[derive(Debug, Serialize, Default)]
pub struct StatusError {
pub name: Option<String>,
pub error: String,
}
pub async fn get_status_json(
Query(DeviceQuery {
name,
+1 -1
View File
@@ -19,7 +19,7 @@ pub async fn _ping_ip_2<T: ToSocketAddrs>(_addr: T) -> bool {
}
pub async fn _ping_ip_3<T: Into<IpAddr>>(addr: T) -> u8 {
match get_mac(Some(addr.into()), None, &[] as &[NUDState]).await {
match get_mac(Some(addr.into()), None, None).await {
Err(_) => 0,
Ok(l) => l
.into_iter()
+13 -4
View File
@@ -72,8 +72,13 @@ pub async fn get_macs(
} else {
devs.iter().next().map(AsRef::as_ref)
};
let opt_state = if state.len() > 1 {
None
} else {
state.iter().next().copied()
};
let run_one = |to_ip: Option<IpAddr>| get_mac(to_ip, opt_dev, state);
let run_one = |to_ip: Option<IpAddr>| get_mac(to_ip, opt_dev, opt_state);
let mut ip_filtered = if let Some(something) = ip_all {
if something.len() == 1 {
@@ -92,6 +97,7 @@ pub async fn get_macs(
// Apply additional filters if any were provided
if !devs.is_empty() || !macs.is_empty() || !state.is_empty() {
let devset: HashSet<_> = devs.iter().map(AsRef::as_ref).collect();
let nudset: HashSet<_> = state.iter().collect();
let macset: HashSet<_> = macs.iter().collect();
ip_filtered.retain(|entry| {
@@ -99,10 +105,13 @@ pub async fn get_macs(
let dev_ok =
devset.is_empty() || entry.dev.as_deref().is_some_and(|d| devset.contains(d));
// NUD filter: always present, simple check
let nud_ok = nudset.is_empty() || nudset.contains(&entry.state);
// MAC filter: if we're filtering by MAC, entry must have a MAC AND it must be in the set
let mac_ok = macset.is_empty() || entry.mac.is_some_and(|m| macset.contains(&m));
dev_ok && mac_ok
dev_ok && nud_ok && mac_ok
})
};
Ok(ip_filtered)
@@ -112,7 +121,7 @@ pub async fn get_macs(
pub async fn get_mac(
ip: Option<IpAddr>,
dev: Option<&str>,
state: &[NUDState],
state: Option<NUDState>,
) -> Result<Vec<IpNeighLine>> {
let mut args: Vec<String> = vec!["neigh".into(), "show".into()];
if let Some(ip) = ip {
@@ -123,7 +132,7 @@ pub async fn get_mac(
args.push("dev".into());
args.push(d.to_string());
}
for nud in state {
if let Some(nud) = state {
args.push("nud".into());
args.push(nud.as_ip_neigh_arg().into());
}