From 851e5c25eb2d4d4a6f97d9d17f9a56b00dfa1d4b Mon Sep 17 00:00:00 2001 From: Thiflict <121az348@gmail.com> Date: Mon, 20 Apr 2026 21:21:07 +0500 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3:=20=D0=A7=D0=B8=D1=81=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BA=D0=BE=D0=B4=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/ButtonListener.kt | 26 +---- src/main/kotlin/GPIOController.kt | 25 ++--- src/main/kotlin/Main.kt | 161 +++++++----------------------- 3 files changed, 46 insertions(+), 166 deletions(-) diff --git a/src/main/kotlin/ButtonListener.kt b/src/main/kotlin/ButtonListener.kt index fd38e1e..08bf776 100644 --- a/src/main/kotlin/ButtonListener.kt +++ b/src/main/kotlin/ButtonListener.kt @@ -6,6 +6,7 @@ import ru.thiflict.PinConfig.BUTTON import java.io.BufferedReader import java.io.InputStreamReader import java.util.concurrent.atomic.AtomicBoolean +import kotlin.time.Duration.Companion.milliseconds class ButtonClickEvent class ButtonLongPressEvent @@ -31,18 +32,10 @@ class ButtonListener( clickListeners.add(listener) } - fun removeClickListener(listener: ButtonClickListener) { - clickListeners.remove(listener) - } - fun addLongPressListener(listener: ButtonLongPressListener) { longPressListeners.add(listener) } - fun removeLongPressListener(listener: ButtonLongPressListener) { - longPressListeners.remove(listener) - } - private fun notifyClick() { println("=== [CLICK] Короткое нажатие ===") val event = ButtonClickEvent() @@ -93,7 +86,6 @@ class ButtonListener( onStateChange?.invoke(false) println(if (isDebug) "Кнопка отпущена, длительность: ${pressDuration}ms" else "") - // Определяем тип нажатия по длительности when { pressDuration >= longPressThresholdMs -> { println(if (isDebug) "Длинное нажатие (${pressDuration}ms)" else "") @@ -118,10 +110,9 @@ class ButtonListener( println("Процесс завершён ($exitCode)") isListening.set(false) - // Автоматически перезапускаем прослушивание, если оно должно быть активно if (isListening.get()) { println("Перезапуск прослушивания...") - delay(100) + delay(100.milliseconds) startListeningInternal(onStateChange) } } @@ -130,17 +121,4 @@ class ButtonListener( isListening.set(false) } } - - fun stopListening() { - isListening.set(false) - listenerJob?.cancel() - process?.destroy() - process = null - } - - fun restartListening(onStateChange: ((Boolean) -> Unit)? = null) { - stopListening() - Thread.sleep(200) - startListening(onStateChange) - } } \ No newline at end of file diff --git a/src/main/kotlin/GPIOController.kt b/src/main/kotlin/GPIOController.kt index f4278fc..4c48568 100644 --- a/src/main/kotlin/GPIOController.kt +++ b/src/main/kotlin/GPIOController.kt @@ -6,18 +6,15 @@ class GPIOController(private val pin: Int) { fun setValue(value: Int) { try { - // Пробуем разные варианты синтаксиса gpioset val commands = listOf("gpioset", "--chip=0", "$pin=$value") - - try { - val process = ProcessBuilder(commands) - .redirectErrorStream(true) - .start() - Thread.sleep(50) - process.destroy() - } catch (e: Exception) { - // Пробуем следующую команду - } + try { + val process = ProcessBuilder(commands) + .redirectErrorStream(true) + .start() + Thread.sleep(30) + process.destroy() + } catch (_: Exception) { + } } catch (e: Exception) { println(if (isDebug) "Ошибка установки GPIO $pin = $value: ${e.message}" else "") @@ -38,10 +35,4 @@ class GPIOController(private val pin: Int) { 0 } } - - fun close() { - // Ничего не делаем - } - - } \ No newline at end of file diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 5f007f7..4803df4 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -10,7 +10,6 @@ import java.util.* import java.util.concurrent.* import kotlin.time.Duration.Companion.milliseconds -// Конфигурация GPIO (BCM номера) object PinConfig { const val GREEN_LED = 17 const val YELLOW_LED = 27 @@ -26,7 +25,6 @@ object DebugMode { } } -// Состояния системы enum class SystemState { IDLE, SCANNING, CLEAN, INFECTED, ERROR, INIT, SAMBA } @@ -48,22 +46,19 @@ class USBVirusScanner { println(if (isDebug) "Инициализация..." else "") try { - // Проверяем доступность gpiod - checkLibgpiod() + checkLibgpiod() // Проверка установленных библиотек greenLed = GPIOController(PinConfig.GREEN_LED) yellowLed = GPIOController(PinConfig.YELLOW_LED) redLed = GPIOController(PinConfig.RED_LED) - // Выключаем все светодиоды greenLed.setValue(0) yellowLed.setValue(0) redLed.setValue(0) - // Запускаем индикацию состояния - startStateIndication() + startStateIndication() // Запуск системы индикации - antivirusDatabaseUpdater() + antivirusDatabaseUpdater() // Первоначальная проверка обновлений антивирусных баз данных Thread.sleep(1000) @@ -73,7 +68,7 @@ class USBVirusScanner { } catch (e: Exception) { currentState = SystemState.ERROR - println(if (isDebug) "❌ Ошибка инициализации: ${e.message}" else "") + println(if (isDebug) "Ошибка инициализации: ${e.message}" else "") e.printStackTrace() throw e } @@ -89,30 +84,16 @@ class USBVirusScanner { } val output = process.inputStream.bufferedReader().readText() - println(if (isDebug) "✅ libgpiod найден" else "") + println(if (isDebug) "libgpiod найден" else "") if (output.isNotBlank()) { println(if (isDebug) "Доступные чипы: ${output.trim()}" else "") } - } catch (e: Exception) { - throw Exception(if (isDebug) "libgpiod Не установлен!" else "") + } catch (_: Exception) { + throw Exception(if (isDebug) "libgpiod Не установлен" else "") } } - fun buttonPress(defaultButtonState: Boolean): Boolean { - var finalButtonState = defaultButtonState - println(if (isDebug) "Начало finalButtonState: $finalButtonState" else "") - - val buttonListener = ButtonListener() - val initialState = buttonListener.startListening { isPressed -> - if (isPressed) { - finalButtonState = true - } - } - println(if (isDebug) "finalButtonState: $finalButtonState" else "") - return finalButtonState - } - private fun startStateIndication() { indicationJob = scope.launch { while (isRunning) { @@ -205,7 +186,7 @@ class USBVirusScanner { return@launch } - println(if (isDebug) "📀 Найдены USB-устройства:" else "") + println(if (isDebug) "Найдены USB-устройства:" else "") usbDevices.forEach { device -> println(" - ${device.mountPoint}") } @@ -215,31 +196,28 @@ class USBVirusScanner { val scanResults = mutableListOf() for (device in usbDevices) { - println(if (isDebug) "🔍 Сканирование: ${device.mountPoint}" else "") + println(if (isDebug) "Сканирование: ${device.mountPoint}" else "") val result = scanWithClamAV(device.mountPoint) scanResults.add(result) if (result.isInfected) { hasVirus = true - println(if (isDebug) "⚠️ ВНИМАНИЕ! Найдены угрозы!" else "") + println(if (isDebug) "ВНИМАНИЕ! Найдены угрозы!" else "") result.infectedFiles.take(10).forEach { file -> - println(" 🦠 ${file.take(100)}") + println(" - ${file.take(100)}") } if (result.infectedFiles.size > 10) { println(if (isDebug) " ... и ещё ${result.infectedFiles.size - 10} файлов" else "") } unmount() } else if (result.error != null) { - println(if (isDebug) "❌ Ошибка сканирования: ${result.error}" else "") + println(if (isDebug) "Ошибка сканирования: ${result.error}" else "") } else { - println(if (isDebug) "✅ Сканирование завершено: угроз не найдено" else "") + println(if (isDebug) "Сканирование завершено: угроз не найдено" else "") } println() } - // Сохраняем лог - saveScanLog(scanResults) - currentState = if (hasVirus) { SystemState.INFECTED } else { @@ -247,14 +225,13 @@ class USBVirusScanner { } val message = if (hasVirus) { - if (isDebug) "🦠 Найдены вирусы! Красный LED горит" else "" + if (isDebug) "Debug: Найдены вирусы" else "" } else { - if (isDebug) "✅ Флешка чиста! Зелёный LED горит" else "" + if (isDebug) "Debug: Флешка чиста" else "" } println(if (isDebug) message else "") - // Держим состояние 5 секунд - delay(10000.milliseconds) + delay(10000.milliseconds) // Удерживание состояния на 10 секунд if (!hasVirus) { currentState = SystemState.SAMBA @@ -263,7 +240,7 @@ class USBVirusScanner { val buttonListener = ButtonListener() var isEventHappened = false - buttonListener.addLongPressListener { event -> + buttonListener.addLongPressListener { _ -> isEventHappened = true } buttonListener.startListening() @@ -274,12 +251,12 @@ class USBVirusScanner { currentState = SystemState.IDLE - } catch (e: kotlinx.coroutines.CancellationException) { + } catch (_: kotlinx.coroutines.CancellationException) { currentState = SystemState.IDLE println(if (isDebug) "Программа получила CancellationException. Возврат к состоянию IDLE." else "") } catch (e: Exception) { - println(if (isDebug) "❌ Критическая ошибка: ${e.message}" else "") + println(if (isDebug) "Критическая ошибка: ${e.message}" else "") e.printStackTrace() currentState = SystemState.ERROR delay(10000.milliseconds) @@ -293,8 +270,7 @@ class USBVirusScanner { private fun findUSBDevices(): List { val devices = mutableListOf() - try { - // Проверяем /media директории + try { // Проверка директории /media val mediaDirs = listOf("/media", "/media/pi") for (mediaDirPath in mediaDirs) { @@ -319,7 +295,7 @@ class USBVirusScanner { } } - // Проверяем /proc/mounts для дополнительных точек монтирования + // Проверка /proc/mounts не предмет дополнительных точек монтирования val mountsFile = File("/proc/mounts") if (mountsFile.exists()) { mountsFile.readLines().forEach { line -> @@ -351,7 +327,7 @@ class USBVirusScanner { try { // Проверяем установлен ли ClamAV - val checkProcess = ProcessBuilder("which", "clamscan").start() + val checkProcess = ProcessBuilder("which", "clamdscan").start() val checkExitCode = checkProcess.waitFor() if (checkExitCode != 0) { @@ -360,11 +336,11 @@ class USBVirusScanner { infectedFiles = emptyList(), virusNames = emptyMap(), exitCode = -1, - error = if (isDebug) "ClamAV не установлен. Установите: sudo apt install clamav" else "" + error = if (isDebug) "ClamAV не установлен." else "" ) } - // Проверяем существование пути + // Проверка существования пути val pathFile = File(path) if (!pathFile.exists() || !pathFile.isDirectory) { return ScanResult( @@ -376,9 +352,9 @@ class USBVirusScanner { ) } - println(if (isDebug) " Запуск clamscan (это может занять некоторое время)..." else "") + println(if (isDebug) " Запуск clamdcan..." else "") - // Запускаем ClamAV + // Запуск непосредственной антивирусной проверки val processBuilder = ProcessBuilder( "clamdscan", "--multiscan", @@ -393,7 +369,7 @@ class USBVirusScanner { val output = process.inputStream.bufferedReader().readText() val exitCode = process.waitFor() - // Парсим вывод + // Парс вывода output.lines().forEach { line -> if (line.contains(" FOUND")) { val colonIndex = line.indexOf(": ") @@ -415,7 +391,7 @@ class USBVirusScanner { ) } catch (e: Exception) { - println(if (isDebug) "Ошибка при выполнении clamscan: ${e.message}" else "") + println(if (isDebug) "Ошибка при выполнении clamdscan: ${e.message}" else "") return ScanResult( isInfected = false, infectedFiles = emptyList(), @@ -426,47 +402,6 @@ class USBVirusScanner { } } - private fun saveScanLog(results: List) { - try { - val logDir = File("/home/${System.getProperty("user.name")}/usb-scanner-logs") - if (!logDir.exists()) { - logDir.mkdirs() - } - - val timestamp = System.currentTimeMillis() - val logFile = File(logDir, "scan_$timestamp.log") - - logFile.bufferedWriter().use { writer -> - writer.write("=== USB Virus Scanner Log ===\n") - writer.write("Time: ${java.time.LocalDateTime.now()}\n\n") - - results.forEachIndexed { index, result -> - writer.write("Device ${index + 1}:\n") - if (result.isInfected) { - writer.write("Status: INFECTED\n") - writer.write("Found ${result.infectedFiles.size} infected files:\n") - result.infectedFiles.take(20).forEach { file -> - writer.write(" $file: ${result.virusNames[file]}\n") - } - if (result.infectedFiles.size > 20) { - writer.write(" ... and ${result.infectedFiles.size - 20} more files\n") - } - } else if (result.error != null) { - writer.write("Status: ERROR\n") - writer.write("Error: ${result.error}\n") - } else { - writer.write("Status: CLEAN\n") - } - writer.write("\n") - } - } - - println(if (isDebug) "📝 Лог сохранён: ${logFile.absolutePath}" else "") - } catch (e: Exception) { - println(if (isDebug) "Ошибка сохранения лога: ${e.message}" else "") - } - } - suspend fun sambaStartSharing() { try { currentState = SystemState.SAMBA @@ -496,10 +431,9 @@ class USBVirusScanner { process = processBuilder.start() scanJob?.cancel() currentState = SystemState.IDLE - } catch (e: Exception) {} + } catch (_: Exception) {} } - fun unmount() { for (i in 0..9) { val path = if (i == 0) "/media/usb" else "/media/usb$i" @@ -517,7 +451,7 @@ class USBVirusScanner { } } - + fun shutdown() { println(if (isDebug) "\nЗавершение работы..." else "") isRunning = false @@ -527,17 +461,13 @@ class USBVirusScanner { scope.cancel() - // Выключаем все светодиоды try { if (::greenLed.isInitialized) { greenLed.setValue(0) yellowLed.setValue(0) redLed.setValue(0) } - } catch (e: Exception) { - // Игнорируем ошибки при закрытии - } - + } catch (_: Exception) {} println(if (isDebug) "✅ Система остановлена" else "") } } @@ -581,7 +511,7 @@ fun scheduleUpdaterAt3AM() { TimeUnit.MILLISECONDS ) - println("Планировщик запущен. Первый запуск через ${initialDelay / 1000 / 60} минут") + println(if (isDebug) "Планировщик обновления антивирусных баз запущен." else "") } fun antivirusDatabaseUpdater() { @@ -605,14 +535,7 @@ fun main(args: Array) { if (args.contains("--debug")) { DebugMode.enableDebugging() } - scheduleUpdaterAt3AM() - - println(if (isDebug) "Зелёный - ${PinConfig.GREEN_LED}" else "") - println(if (isDebug) "Жёлтый - ${PinConfig.YELLOW_LED}" else "") - println(if (isDebug) "Красный - ${PinConfig.RED_LED}" else "") - println(if (isDebug) "Кнопка - ${PinConfig.BUTTON}" else "") - val scanner = USBVirusScanner() Runtime.getRuntime().addShutdownHook(Thread { @@ -623,36 +546,24 @@ fun main(args: Array) { scanner.initialize() val buttonListener = ButtonListener() - - buttonListener.addClickListener { event -> + buttonListener.addClickListener { _ -> scanner.startScan() } - - buttonListener.addLongPressListener { event -> + buttonListener.addLongPressListener { _ -> scanner.sambaShutdown() } buttonListener.startListening() println( - if (isDebug) """ - ═══════════════════════════════════════ - USB Virus Scanner готов к работе - ═══════════════════════════════════════ - 📌 Вставьте флешку и нажмите кнопку - 📌 Зелёный LED мигает - режим ожидания - 📌 Жёлтый LED мигает - идёт проверка - 📌 Зелёный LED горит - флешка чиста - 📌 Красный LED горит - найдены вирусы - 📌 Для выхода нажмите Ctrl+C - """.trimIndent() else "" + if (isDebug) "!!! ПРОГРАММА ПОЛНОСТЬЮ ГОТОВА К РАБОТЕ !!!" else "" ) while (true) { Thread.sleep(1000) } } catch (e: Exception) { - println(if (isDebug) "❌ Критическая ошибка: ${e.message}" else "") + println(if (isDebug) "Критическая ошибка: ${e.message}" else "") if (isDebug) e.printStackTrace() if (isDebug) println("Общий Exception") scanner.shutdown()