diff --git a/openapi/owgw.yaml b/openapi/owgw.yaml index 8c36b30a..330a41d7 100644 --- a/openapi/owgw.yaml +++ b/openapi/owgw.yaml @@ -1489,7 +1489,7 @@ paths: default: false required: false - in: query - description: MAC address must match this pattern + description: MAC address must match this pattern. Mutually exclusive with oldestContact name: macPattern schema: type: string @@ -1497,7 +1497,16 @@ paths: - "aabbcc*" - "*aabbcc*" - "*cccddee" - required: true + required: false + - in: query + description: lastRecordedContact older than this value. Mutually exclusive with macPattern + name: oldestContact + schema: + type: integer + format: int64 + required: false + + responses: 200: $ref: '#/components/responses/Success' diff --git a/src/RESTAPI/RESTAPI_devices_handler.cpp b/src/RESTAPI/RESTAPI_devices_handler.cpp index 841c6c9d..a780a01e 100644 --- a/src/RESTAPI/RESTAPI_devices_handler.cpp +++ b/src/RESTAPI/RESTAPI_devices_handler.cpp @@ -185,6 +185,13 @@ namespace OpenWifi { return OK(); } + auto SimulatedOnly = GetBoolParameter("simulatedOnly",false); + auto oldestContact = GetParameter("oldestContact",0); + if(oldestContact!=0) { + StorageService()->DeleteDevices(oldestContact,SimulatedOnly); + return OK(); + } + auto macPattern = GetParameter("macPattern",""); if(macPattern.empty()) { return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); @@ -197,7 +204,6 @@ namespace OpenWifi { return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); } - auto SimulatedOnly = GetBoolParameter("simulatedOnly",false); StorageService()->DeleteDevices(macPattern, SimulatedOnly); return OK(); } diff --git a/src/StorageService.h b/src/StorageService.h index 31c64300..c9abec95 100644 --- a/src/StorageService.h +++ b/src/StorageService.h @@ -128,6 +128,7 @@ namespace OpenWifi { // std::vector &Devices, const std::string & orderBy=""); bool DeleteDevice(std::string &SerialNumber); bool DeleteDevices(std::string &SerialPattern, bool SimulatedOnly); + bool DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly); bool UpdateDevice(GWObjects::Device &); bool DeviceExists(std::string &SerialNumber); diff --git a/src/storage/storage_device.cpp b/src/storage/storage_device.cpp index 39a7545f..feedb48a 100644 --- a/src/storage/storage_device.cpp +++ b/src/storage/storage_device.cpp @@ -566,17 +566,17 @@ namespace OpenWifi { bool Storage::DeleteDevice(std::string &SerialNumber) { try { - std::vector DBList{"Devices", "Statistics", "CommandList", + std::vector TableNames{"Devices", "Statistics", "CommandList", "HealthChecks", "Capabilities", "DeviceLogs"}; - for (const auto &i : DBList) { + for (const auto &tableName : TableNames) { Poco::Data::Session Sess = Pool_->get(); Poco::Data::Statement Delete(Sess); - std::string St{"DELETE FROM " + i + " WHERE SerialNumber=?"}; + std::string St = fmt::format("DELETE FROM {} WHERE SerialNumber='{}'", tableName, SerialNumber); try { - Delete << ConvertParams(St), Poco::Data::Keywords::use(SerialNumber); + Delete << St; Delete.execute(); } catch (...) { } @@ -600,11 +600,15 @@ namespace OpenWifi { return false; } + static void DeleteDeviceList(std::vector &SerialNumbers, Poco::Logger &Logger) { + for (auto &serialNumber:SerialNumbers) { + poco_information(Logger,fmt::format("BATCH-DEVICE_DELETE: deleting {}", serialNumber)); + StorageService()->DeleteDevice(serialNumber); + } + } + bool Storage::DeleteDevices(std::string &SerialPattern, bool SimulatedOnly) { try { - std::vector TableNames{"Devices", "Statistics", "CommandList", - "HealthChecks", "Capabilities", "DeviceLogs"}; - std::vector SerialNumbers; Poco::Data::Session Sess = Pool_->get(); Poco::Data::Statement GetSerialNumbers(Sess); @@ -617,38 +621,30 @@ namespace OpenWifi { Poco::Data::Keywords::into(SerialNumbers); GetSerialNumbers.execute(); - poco_information(Logger(),fmt::format("Found {} devices that match the criteria {} to delete.", SerialNumbers.size(), SerialPattern)); + poco_information(Logger(),fmt::format("BATCH-DEVICE_DELETE: Found {} devices that match the criteria {} to delete.", SerialNumbers.size(), SerialPattern)); + DeleteDeviceList(SerialNumbers, Logger()); + return true; + } catch (const Poco::Exception &E) { + Logger().log(E); + } + return false; + } - for (auto &serialNumber:SerialNumbers) { - poco_information(Logger(),fmt::format("BATCH-DEVICE_DELETE: deleting {}", serialNumber)); - for (const auto &tableName : TableNames) { + bool Storage::DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly) { + try { + std::vector SerialNumbers; + Poco::Data::Session Sess = Pool_->get(); + Poco::Data::Statement GetSerialNumbers(Sess); - Poco::Data::Session DeleteSess = Pool_->get(); - Poco::Data::Statement Delete(Sess); - - std::string St = fmt::format("DELETE FROM {} WHERE SerialNumber='{}'", tableName, serialNumber); - Delete << St; - Delete.execute(); - - try { - Delete << ConvertParams(St), Poco::Data::Keywords::use(SerialPattern); - Delete.execute(); - } catch (...) { - } - } - SerialNumberCache()->DeleteSerialNumber(serialNumber); - - if (KafkaManager()->Enabled()) { - Poco::JSON::Object Message; - Message.set("command", "device_deleted"); - Message.set("timestamp", Utils::Now()); - std::ostringstream StrPayload; - Message.stringify(StrPayload); - KafkaManager()->PostMessage(KafkaTopics::COMMAND, serialNumber, std::make_shared(StrPayload.str())); - } - - } + std::string SelectStatement = SimulatedOnly ? + fmt::format("SELECT SerialNumber FROM Devices WHERE simulated and lastRecordedContact!=0 and lastRecordedContact<{} limit 10000",OlderContact) : + fmt::format("SELECT SerialNumber FROM Devices lastRecordedContact>0 and lastRecordedContact<{} limit 10000",OlderContact); + GetSerialNumbers << SelectStatement, + Poco::Data::Keywords::into(SerialNumbers); + GetSerialNumbers.execute(); + poco_information(Logger(),fmt::format("BATCH-DEVICE_DELETE: Found {} devices that match with lastRecordedContact older than {} to delete.", SerialNumbers.size(), OlderContact)); + DeleteDeviceList(SerialNumbers, Logger()); return true; } catch (const Poco::Exception &E) { Logger().log(E);