diff --git a/server/SHServ/Controllers/CronController.php b/server/SHServ/Controllers/CronController.php index 937d5c6..5abc093 100644 --- a/server/SHServ/Controllers/CronController.php +++ b/server/SHServ/Controllers/CronController.php @@ -85,35 +85,6 @@ $device_scanner = $this -> createDeviceScanner(); $found_devices = $device_scanner -> scan_range(FCONF["device_ip_range"][0], FCONF["device_ip_range"][1]); - $found_by_hard_id = []; - foreach($found_devices as $found) { - $found_by_hard_id[$found["device_id"]] = $found; - } - - foreach($active_devices as $device) { - if(!isset($found_by_hard_id[$device -> device_hard_id])) { - continue; - } - - $found = $found_by_hard_id[$device -> device_hard_id]; - $is_changed = false; - - if($device -> device_ip != $found["ip_address"]) { - $device -> device_ip = $found["ip_address"]; - $is_changed = true; - } - - if($device -> connection_status != "active") { - $device -> connection_status = "active"; - $is_changed = true; - } - - if($is_changed) { - $device -> update(); - } - - // HTTP-ответ от устройства = контакт - $device -> touch_last_contact(); - } + $devices_model -> reconcile_scan_results($found_devices); } } diff --git a/server/SHServ/Controllers/DevicesRESTAPIController.php b/server/SHServ/Controllers/DevicesRESTAPIController.php index b439bbd..612ad0a 100644 --- a/server/SHServ/Controllers/DevicesRESTAPIController.php +++ b/server/SHServ/Controllers/DevicesRESTAPIController.php @@ -78,6 +78,9 @@ $device_model = new Devices(); $devices = $device_model -> scanning_localnet(FCONF["device_ip_range"][0], FCONF["device_ip_range"][1]); + // Update IP / connection_status for active devices that changed their address + $device_model -> reconcile_scan_results($devices); + return $this -> utils() -> response_success([ "devices" => $devices ]); diff --git a/server/SHServ/Models/Devices.php b/server/SHServ/Models/Devices.php index caabd7e..4c51456 100644 --- a/server/SHServ/Models/Devices.php +++ b/server/SHServ/Models/Devices.php @@ -313,4 +313,61 @@ return $count ? false : true; } -} \ No newline at end of file + + /** + * Reconcile scan results against active devices in DB. + * For each active device whose hard_id was found on the network, + * update device_ip if it changed and restore connection_status to active. + * Returns statistics about updates. + * + * @param array $found_devices Results from DeviceScanner::scan_range() + * @return array ['updated' => int, 'restored' => int] + */ + public function reconcile_scan_results(array $found_devices): array { + $active_devices = $this -> get_device_list("active"); + + $found_by_hard_id = []; + foreach($found_devices as $found) { + $hard_id = $found["device_id"] ?? null; + if($hard_id) { + $found_by_hard_id[(string)$hard_id] = $found; + } + } + + $updated = 0; + $restored = 0; + + foreach($active_devices as $device) { + if(!isset($found_by_hard_id[(string)$device -> device_hard_id])) { + continue; + } + + $found = $found_by_hard_id[(string)$device -> device_hard_id]; + $is_changed = false; + + if($device -> device_ip != ($found["ip_address"] ?? "")) { + $device -> device_ip = $found["ip_address"] ?? ""; + $is_changed = true; + $updated++; + } + + if($device -> connection_status != "active") { + $device -> connection_status = "active"; + $is_changed = true; + $restored++; + } + + if($is_changed) { + $device -> update(); + } + + // HTTP-ответ от устройства = контакт + $device -> touch_last_contact(); + } + + return [ + "updated" => $updated, + "restored" => $restored, + ]; + } +} diff --git a/server/tests/DevicesTest.php b/server/tests/DevicesTest.php new file mode 100644 index 0000000..6ead72c --- /dev/null +++ b/server/tests/DevicesTest.php @@ -0,0 +1,93 @@ + tb = app() -> thin_builder; + $this -> tb -> query("CREATE TABLE devices ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + area_id INTEGER DEFAULT 0, + alias TEXT, + name TEXT, + device_type TEXT, + device_ip TEXT, + device_mac TEXT, + device_hard_id TEXT, + firmware_version TEXT, + connection_status TEXT, + status TEXT, + description TEXT, + last_contact TEXT, + create_at TEXT, + update_at TEXT + )"); + } + + protected function tearDown(): void { + $this -> tb -> query("DROP TABLE IF EXISTS devices"); + } + + public function test_reconcile_updates_ip_and_restores_connection_status(): void { + $this -> tb -> insert('devices', [ + 'alias' => 'roaming', + 'name' => 'Roaming', + 'device_type' => 'relay', + 'device_ip' => '192.168.1.40', + 'device_hard_id' => 'hard_roam_001', + 'connection_status' => 'lost', + 'status' => 'active', + 'last_contact' => date('Y-m-d H:i:s', time() - 600), + 'create_at' => date('Y-m-d H:i:s'), + ]); + + $devices_model = new Devices(); + $result = $devices_model -> reconcile_scan_results([ + [ + 'device_id' => 'hard_roam_001', + 'ip_address' => '192.168.1.99', + 'device_type' => 'relay', + ] + ]); + + $this -> assertSame(1, $result['updated']); + $this -> assertSame(1, $result['restored']); + + $row = $this -> tb -> query("SELECT device_ip, connection_status FROM devices WHERE device_hard_id = 'hard_roam_001'") -> fetch(\PDO::FETCH_ASSOC); + $this -> assertSame('192.168.1.99', $row['device_ip']); + $this -> assertSame('active', $row['connection_status']); + } + + public function test_reconcile_skips_unknown_devices(): void { + $this -> tb -> insert('devices', [ + 'alias' => 'known', + 'name' => 'Known', + 'device_type' => 'relay', + 'device_ip' => '192.168.1.10', + 'device_hard_id' => 'hard_known_001', + 'connection_status' => 'active', + 'status' => 'active', + 'last_contact' => date('Y-m-d H:i:s'), + 'create_at' => date('Y-m-d H:i:s'), + ]); + + $devices_model = new Devices(); + $result = $devices_model -> reconcile_scan_results([ + [ + 'device_id' => 'hard_unknown_999', + 'ip_address' => '192.168.1.99', + 'device_type' => 'relay', + ] + ]); + + $this -> assertSame(0, $result['updated']); + $this -> assertSame(0, $result['restored']); + + $row = $this -> tb -> query("SELECT device_ip, connection_status FROM devices WHERE device_hard_id = 'hard_known_001'") -> fetch(\PDO::FETCH_ASSOC); + $this -> assertSame('192.168.1.10', $row['device_ip']); + $this -> assertSame('active', $row['connection_status']); + } +} diff --git a/server/tests/TestApp.php b/server/tests/TestApp.php index 6accb48..49bd8a4 100644 --- a/server/tests/TestApp.php +++ b/server/tests/TestApp.php @@ -3,7 +3,6 @@ class TestApp { public \Fury\Modules\ThinBuilder\ThinBuilder $thin_builder; public \SHServ\Utils $utils; - public \SHServ\Sessions $sessions; public \SHServ\DevTools $devtools; public $factory = null; public array $control_scripts_instances = []; diff --git a/server/tests/bootstrap.php b/server/tests/bootstrap.php index 9a89217..9c276d2 100644 --- a/server/tests/bootstrap.php +++ b/server/tests/bootstrap.php @@ -15,7 +15,6 @@ $testApp = new TestApp(); $testApp->thin_builder = $tb; $testApp->utils = new \SHServ\Utils(); -$testApp->sessions = new \SHServ\Sessions(); $testApp->devtools = new \SHServ\DevTools(); \Fury\Kernel\AppContainer::set_app($testApp);