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": { "/rescan": {
"get": { "get": {
"description": "Manually trigger rescan", "description": "Manually trigger rescan and wait until the DB is updated",
"produces": [ "produces": [
"application/json" "application/json"
], ],

View file

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

View file

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

View file

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

View file

@ -3,6 +3,7 @@ package routines
import ( import (
"sort" "sort"
"strings" "strings"
"sync"
"time" "time"
"github.com/aceberg/WatchYourLAN/internal/arp" "github.com/aceberg/WatchYourLAN/internal/arp"
@ -15,9 +16,21 @@ import (
"github.com/aceberg/WatchYourLAN/internal/prometheus" "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) { func startScan(quit chan bool) {
var lastDate, nowDate, plusDate time.Time var lastDate, nowDate, plusDate time.Time
var foundHosts []models.Host
for { for {
select { select {
@ -29,15 +42,16 @@ func startScan(quit chan bool) {
if nowDate.After(plusDate) { if nowDate.After(plusDate) {
foundHosts = arp.Scan(conf.AppConfig.Ifaces, conf.AppConfig.ArpArgs, conf.AppConfig.ArpStrs) ScanNow()
foundHosts = check.EnrichHosts(foundHosts)
compareHosts(newFoundHostIndex(foundHosts))
lastDate = time.Now() 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 { editNames, selectedIDs, setEditNames } from "../../functions/exports";
import Filter from "../Filter"; import Filter from "../Filter";
import Search from "../Search"; import Search from "../Search";
import { getHosts } from "../../functions/atstart"; import { getHosts } from "../../functions/atstart";
import { apiDelHost } from "../../functions/api"; import { apiDelHost, apiRescan } from "../../functions/api";
function CardHead() { function CardHead() {
const [rescanning, setRescanning] = createSignal(false);
const handleEditNames = (toggle: boolean) => { const handleEditNames = (toggle: boolean) => {
if (!toggle) { if (!toggle) {
@ -24,6 +25,20 @@ function CardHead() {
window.location.href = '/'; window.location.href = '/';
}; };
const handleRescan = async () => {
if (rescanning()) {
return;
}
setRescanning(true);
try {
await apiRescan();
await getHosts();
} finally {
setRescanning(false);
}
};
return ( return (
<div class="row"> <div class="row">
<div class="col-md mt-1 mb-1"> <div class="col-md mt-1 mb-1">
@ -33,7 +48,18 @@ function CardHead() {
</div> </div>
<div class="col-md mt-1 mb-1"> <div class="col-md mt-1 mb-1">
<div class="d-flex justify-content-between"> <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 <Show
when={editNames()} when={editNames()}
fallback={<button class="btn btn-outline-primary" title="Toggle edit" onClick={[handleEditNames, true]}>Edit</button>} 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); 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) => { export const apiEditHost = async (id:number, name:string, known:string) => {
const url = apiPath+'/api/edit/'+id+'/'+name+'/'+known; 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(); const res = await (await fetch(url)).json();
return res; return res;
}; };

View file

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