Add manual rescan control

This commit is contained in:
Corsair-cxs 2026-06-23 22:37:30 +08:00
parent d92b0f6b0e
commit dc021d307b
9 changed files with 66 additions and 20 deletions

View file

@ -370,7 +370,7 @@ const docTemplate = `{
},
"/rescan": {
"get": {
"description": "Manually trigger rescan",
"description": "Manually trigger rescan and wait until the DB is updated",
"produces": [
"application/json"
],

View file

@ -363,7 +363,7 @@
},
"/rescan": {
"get": {
"description": "Manually trigger rescan",
"description": "Manually trigger rescan and wait until the DB is updated",
"produces": [
"application/json"
],

View file

@ -345,7 +345,7 @@ paths:
- network
/rescan:
get:
description: Manually trigger rescan
description: Manually trigger rescan and wait until the DB is updated
produces:
- application/json
responses:

View file

@ -25,14 +25,14 @@ func getVersion(c *gin.Context) {
// triggerRescan godoc
// @Summary Rescan all interfaces now
// @Description Manually trigger rescan
// @Description Manually trigger rescan and wait until the DB is updated
// @Tags system
// @Produce json
// @Success 200 {string} string "OK"
// @Router /rescan [get]
func triggerRescan(c *gin.Context) {
routines.ScanRestart()
c.Status(http.StatusOK)
routines.ScanNow()
c.IndentedJSON(http.StatusOK, "OK")
}
// getConfig godoc

View file

@ -3,6 +3,7 @@ package routines
import (
"sort"
"strings"
"sync"
"time"
"github.com/aceberg/WatchYourLAN/internal/arp"
@ -15,9 +16,21 @@ import (
"github.com/aceberg/WatchYourLAN/internal/prometheus"
)
var scanMu sync.Mutex
// ScanNow runs one scan immediately and waits until DB state is updated.
func ScanNow() {
scanMu.Lock()
defer scanMu.Unlock()
foundHosts := arp.Scan(conf.AppConfig.Ifaces, conf.AppConfig.ArpArgs, conf.AppConfig.ArpStrs)
foundHosts = check.EnrichHosts(foundHosts)
compareHosts(newFoundHostIndex(foundHosts))
}
func startScan(quit chan bool) {
var lastDate, nowDate, plusDate time.Time
var foundHosts []models.Host
for {
select {
@ -29,15 +42,16 @@ func startScan(quit chan bool) {
if nowDate.After(plusDate) {
foundHosts = arp.Scan(conf.AppConfig.Ifaces, conf.AppConfig.ArpArgs, conf.AppConfig.ArpStrs)
foundHosts = check.EnrichHosts(foundHosts)
compareHosts(newFoundHostIndex(foundHosts))
ScanNow()
lastDate = time.Now()
}
time.Sleep(time.Duration(1) * time.Minute)
select {
case <-quit:
return
case <-time.After(time.Duration(1) * time.Minute):
}
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,11 +1,12 @@
import { Show } from "solid-js";
import { Show, createSignal } from "solid-js";
import { editNames, selectedIDs, setEditNames } from "../../functions/exports";
import Filter from "../Filter";
import Search from "../Search";
import { getHosts } from "../../functions/atstart";
import { apiDelHost } from "../../functions/api";
import { apiDelHost, apiRescan } from "../../functions/api";
function CardHead() {
const [rescanning, setRescanning] = createSignal(false);
const handleEditNames = (toggle: boolean) => {
if (!toggle) {
@ -24,6 +25,20 @@ function CardHead() {
window.location.href = '/';
};
const handleRescan = async () => {
if (rescanning()) {
return;
}
setRescanning(true);
try {
await apiRescan();
await getHosts();
} finally {
setRescanning(false);
}
};
return (
<div class="row">
<div class="col-md mt-1 mb-1">
@ -33,7 +48,18 @@ function CardHead() {
</div>
<div class="col-md mt-1 mb-1">
<div class="d-flex justify-content-between">
<Search></Search>
<div class="d-flex gap-2">
<Search></Search>
<button
class="btn btn-outline-primary"
title="Rescan now"
onClick={handleRescan}
disabled={rescanning()}
style="width: 2.5rem;"
>
<i class={rescanning() ? "spinner-border spinner-border-sm" : "bi bi-arrow-clockwise"}></i>
</button>
</div>
<Show
when={editNames()}
fallback={<button class="btn btn-outline-primary" title="Toggle edit" onClick={[handleEditNames, true]}>Edit</button>}

View file

@ -29,6 +29,12 @@ export const apiTestNotify = async () => {
await fetch(url);
};
export const apiRescan = async () => {
const url = apiPath+'/api/rescan';
await fetch(url);
};
export const apiEditHost = async (id:number, name:string, known:string) => {
const url = apiPath+'/api/edit/'+id+'/'+name+'/'+known;
@ -81,4 +87,4 @@ export const apiWOL = async (mac:string) => {
const res = await (await fetch(url)).json();
return res;
};
};

View file

@ -15,7 +15,7 @@ export function runAtStart() {
export async function getHosts() {
const hosts = await apiGetAllHosts();
if (hosts !== null && hosts.length > 0) {
if (hosts !== null) {
setAllHosts(hosts);
setBkpHosts(hosts);
@ -36,4 +36,4 @@ function listIfaces() {
}
setIfaces(ifaces);
}
}