From cb5cafb8f696fd8accffc5fa8a124a8aec82de36 Mon Sep 17 00:00:00 2001 From: RoyceDa Date: Tue, 3 Feb 2026 20:11:37 +0200 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B0=D1=87=D0=B0=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=B0=20(?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=BD=D0=B0=D1=80=D1=83=D1=88=D0=B0=D0=B5=D1=82?= =?UTF-8?q?=D1=81=D1=8F=20=D0=BF=D1=80=D0=B8=D0=BD=D1=86=D0=B8=D0=BF=20?= =?UTF-8?q?=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=81=D1=82=D0=B2=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D0=B8),=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=BB=D0=BE=D0=B3=D0=B3=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5,=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=BD=20Boot?= =?UTF-8?q?=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D1=8B=D0=B9=20=D1=81=D0=BE?= =?UTF-8?q?=D0=B1=D0=B8=D1=80=D0=B0=D0=B5=D1=82=20=D0=B2=D1=81=D0=B5=20?= =?UTF-8?q?=D0=B4=D1=80=D0=B5=D0=B2=D0=BE=20=D0=BF=D1=80=D0=B8=D0=BB=D0=BE?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F,=20=D1=83=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D1=88=D0=B5=D0=BD=20=D0=BF=D1=80=D0=BE=D1=82=D0=BE=D0=BA=D0=BE?= =?UTF-8?q?=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/rosetta/im/AppContext.java | 22 ------ src/main/java/com/rosetta/im/Boot.java | 47 ++++++++++-- .../java/com/rosetta/im/ContextBuilder.java | 23 ------ src/main/java/com/rosetta/im/Main.java | 18 +++-- .../im/executors/Executor0Handshake.java | 16 ++-- .../im/listeners/ServerStopListener.java | 24 +++++- .../java/com/rosetta/im/logger/Logger.java | 74 +++++++++++++++++++ .../com/rosetta/im/logger/enums/Color.java | 13 ++++ .../com/rosetta/im/logger/enums/LogLevel.java | 12 +++ src/main/java/io/orprotocol/Server.java | 28 +------ .../io/orprotocol/packet/PacketExecutor.java | 11 --- .../io/orprotocol/packet/PacketManager.java | 6 +- 12 files changed, 188 insertions(+), 106 deletions(-) delete mode 100644 src/main/java/com/rosetta/im/AppContext.java delete mode 100644 src/main/java/com/rosetta/im/ContextBuilder.java create mode 100644 src/main/java/com/rosetta/im/logger/Logger.java create mode 100644 src/main/java/com/rosetta/im/logger/enums/Color.java create mode 100644 src/main/java/com/rosetta/im/logger/enums/LogLevel.java diff --git a/src/main/java/com/rosetta/im/AppContext.java b/src/main/java/com/rosetta/im/AppContext.java deleted file mode 100644 index 960adb9..0000000 --- a/src/main/java/com/rosetta/im/AppContext.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.rosetta.im; - -import com.rosetta.im.event.EventManager; - -import io.orprotocol.Context; - -/** - * Контекст приложения, хранящий глобальные объекты - */ -public class AppContext extends Context { - - private EventManager eventManager; - - public AppContext(EventManager eventManager) { - this.eventManager = eventManager; - } - - public EventManager getEventManager() { - return eventManager; - } - -} diff --git a/src/main/java/com/rosetta/im/Boot.java b/src/main/java/com/rosetta/im/Boot.java index 24fbc3c..6d426c6 100644 --- a/src/main/java/com/rosetta/im/Boot.java +++ b/src/main/java/com/rosetta/im/Boot.java @@ -1,44 +1,81 @@ package com.rosetta.im; +import com.rosetta.im.event.EventManager; import com.rosetta.im.executors.Executor0Handshake; +import com.rosetta.im.listeners.ServerStopListener; +import com.rosetta.im.logger.Logger; +import com.rosetta.im.logger.enums.Color; +import com.rosetta.im.logger.enums.LogLevel; import com.rosetta.im.packet.Packet0Handshake; import io.orprotocol.packet.PacketManager; +/** + * Boot отвечает за инициализацию всех пакетов и их обработчиков, + * а так же событий приложения. Этот Boot отвечает за приложение, а не за протокол. + */ public class Boot { private PacketManager packetManager; + private EventManager eventManager; + private Logger logger; public Boot() { this.packetManager = new PacketManager(); + this.eventManager = new EventManager(); + this.logger = new Logger(LogLevel.INFO); } + /** + * Получить менеджер пакетов приложения + * @return PacketManager + */ public PacketManager getPacketManager() { return this.packetManager; } /** - * Инициализация всех пакетов и их обработчиков + * Получить менеджер событий приложения + * @return EventManager + */ + public EventManager getEventManager() { + return this.eventManager; + } + + /** + * Получить логгер приложения + * @return Logger + */ + public Logger getLogger() { + return this.logger; + } + + /** + * Регистрация пакетов, обработчиков, событий приложения + * @return Boot */ public Boot bootstrap() { this.registerAllPackets(); this.registerAllExecutors(); + this.registerAllEvents(); this.printBootMessage(); return this; } + private void registerAllEvents() { + this.eventManager.registerListener(new ServerStopListener(this.logger)); + } + private void registerAllPackets() { this.packetManager.registerPacket(0, Packet0Handshake.class); } private void registerAllExecutors() { - this.packetManager.registerExecutor(0, Executor0Handshake.class); + this.packetManager.registerExecutor(0, new Executor0Handshake(this.eventManager)); } private void printBootMessage() { - System.out.println("Bootstrapping completed. All packets and executors are registered."); - System.out.println("Total packets registered: " + this.packetManager.totalPackets()); - System.out.println("Total executors registered: " + this.packetManager.totalExecutors()); + this.logger.log(LogLevel.INFO, Color.GREEN + "Boot successful complete"); } } diff --git a/src/main/java/com/rosetta/im/ContextBuilder.java b/src/main/java/com/rosetta/im/ContextBuilder.java deleted file mode 100644 index 471690a..0000000 --- a/src/main/java/com/rosetta/im/ContextBuilder.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.rosetta.im; - -import com.rosetta.im.event.EventManager; -import com.rosetta.im.listeners.ServerStopListener; - -public class ContextBuilder { - - private AppContext appContext; - - public ContextBuilder() {} - - public AppContext buildContext() { - /** - * Создание глобальных объектов приложения - */ - EventManager eventManager = new EventManager(); - eventManager.registerListener(new ServerStopListener()); - - this.appContext = new AppContext(eventManager); - return this.appContext; - } - -} diff --git a/src/main/java/com/rosetta/im/Main.java b/src/main/java/com/rosetta/im/Main.java index b4b2517..d9f8547 100644 --- a/src/main/java/com/rosetta/im/Main.java +++ b/src/main/java/com/rosetta/im/Main.java @@ -2,25 +2,27 @@ package com.rosetta.im; import io.orprotocol.Server; import io.orprotocol.Settings; -import io.orprotocol.packet.PacketManager; public class Main { public static void main(String[] args) { /** * Регистрация всех пакетов и их обработчиков */ - Boot boot = new Boot(); - PacketManager manager = boot.bootstrap().getPacketManager(); + Boot boot = new Boot().bootstrap(); /** - * Загрузка настроек сервера, сборка контекста приложения + * Загрузка настроек сервера */ Settings settings = new Settings(8881, 30); - AppContext appContext = new ContextBuilder().buildContext(); - ServerAdapter serverAdapter = new ServerAdapter(appContext.getEventManager()); /** - * Запуск сервера на порту 8881 + * Создание адаптера сервера для трансляции событий протокола в события приложения, + * обрабатываются основыне события такие как запуск/остановка сервера, + * подключение/отключение клиентов, ошибки сервера и получение пакетов */ - Server server = new Server(settings, manager, appContext, serverAdapter); + ServerAdapter serverAdapter = new ServerAdapter(boot.getEventManager()); + /** + * Запуск сервера + */ + Server server = new Server(settings, boot.getPacketManager(), serverAdapter); server.start(); } } \ No newline at end of file diff --git a/src/main/java/com/rosetta/im/executors/Executor0Handshake.java b/src/main/java/com/rosetta/im/executors/Executor0Handshake.java index 910c1b1..b3939ee 100644 --- a/src/main/java/com/rosetta/im/executors/Executor0Handshake.java +++ b/src/main/java/com/rosetta/im/executors/Executor0Handshake.java @@ -1,6 +1,5 @@ package com.rosetta.im.executors; -import com.rosetta.im.AppContext; import com.rosetta.im.Configuration; import com.rosetta.im.Failures; import com.rosetta.im.client.tags.ECIAuthentificate; @@ -9,6 +8,7 @@ import com.rosetta.im.database.entity.Device; import com.rosetta.im.database.entity.User; import com.rosetta.im.database.repository.DeviceRepository; import com.rosetta.im.database.repository.UserRepository; +import com.rosetta.im.event.EventManager; import com.rosetta.im.event.events.handshake.HandshakeCompletedEvent; import com.rosetta.im.event.events.handshake.HandshakeDeviceConfirmEvent; import com.rosetta.im.event.events.handshake.HandshakeFailedEvent; @@ -27,6 +27,11 @@ public class Executor0Handshake extends PacketExecutor { private final UserRepository userRepository = new UserRepository(); private final DeviceRepository deviceRepository = new DeviceRepository(); private final DeviceService deviceService = new DeviceService(deviceRepository); + private final EventManager eventManager; + + public Executor0Handshake(EventManager eventManager) { + this.eventManager = eventManager; + } @Override @@ -39,7 +44,6 @@ public class Executor0Handshake extends PacketExecutor { String deviceName = handshake.getDeviceName(); String deviceOs = handshake.getDeviceOs(); int protocolVersion = handshake.getProtocolVersion(); - AppContext context = (AppContext) this.getContext(); /** * Получаем информацию об аутентификации клиента * используя возможности ECI тэгов. @@ -95,7 +99,7 @@ public class Executor0Handshake extends PacketExecutor { /** * Вызываем событие завершения хэндшейка */ - boolean cancelled = context.getEventManager().callEvent( + boolean cancelled = this.eventManager.callEvent( new HandshakeCompletedEvent(publicKey, privateKey, device, eciTag, client) ); if(cancelled) { @@ -120,7 +124,7 @@ public class Executor0Handshake extends PacketExecutor { /** * Приватный ключ не совпадает, отключаем клиента */ - context.getEventManager().callEvent(new HandshakeFailedEvent(publicKey, privateKey, device, authentificate, client)); + eventManager.callEvent(new HandshakeFailedEvent(publicKey, privateKey, device, authentificate, client)); client.disconnect(Failures.AUTHENTIFICATION_ERROR); return; } @@ -139,7 +143,7 @@ public class Executor0Handshake extends PacketExecutor { /** * Вызываем событие подтверждения устройства */ - context.getEventManager().callEvent( + this.eventManager.callEvent( new HandshakeDeviceConfirmEvent(publicKey, privateKey, device, authentificate, client) ); /** @@ -179,7 +183,7 @@ public class Executor0Handshake extends PacketExecutor { /** * Вызываем событие завершения хэндшейка */ - boolean cancelled = context.getEventManager().callEvent( + boolean cancelled = this.eventManager.callEvent( new HandshakeCompletedEvent(publicKey, privateKey, device, eciTag, client) ); if(cancelled) { diff --git a/src/main/java/com/rosetta/im/listeners/ServerStopListener.java b/src/main/java/com/rosetta/im/listeners/ServerStopListener.java index e56f16a..e0d459b 100644 --- a/src/main/java/com/rosetta/im/listeners/ServerStopListener.java +++ b/src/main/java/com/rosetta/im/listeners/ServerStopListener.java @@ -6,6 +6,8 @@ import com.rosetta.im.database.repository.DeviceRepository; import com.rosetta.im.event.EventHandler; import com.rosetta.im.event.Listener; import com.rosetta.im.event.events.ServerStopEvent; +import com.rosetta.im.logger.Logger; +import com.rosetta.im.logger.enums.Color; import com.rosetta.im.service.services.DeviceService; import io.orprotocol.Server; @@ -17,25 +19,39 @@ import io.orprotocol.client.Client; */ public class ServerStopListener implements Listener { - private static final DeviceRepository deviceRepository = new DeviceRepository(); - private static final DeviceService deviceService = new DeviceService(deviceRepository); + private final DeviceRepository deviceRepository = new DeviceRepository(); + private final DeviceService deviceService = new DeviceService(deviceRepository); + private Logger logger; + + public ServerStopListener(Logger logger) { + this.logger = logger; + } + @EventHandler public void onServerStop(ServerStopEvent event) { Server server = event.getServer(); - System.out.println("Server is stopping. Please wait..."); + this.logger.info(Color.RED + "Сервер останавливается, обновляем время последней активности устройств клиентов..."); for(Client client : server.getClients()){ ECIAuthentificate eciAuth = client.getTag(ECIAuthentificate.class); if(eciAuth == null || !eciAuth.hasAuthorized()){ + /** + * Если клиент не авторизован, пропускаем его, таким клиентам не нужно + * обновлять время активности устройства + */ continue; } ECIDevice eciDevice = client.getTag(ECIDevice.class); if(eciDevice == null){ + /** + * Если у клиента нет тега устройства, пропускаем его + * такого быть не должно, но на всякий случай + */ continue; } deviceService.updateDeviceLeaveTime(eciDevice.getDeviceId()); } - System.out.println("Server stopped successfully."); + this.logger.info(Color.RED + "Время последней активности устройств клиентов обновлено."); } } diff --git a/src/main/java/com/rosetta/im/logger/Logger.java b/src/main/java/com/rosetta/im/logger/Logger.java new file mode 100644 index 0000000..46586f0 --- /dev/null +++ b/src/main/java/com/rosetta/im/logger/Logger.java @@ -0,0 +1,74 @@ +package com.rosetta.im.logger; + +import java.time.Instant; + +import com.rosetta.im.logger.enums.Color; +import com.rosetta.im.logger.enums.LogLevel; + +public class Logger { + + private long startTime = 0; + private LogLevel logLevel; + + public Logger(LogLevel logLevel) { + this.logLevel = logLevel; + startTime = (System.currentTimeMillis() / 1000); + } + + /** + * Логирование сообщения с указанным уровнем логирования + * @param logLevel уровень логирования + * @param message сообщение для логирования + */ + public void log(LogLevel logLevel, String message) { + if (!this.logLevel.allows(logLevel)) { + return; + } + long currentTimeMs = System.currentTimeMillis(); + long currentTime = currentTimeMs / 1000; + long elapsedTime = currentTime - startTime; + String currentDateISO = Instant.ofEpochMilli(currentTimeMs).toString(); + System.out.println(getColorForLogLevel(logLevel) + "["+ logLevel.toString() +"]" + Color.RESET + "[" + currentDateISO + "]" + Color.CYAN + "[+" + elapsedTime + "] " + Color.WHITE + message + Color.RESET); + } + + /** + * Логирование информационного сообщения + * @param message сообщение для логирования + */ + public void info(String message) { + this.log(LogLevel.INFO, message); + } + + /** + * Логирование предупреждающего сообщения + * @param message сообщение для логирования + */ + public void warn(String message) { + this.log(LogLevel.WARN, message); + } + + /** + * Логирование сообщения об ошибке + * @param message сообщение для логирования + */ + public void error(String message) { + this.log(LogLevel.ERROR, message); + } + + /** + * Логирование отладочного сообщения + * @param message сообщение для логирования + */ + public void debug(String message) { + this.log(LogLevel.DEBUG, message); + } + + private String getColorForLogLevel(LogLevel logLevel) { + return switch (logLevel) { + case INFO -> Color.BLUE; + case WARN -> Color.YELLOW; + case ERROR -> Color.RED; + case DEBUG -> Color.PURPLE; + }; + } +} diff --git a/src/main/java/com/rosetta/im/logger/enums/Color.java b/src/main/java/com/rosetta/im/logger/enums/Color.java new file mode 100644 index 0000000..2e9a6e2 --- /dev/null +++ b/src/main/java/com/rosetta/im/logger/enums/Color.java @@ -0,0 +1,13 @@ +package com.rosetta.im.logger.enums; + +public final class Color { + public static final String RESET = "\u001B[0m"; + public static final String BLACK = "\u001B[30m"; + public static final String RED = "\u001B[31m"; + public static final String GREEN = "\u001B[32m"; + public static final String YELLOW = "\u001B[33m"; + public static final String BLUE = "\u001B[34m"; + public static final String PURPLE = "\u001B[35m"; + public static final String CYAN = "\u001B[36m"; + public static final String WHITE = "\u001B[37m"; +} diff --git a/src/main/java/com/rosetta/im/logger/enums/LogLevel.java b/src/main/java/com/rosetta/im/logger/enums/LogLevel.java new file mode 100644 index 0000000..759b415 --- /dev/null +++ b/src/main/java/com/rosetta/im/logger/enums/LogLevel.java @@ -0,0 +1,12 @@ +package com.rosetta.im.logger.enums; + +public enum LogLevel { + INFO, + WARN, + ERROR, + DEBUG; + + public boolean allows(LogLevel other) { + return this.ordinal() <= other.ordinal(); + } +} diff --git a/src/main/java/io/orprotocol/Server.java b/src/main/java/io/orprotocol/Server.java index a14416c..ed2e4b3 100644 --- a/src/main/java/io/orprotocol/Server.java +++ b/src/main/java/io/orprotocol/Server.java @@ -23,7 +23,6 @@ public class Server extends WebSocketServer { private PacketManager packetManager; private Settings settings; private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - private Context context; private ServerListener listener; private ThreadLocker threadLocker = new ThreadLocker(); @@ -38,33 +37,17 @@ public class Server extends WebSocketServer { this.packetManager = packetManager; } - /** - * Конструктор сервера с объектом прикрепления - * @param settings базовые настройки серверера - * @param packetManager менеджер пакетов (обработчиков и зарегистрированных пакетов) - * @param context вложение которое будет передаваться всем серрверным обработчикам пакетов, - * может быть использовано для передачи контекста приложения - */ - public Server(Settings settings, PacketManager packetManager, Context context) { - super(new InetSocketAddress(settings.port)); - this.settings = settings; - this.packetManager = packetManager; - this.context = context; - } - /** * Конструктор сервера с объектом прикрепления и слушателем событий сервера * @param settings базовые настройки серверера * @param packetManager менеджер пакетов (обработчиков и зарегистрированных пакетов) - * @param context вложение которое будет передаваться всем серрверным обработчикам пакетов, * @param listener слушатель событий сервера * может быть использовано для передачи контекста приложения */ - public Server(Settings settings, PacketManager packetManager, Context context, ServerListener listener) { + public Server(Settings settings, PacketManager packetManager, ServerListener listener) { super(new InetSocketAddress(settings.port)); this.settings = settings; this.packetManager = packetManager; - this.context = context; this.listener = listener; } @@ -138,10 +121,8 @@ public class Server extends WebSocketServer { /** * Получаем обработчик пакета и вызываем его метод обработки. */ - Class executorClass = this.packetManager.getExecutors().get(packetId); - PacketExecutor executor = executorClass.getConstructor().newInstance(); + PacketExecutor executor = this.packetManager.getExecutors().get(packetId); executor.settings = this.settings; - executor.context = this.context; if(listener != null && !listener.onPacketReceived(this, client, packet)) { /** * Если слушатель сервера вернул false, пакет не обрабатываем. @@ -151,7 +132,7 @@ public class Server extends WebSocketServer { /** * Проверяем наличие блокировки для данного пакета и ключа в аннотации @Lock. */ - if(!threadLocker.acquireLock(packet, executorClass)) { + if(!threadLocker.acquireLock(packet, executor.getClass())) { /** * Если блокировка уже существует, значит другой поток обрабатывает пакет * с таким же значением lockFor, отклоняем текущий пакет. @@ -164,7 +145,7 @@ public class Server extends WebSocketServer { /** * Снимаем блокировку после обработки пакета. */ - threadLocker.releaseLock(packet, executorClass); + threadLocker.releaseLock(packet, executor.getClass()); } } catch (Exception e) { System.out.println("Error while processing packet " + packetClass.getName()); @@ -244,7 +225,6 @@ public class Server extends WebSocketServer { /** * Останавливаем сервер при завершении работы и вызываем слушатели остановки сервера. */ - System.out.println("JVM Shutdown detected, stopping server..."); this.listener.onServerStop(this); })); } diff --git a/src/main/java/io/orprotocol/packet/PacketExecutor.java b/src/main/java/io/orprotocol/packet/PacketExecutor.java index d2ad093..cb75c69 100644 --- a/src/main/java/io/orprotocol/packet/PacketExecutor.java +++ b/src/main/java/io/orprotocol/packet/PacketExecutor.java @@ -1,6 +1,5 @@ package io.orprotocol.packet; -import io.orprotocol.Context; import io.orprotocol.ProtocolException; import io.orprotocol.Settings; import io.orprotocol.client.Client; @@ -10,7 +9,6 @@ import io.orprotocol.client.Client; */ public abstract class PacketExecutor { public Settings settings; - public Context context; /** * Настройки сервера. @@ -19,15 +17,6 @@ public abstract class PacketExecutor { public Settings getSettings() { return settings; } - - /** - * Контекст приложения переданный при создании сервера. - * @return контекст - */ - public Context getContext() { - return context; - } - /** * Вызывается при получении пакета от клиента. * @param packet Пакет, полученный от клиента. diff --git a/src/main/java/io/orprotocol/packet/PacketManager.java b/src/main/java/io/orprotocol/packet/PacketManager.java index a193654..d2bf5cf 100644 --- a/src/main/java/io/orprotocol/packet/PacketManager.java +++ b/src/main/java/io/orprotocol/packet/PacketManager.java @@ -8,7 +8,7 @@ import java.util.HashMap; public class PacketManager { private HashMap> packets; - private HashMap> executors; + private HashMap executors; public PacketManager() { this.packets = new HashMap<>(); @@ -46,7 +46,7 @@ public class PacketManager { * Возвращает зарегистрированные исполнители пакетов. * @return Хэш-карта зарегистрированных исполнителей пакетов. */ - public HashMap> getExecutors() { + public HashMap getExecutors() { return this.executors; } @@ -73,7 +73,7 @@ public class PacketManager { * @param packetId ID пакета * @param executor Обработчик пакета */ - public void registerExecutor(int packetId, Class executor) { + public void registerExecutor(int packetId, PacketExecutor executor) { if (this.executors == null) { this.executors = new HashMap<>(); }