Server-Sent Events Plugin System - HrFiskalizator
Verzija 1.0 | Real-time Communication & Monitoring
SSE (Server-Sent Events) sustav u HrFiskalizatoru omogućava real-time komunikaciju između servera i klijenata putem standardnog HTTP protokola. Sustav je dizajniran za visoku performansu, skalabilnost i jednostavnost korištenja.
Komponenta | Funkcija | Lokacija |
---|---|---|
SSEHandler.java | Glavni server handler | src/fiskalizacija/ |
sse.js | JavaScript monitoring client | web/ |
sse.php | Web monitoring interface | web/ |
Plugin JARs | Proširivi plugin sustav | SSEPLUGINS/ |
SSE sustav pruža RESTful API za dohvaćanje informacija i statistika.
{ "clients": [ { "clientId": "web-client-1759588812045", "clientIP": "192.168.1.5", "connected": true, "tasks": ["status", "sms", "echo"] } ], "count": 1 }
{ "systemInfo": { "totalTasks": 7, "activeClients": 2, "pluginTasks": 3 }, "allTasks": ["notification", "sms", "echo", "status"], "taskSubscribers": { "sms": 2, "echo": 2, "status": 2 } }
// Primjer konekcije const eventSource = new EventSource('/sse?tasks=sms,status,echo'); eventSource.onmessage = function(event) { const data = JSON.parse(event.data); console.log('Received:', data); };
Web-based monitoring interface omogućava real-time praćenje SSE sustava kroz intuitivno sučelje.
Osnovne informacije o SSE serveru, verziji API-ja i dostupnim endpointovima.
Real-time prikaz aktivnih klijenata s IP adresama i pretplaćenim taskovima.
Lista svih dostupnih taskova podijeljenih na sistemske i plugin taskove.
Pregled svih registriranih pluginova s njihovim statusom i verzijama.
Detaljne statistike sustava uključujući performance podatke.
Mrežne statistike, analiza konekcija po IP adresama i taskovima.
Ikona | Funkcija | Opis |
---|---|---|
🔄 | Refresh Stats | Ručno osvježavanje svih statistika |
🗑️ | Clear Editor | Brisanje sadržaja editora |
📄 | Toggle Format | Prebacivanje između čitljivog i JSON formata |
📋 | Copy to Clipboard | Kopiranje statistika u clipboard |
💾 | Save Stats | Spremanje statistika u datoteku |
⏰ | Auto-refresh | Automatsko osvježavanje (10s interval) |
Plugin arhitektura omogućava proširivanje funkcionalnosti SSE sustava kroz dinamički učitane JAR datoteke.
// Osnovna plugin klasa public class MyPlugin { public String getTaskName() { return "my-custom-task"; } public String getDescription() { return "Opis mog plugina"; } public String getVersion() { return "1.0.0"; } public boolean isEnabled() { return true; } public String executeTask(String parameters) { // Plugin logika return "Rezultat izvršavanja"; } }
Plugin | Task Name | Opis |
---|---|---|
EchoPlugin | echo | Vraća poslane podatke (test plugin) |
HelloWorldPlugin | hello | Demonstracija osnovnih funkcionalnosti |
SmsPlugin | sms | SMS poruke s priority sustavom |
SSE sustav upravlja klijentskim konekcijama i omogućava praćenje njihovog statusa u realnom vremenu.
Klijent se spaja na SSE endpoint s listom željenih taskova.
Server registrira klijenta i dodjeljuje jedinstveni ID.
Klijent se pretplaćuje na određene taskove za primanje eventi.
Real-time primanje eventi na osnovu pretplaćenih taskova.
Za svakog klijenta sustav prati sljedeće informacije:
// Spajanje na SSE stream const eventSource = new EventSource('/sse?tasks=sms,status,echo'); // Rukovanje događajima eventSource.onopen = function(event) { console.log('SSE connection opened'); }; eventSource.onmessage = function(event) { const data = JSON.parse(event.data); console.log('Received message:', data); // Obrada različitih tipova poruka switch(data.task) { case 'sms': handleSmsMessage(data); break; case 'status': updateStatus(data); break; case 'echo': displayEcho(data); break; } }; eventSource.onerror = function(event) { console.error('SSE connection error:', event); // Automatska reconnection logika setTimeout(() => { eventSource.close(); connectToSSE(); // Ponovni pokušaj spajanja }, 5000); };
Task sistem omogućava organizaciju i distribuciju različitih tipova poruka kroz SSE komunikaciju.
Tip | Opis | Primjeri |
---|---|---|
System Tasks | Ugrađeni sistemski taskovi | notification, status, task-update |
Plugin Tasks | Taskovi definirani u pluginovima | sms, echo, hello |
Custom Tasks | Prilagođeni taskovi aplikacije | user-defined tasks |
Klijenti se mogu pretplatiti na jedan ili više taskova:
// Pretplata na pojedinačni task const sseClient = new EventSource('/sse?tasks=sms'); // Pretplata na više taskova const sseClient = new EventSource('/sse?tasks=sms,status,echo'); // Pretplata na sve dostupne taskove const sseClient = new EventSource('/sse?tasks=*');
Sve SSE poruke slijede standardni JSON format:
{ "task": "sms", "timestamp": "2025-10-04T15:30:00Z", "data": { "message": "Test SMS poruka", "priority": "high", "sender": "system" }, "clientId": "web-client-1759588812045", "eventId": "evt-12345" }
Sustav prati detaljne statistike za svaki task:
SSE sustav može se konfigurirati kroz različite parametre i postavke.
Parametar | Zadana Vrijednost | Opis |
---|---|---|
SSE_PORT | Port HrFiskalizatora | Port za SSE server |
MAX_CLIENTS | 1000 | Maksimalni broj klijената |
HEARTBEAT_INTERVAL | 30s | Interval heartbeat poruka |
PLUGIN_DIR | SSEPLUGINS/ | Folder za plugin datoteke |
LOG_LEVEL | INFO | Razina logiranja |
// JavaScript client konfiguracija const sseConfig = { url: '/sse', tasks: ['sms', 'status'], reconnectInterval: 5000, maxReconnectAttempts: 10, heartbeatTimeout: 45000 }; // PHP konfiguracija $sseConfig = [ 'base_url' => 'http://localhost:8449', 'timeout' => 30, 'retry_count' => 3 ];
Pluginovi mogu imati vlastite konfiguracijske datoteke:
// plugin.properties plugin.name=SmsPlugin plugin.version=1.0.0 plugin.enabled=true plugin.priority=normal plugin.timeout=10000 # SMS specifične postavke sms.provider=twillio sms.api_key=your_api_key sms.from_number=+1234567890
Mogući uzroci:
Rješenje:
Mogući uzroci:
Rješenje:
Network tab za praćenje SSE konekcije
Console za JavaScript greške
Real-time statistike
Client i plugin status
Detaljno logiranje eventi
Error tracking
Test endpoints direktno
Provjeri JSON odgovore
<!DOCTYPE html> <html> <head> <title>SSE Chat Example</title> </head> <body> <div id="messages"></div> <input type="text" id="messageInput" placeholder="Upišite poruku..."> <button onclick="sendMessage()">Pošalji</button> <script> // Spoji se na SSE const eventSource = new EventSource('/sse?tasks=chat'); eventSource.onmessage = function(event) { const data = JSON.parse(event.data); if (data.task === 'chat') { displayMessage(data.data.message, data.data.user); } }; function displayMessage(message, user) { const messagesDiv = document.getElementById('messages'); messagesDiv.innerHTML += `<p><strong>${user}:</strong> ${message}</p>`; } function sendMessage() { const input = document.getElementById('messageInput'); const message = input.value.trim(); if (message) { // Pošalji poruku preko API-ja fetch('/api/chat/send', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: message, user: 'Anonymous' }) }); input.value = ''; } } </script> </body> </html>
// React komponenta za status dashboard import React, { useState, useEffect } from 'react'; function StatusDashboard() { const [status, setStatus] = useState({}); const [connected, setConnected] = useState(false); useEffect(() => { const eventSource = new EventSource('/sse?tasks=status,monitoring'); eventSource.onopen = () => setConnected(true); eventSource.onclose = () => setConnected(false); eventSource.onmessage = (event) => { const data = JSON.parse(event.data); switch(data.task) { case 'status': updateSystemStatus(data.data); break; case 'monitoring': updateMonitoringData(data.data); break; } }; return () => eventSource.close(); }, []); const updateSystemStatus = (data) => { setStatus(prev => ({ ...prev, system: data })); }; const updateMonitoringData = (data) => { setStatus(prev => ({ ...prev, monitoring: data })); }; return ( <div className="dashboard"> <h2>System Status {connected ? '🟢' : '🔴'}</h2> <div className="status-grid"> <div className="status-card"> <h3>CPU Usage</h3> <p>{status.system?.cpu || 0}%</p> </div> <div className="status-card"> <h3>Memory Usage</h3> <p>{status.system?.memory || 0}%</p> </div> <div className="status-card"> <h3>Active Users</h3> <p>{status.monitoring?.activeUsers || 0}</p> </div> </div> </div> ); } export default StatusDashboard;
<?php /** * PHP klasa za komunikaciju s SSE sustavom */ class SSEClient { private $baseUrl; private $timeout; public function __construct($baseUrl = 'http://localhost:8449', $timeout = 30) { $this->baseUrl = $baseUrl; $this->timeout = $timeout; } /** * Pošalji poruku preko SSE sustava */ public function sendMessage($task, $data, $targetClients = null) { $payload = [ 'task' => $task, 'data' => $data, 'timestamp' => date('c'), 'targets' => $targetClients ]; $context = stream_context_create([ 'http' => [ 'method' => 'POST', 'header' => 'Content-Type: application/json', 'content' => json_encode($payload), 'timeout' => $this->timeout ] ]); $response = file_get_contents( $this->baseUrl . '/api/sse/send', false, $context ); return json_decode($response, true); } /** * Dohvati statistike SSE sustava */ public function getStats() { $response = file_get_contents( $this->baseUrl . '/sseapi/stats', false, stream_context_create([ 'http' => ['timeout' => $this->timeout] ]) ); return json_decode($response, true); } /** * Dohvati aktivne klijente */ public function getActiveClients() { $response = file_get_contents( $this->baseUrl . '/sseapi/clients', false, stream_context_create([ 'http' => ['timeout' => $this->timeout] ]) ); return json_decode($response, true); } } // Primjer korištenja $sse = new SSEClient(); // Pošalji SMS notifikaciju $sse->sendMessage('sms', [ 'message' => 'Nova fiskalna potvrda kreirana', 'priority' => 'high', 'recipient' => '+385981234567' ]); // Pošalji status update $sse->sendMessage('status', [ 'status' => 'processing', 'progress' => 75, 'operation' => 'invoice_generation' ]); // Dohvati trenutne statistike $stats = $sse->getStats(); echo "Aktivnih klijenta: " . $stats['systemInfo']['activeClients']; ?>
/** * Primjer custom plugin-a za email notifikacije */ public class EmailNotificationPlugin { public String getTaskName() { return "email"; } public String getDescription() { return "Email notification plugin za slanje obavještenja"; } public String getVersion() { return "1.0.0"; } public boolean isEnabled() { return true; } public String executeTask(String parameters) { try { // Parse JSON parametara JSONObject params = new JSONObject(parameters); String to = params.getString("to"); String subject = params.getString("subject"); String message = params.getString("message"); String priority = params.optString("priority", "normal"); // Pošalji email boolean success = sendEmail(to, subject, message, priority); // Vrati rezultat JSONObject result = new JSONObject(); result.put("success", success); result.put("timestamp", new Date().toInstant().toString()); result.put("recipient", to); return result.toString(); } catch (Exception e) { // Handle greške JSONObject error = new JSONObject(); error.put("success", false); error.put("error", e.getMessage()); return error.toString(); } } private boolean sendEmail(String to, String subject, String message, String priority) { // Implementiraj email slanje logiku // Koristi JavaMail API ili drugi email provider try { Properties props = new Properties(); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.starttls.enable", "true"); props.put("mail.smtp.host", "smtp.gmail.com"); props.put("mail.smtp.port", "587"); Session session = Session.getInstance(props, new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication("your_email", "your_password"); } }); Message emailMessage = new MimeMessage(session); emailMessage.setFrom(new InternetAddress("noreply@hrfiskalizator.com")); emailMessage.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to)); emailMessage.setSubject(subject); emailMessage.setText(message); // Postavi prioritet if ("high".equals(priority)) { emailMessage.setHeader("X-Priority", "1"); } else if ("low".equals(priority)) { emailMessage.setHeader("X-Priority", "5"); } Transport.send(emailMessage); return true; } catch (MessagingException e) { System.err.println("Email sending failed: " + e.getMessage()); return false; } } }