commit 16/06/2025

This commit is contained in:
2025-06-17 16:23:50 +07:00
parent f2bb3500c9
commit c617157a0b
33 changed files with 321 additions and 56 deletions

View File

@@ -1,37 +1,28 @@
<component name="libraryTable"> <component name="libraryTable">
<library name="io.javalin" type="repository"> <library name="io.javalin" type="repository">
<properties maven-id="io.javalin:javalin:5.4.2" /> <properties maven-id="io.javalin:javalin:6.6.0" />
<CLASSES> <CLASSES>
<root url="jar://$PROJECT_DIR$/lib/javalin-5.4.2.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/javalin-6.6.0.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/slf4j-api-2.0.6.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/slf4j-api-2.0.17.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-server-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/jetty-server-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-http-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-util-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-io-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-jakarta-servlet-api-5.0.2.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/jetty-jakarta-servlet-api-5.0.2.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-http-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/websocket-jetty-server-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-util-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/jetty-servlet-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-io-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/jetty-security-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-webapp-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/jetty-webapp-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-servlet-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/jetty-xml-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-security-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/websocket-jetty-api-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-xml-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/websocket-jetty-common-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/websocket-jetty-server-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/websocket-core-common-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/websocket-jetty-common-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/websocket-servlet-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/websocket-core-common-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/websocket-core-server-11.0.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/websocket-servlet-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/kotlin-stdlib-jdk8-1.9.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/websocket-core-server-11.0.14.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/kotlin-stdlib-1.9.25.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-annotations-11.0.14.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-plus-11.0.14.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jakarta.transaction-api-2.0.0.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jetty-jndi-11.0.14.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jakarta.annotation-api-2.1.1.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/asm-9.4.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/asm-commons-9.4.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/asm-tree-9.4.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/websocket-jetty-api-11.0.14.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-stdlib-jdk8-1.7.10.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-stdlib-1.7.10.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-stdlib-common-1.7.10.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/annotations-13.0.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/annotations-13.0.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-stdlib-jdk7-1.7.10.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/kotlin-stdlib-jdk7-1.9.25.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />

11
.idea/libraries/slf4j_simple.xml generated Normal file
View File

@@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="slf4j.simple" type="repository">
<properties maven-id="org.slf4j:slf4j-simple:2.0.17" />
<CLASSES>
<root url="jar://$PROJECT_DIR$/lib/slf4j-simple-2.0.17.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/slf4j-api-2.0.17.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -16,5 +16,6 @@
<orderEntry type="library" name="xerial.sqlite.jdbc" level="project" /> <orderEntry type="library" name="xerial.sqlite.jdbc" level="project" />
<orderEntry type="library" name="sun.mail.jakarta" level="project" /> <orderEntry type="library" name="sun.mail.jakarta" level="project" />
<orderEntry type="library" name="digitalpetri.modbus.tcp" level="project" /> <orderEntry type="library" name="digitalpetri.modbus.tcp" level="project" />
<orderEntry type="library" name="slf4j.simple" level="project" />
</component> </component>
</module> </module>

View File

@@ -1 +1 @@
{"Modbus_Port":502,"Modbus_MasterIP":"192.168.10.1","Modbus_SlaveID":"1","VX3KTargetIP":"192.168.14.1","VX3KTargetPort":5000,"Email_SMTPServer":"mail.galva.co.id","Email_SMTPPort":587,"Email_SMTPSSL":true,"Email_SMTPUsername":"admin","Email_SMTPPassword":"admin","Email_SMTPFrom":"fa@galva.co.id","Email_SenderName":"Fire Alarm Gateway","Email_Subject":"Fire Alarm Gateway Notification","MQTT_Broker":"34.101.202.96","MQTT_Port":1883,"MQTT_Topic":"FA_Gateway/status","MQTT_ClientID":"Pekojan","MQTT_Username":"gtcdev","MQTT_Password":"gtcdev2025"} {"Modbus_Port":502,"Modbus_MasterIP":"192.168.10.1","Modbus_SlaveID":"1","VX3KTargetIP":"192.168.14.1","VX3KTargetPort":5000,"Email_SMTPServer":"mail.galva.co.id","Email_SMTPPort":587,"Email_SMTPSSL":true,"Email_SMTPUsername":"admin","Email_SMTPPassword":"admin","Email_SMTPFrom":"fa@galva.co.id","Email_SenderName":"Fire Alarm Gateway","Email_Subject":"Fire Alarm Gateway Notification","MQTT_Broker":"34.101.202.96","MQTT_Port":1883,"MQTT_Topic":"FA_Gateway/status","MQTT_ClientID":"Pekojan","MQTT_Username":"gtcdev","MQTT_Password":"gtcdev2025","WebListenPort":"80"}

BIN
lib/javalin-6.6.0.jar Normal file

Binary file not shown.

BIN
lib/jetty-http-11.0.25.jar Normal file

Binary file not shown.

BIN
lib/jetty-io-11.0.25.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/jetty-util-11.0.25.jar Normal file

Binary file not shown.

Binary file not shown.

BIN
lib/jetty-xml-11.0.25.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/slf4j-api-2.0.17.jar Normal file

Binary file not shown.

BIN
lib/slf4j-simple-2.0.17.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -7,6 +7,7 @@ import mqtt.MqttClient;
import org.tinylog.Logger; import org.tinylog.Logger;
import pa.VX3K; import pa.VX3K;
import pa.VX3KPseudoContactInput; import pa.VX3KPseudoContactInput;
import web.WebServer;
//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or //TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter. // click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
@@ -18,12 +19,14 @@ public class Main {
private static VX3K vx3K; private static VX3K vx3K;
private static SMTPSender mailsender; private static SMTPSender mailsender;
private static ModbusTCPServer modbusServer; private static ModbusTCPServer modbusServer;
private static WebServer webServer;
// Application entry point // Application entry point
public static void main(String[] args) { public static void main(String[] args) {
Logger.info("Application started"); Logger.info("Application started");
// initialize config // initialize config
config = new config(); config = new config();
config.Load();
// initialize database // initialize database
db = new Database(); db = new Database();
@@ -35,9 +38,14 @@ public class Main {
// initialize Email Sender // initialize Email Sender
mailsender = new SMTPSender(config.getEmail_SMTPServer(), config.getEmail_SMTPPort(), true, config.getEmail_SMTPUsername(), config.getEmail_SMTPPassword()); mailsender = new SMTPSender(config.getEmail_SMTPServer(), config.getEmail_SMTPPort(), true, config.getEmail_SMTPUsername(), config.getEmail_SMTPPassword());
// initialize Modbus TCP Server
modbusServer = new ModbusTCPServer(config.getModbus_MasterIP(), config.getModbus_Port(), 1000); modbusServer = new ModbusTCPServer(config.getModbus_MasterIP(), config.getModbus_Port(), 1000);
modbusServer.Start(); modbusServer.Start();
// Initialize the web server
webServer = new WebServer();
webServer.Start(Integer.parseInt(config.getWebListenPort()));
// Initialize the GPIO pins // Initialize the GPIO pins
gpio = new NanopiGpio(); gpio = new NanopiGpio();
// cek di https://wiki.friendlyelec.com/wiki/index.php/NanoPi_Duo20 // cek di https://wiki.friendlyelec.com/wiki/index.php/NanoPi_Duo20
@@ -129,6 +137,7 @@ public class Main {
if (gpio!=null && gpio.IsOpened()) gpio.Close(); if (gpio!=null && gpio.IsOpened()) gpio.Close();
if (mqttClient!=null && mqttClient.isConnected()) mqttClient.Disconnect(); if (mqttClient!=null && mqttClient.isConnected()) mqttClient.Disconnect();
if (modbusServer!=null && modbusServer.isRunning()) modbusServer.Stop(); if (modbusServer!=null && modbusServer.isRunning()) modbusServer.Stop();
if (webServer!=null && webServer.isRunning()) webServer.Stop();
})); }));
} }
} }

View File

@@ -6,43 +6,41 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
public class config { public class config {
private @Getter @Setter int Modbus_Port = 502; @Getter @Setter int Modbus_Port ;
private @Getter @Setter String Modbus_MasterIP = "192.168.10.1"; @Getter @Setter String Modbus_MasterIP;
private @Getter @Setter String Modbus_SlaveID = "1"; @Getter @Setter String Modbus_SlaveID ;
private @Getter @Setter String VX3KTargetIP; @Getter @Setter String VX3KTargetIP;
private @Getter @Setter int VX3KTargetPort; @Getter @Setter int VX3KTargetPort;
private @Getter @Setter String Email_SMTPServer; @Getter @Setter String Email_SMTPServer;
private @Getter @Setter int Email_SMTPPort; @Getter @Setter int Email_SMTPPort;
private @Getter @Setter boolean Email_SMTPSSL; @Getter @Setter boolean Email_SMTPSSL;
private @Getter @Setter String Email_SMTPUsername; @Getter @Setter String Email_SMTPUsername;
private @Getter @Setter String Email_SMTPPassword; @Getter @Setter String Email_SMTPPassword;
private @Getter @Setter String Email_SMTPFrom ; @Getter @Setter String Email_SMTPFrom ;
private @Getter @Setter String Email_SenderName; @Getter @Setter String Email_SenderName;
private @Getter @Setter String Email_Subject; @Getter @Setter String Email_Subject;
private @Getter @Setter String MQTT_Broker; @Getter @Setter String MQTT_Broker;
private @Getter @Setter int MQTT_Port; @Getter @Setter int MQTT_Port;
private @Getter @Setter String MQTT_Topic ; @Getter @Setter String MQTT_Topic ;
private @Getter @Setter String MQTT_ClientID; @Getter @Setter String MQTT_ClientID;
private @Getter @Setter String MQTT_Username; @Getter @Setter String MQTT_Username;
private @Getter @Setter String MQTT_Password ; @Getter @Setter String MQTT_Password ;
@Getter @Setter String WebListenPort;
public config(){
Load();
}
/** /**
* Load configuration from file. * Load configuration from file.
* If the file does not exist, create default configuration. * If the file does not exist, create default configuration.
*/ */
private void Load(){ public void Load(){
Path configPath = Path.of(Somecodes.currentdirectory, "config.json"); Path configPath = Path.of(Somecodes.currentdirectory, "config.json");
if (Files.exists(configPath)){ if (Files.exists(configPath)){
// Read the configuration from the file // Read the configuration from the file
// and if not complete, create defaults // and if not complete, create defaults
try{ try{
String configContent = Files.readString(configPath); String configContent = Files.readString(configPath);
Logger.info("config content: {}", configContent);
config loadedConfig = Somecodes.gson.fromJson(configContent, config.class); config loadedConfig = Somecodes.gson.fromJson(configContent, config.class);
Logger.info("Loaded config from {}", loadedConfig.toString());
if (loadedConfig != null) { if (loadedConfig != null) {
// Copy values from loadedConfig to this instance // Copy values from loadedConfig to this instance
this.Modbus_MasterIP = loadedConfig.Modbus_MasterIP; this.Modbus_MasterIP = loadedConfig.Modbus_MasterIP;
@@ -64,6 +62,7 @@ public class config {
this.MQTT_ClientID = loadedConfig.MQTT_ClientID; this.MQTT_ClientID = loadedConfig.MQTT_ClientID;
this.MQTT_Username = loadedConfig.MQTT_Username; this.MQTT_Username = loadedConfig.MQTT_Username;
this.MQTT_Password = loadedConfig.MQTT_Password; this.MQTT_Password = loadedConfig.MQTT_Password;
this.WebListenPort = loadedConfig.WebListenPort;
} else { } else {
Logger.error("Loaded config is null, creating Default Config"); Logger.error("Loaded config is null, creating Default Config");
@@ -104,7 +103,7 @@ public class config {
MQTT_ClientID = "Pekojan"; MQTT_ClientID = "Pekojan";
MQTT_Username = "gtcdev"; MQTT_Username = "gtcdev";
MQTT_Password = "gtcdev2025"; MQTT_Password = "gtcdev2025";
WebListenPort = "80";
Save(); Save();
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,57 @@
.bs-icon {
--bs-icon-size: .75rem;
display: flex;
flex-shrink: 0;
justify-content: center;
align-items: center;
font-size: var(--bs-icon-size);
width: calc(var(--bs-icon-size) * 2);
height: calc(var(--bs-icon-size) * 2);
color: var(--bs-primary);
}
.bs-icon-xs {
--bs-icon-size: 1rem;
width: calc(var(--bs-icon-size) * 1.5);
height: calc(var(--bs-icon-size) * 1.5);
}
.bs-icon-sm {
--bs-icon-size: 1rem;
}
.bs-icon-md {
--bs-icon-size: 1.5rem;
}
.bs-icon-lg {
--bs-icon-size: 2rem;
}
.bs-icon-xl {
--bs-icon-size: 2.5rem;
}
.bs-icon.bs-icon-primary {
color: var(--bs-white);
background: var(--bs-primary);
}
.bs-icon.bs-icon-primary-light {
color: var(--bs-primary);
background: rgba(var(--bs-primary-rgb), .2);
}
.bs-icon.bs-icon-semi-white {
color: var(--bs-primary);
background: rgba(255, 255, 255, .5);
}
.bs-icon.bs-icon-rounded {
border-radius: .5rem;
}
.bs-icon.bs-icon-circle {
border-radius: 50%;
}

View File

@@ -0,0 +1,22 @@
document.addEventListener("DOMContentLoaded", function () {
const socket = new WebSocket("ws://" + location.host + "/ws");
socket.onopen = () => {
console.log("WebSocket connected");
const message = { type: "hello", value: 123 };
socket.send(JSON.stringify(message));
};
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("Received from server:", data);
};
socket.onerror = (err) => {
console.error("WebSocket error:", err);
};
socket.onclose = () => {
console.log("WebSocket closed");
};
});

32
src/html/index.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html data-bs-theme="light" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>FireAlarmGateway</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/Navbar-Centered-Brand-icons.css">
</head>
<body>
<nav class="navbar navbar-expand-md bg-body py-3">
<div class="container"><a class="navbar-brand d-flex align-items-center" href="#"><span class="bs-icon-sm bs-icon-rounded bs-icon-primary d-flex justify-content-center align-items-center me-2 bs-icon"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-bezier">
<path fill-rule="evenodd" d="M0 10.5A1.5 1.5 0 0 1 1.5 9h1A1.5 1.5 0 0 1 4 10.5v1A1.5 1.5 0 0 1 2.5 13h-1A1.5 1.5 0 0 1 0 11.5zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zm10.5.5A1.5 1.5 0 0 1 13.5 9h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zM6 4.5A1.5 1.5 0 0 1 7.5 3h1A1.5 1.5 0 0 1 10 4.5v1A1.5 1.5 0 0 1 8.5 7h-1A1.5 1.5 0 0 1 6 5.5zM7.5 4a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5z"></path>
<path d="M6 4.5H1.866a1 1 0 1 0 0 1h2.668A6.517 6.517 0 0 0 1.814 9H2.5c.123 0 .244.015.358.043a5.517 5.517 0 0 1 3.185-3.185A1.503 1.503 0 0 1 6 5.5zm3.957 1.358A1.5 1.5 0 0 0 10 5.5v-1h4.134a1 1 0 1 1 0 1h-2.668a6.517 6.517 0 0 1 2.72 3.5H13.5c-.123 0-.243.015-.358.043a5.517 5.517 0 0 0-3.185-3.185z"></path>
</svg></span><span>Contact Input Status</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-4"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse flex-grow-0 order-md-first" id="navcol-4">
<ul class="navbar-nav me-auto">
<li class="nav-item"><a class="nav-link active" href="#">Contact Input</a></li>
<li class="nav-item"><a class="nav-link" href="setting.html">Setting</a></li>
</ul>
<div class="d-md-none my-2"><button class="btn btn-light me-2" type="button">Button</button><button class="btn btn-primary" type="button">Button</button></div>
</div>
<div class="d-none d-md-block"><a class="btn btn-primary" role="button" href="#">Login</a></div>
</div>
</nav>
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/setting.js"></script>
</body>
</html>

58
src/html/setting.html Normal file
View File

@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html data-bs-theme="light" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>FireAlarmGateway</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/Navbar-Centered-Brand-icons.css">
</head>
<body>
<nav class="navbar navbar-expand-md bg-body py-3">
<div class="container"><a class="navbar-brand d-flex align-items-center" href="#"><span class="bs-icon-sm bs-icon-rounded bs-icon-primary d-flex justify-content-center align-items-center me-2 bs-icon"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-bezier">
<path fill-rule="evenodd" d="M0 10.5A1.5 1.5 0 0 1 1.5 9h1A1.5 1.5 0 0 1 4 10.5v1A1.5 1.5 0 0 1 2.5 13h-1A1.5 1.5 0 0 1 0 11.5zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zm10.5.5A1.5 1.5 0 0 1 13.5 9h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zM6 4.5A1.5 1.5 0 0 1 7.5 3h1A1.5 1.5 0 0 1 10 4.5v1A1.5 1.5 0 0 1 8.5 7h-1A1.5 1.5 0 0 1 6 5.5zM7.5 4a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5z"></path>
<path d="M6 4.5H1.866a1 1 0 1 0 0 1h2.668A6.517 6.517 0 0 0 1.814 9H2.5c.123 0 .244.015.358.043a5.517 5.517 0 0 1 3.185-3.185A1.503 1.503 0 0 1 6 5.5zm3.957 1.358A1.5 1.5 0 0 0 10 5.5v-1h4.134a1 1 0 1 1 0 1h-2.668a6.517 6.517 0 0 1 2.72 3.5H13.5c-.123 0-.243.015-.358.043a5.517 5.517 0 0 0-3.185-3.185z"></path>
</svg></span><span>Settings</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-4"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse flex-grow-0 order-md-first" id="navcol-4">
<ul class="navbar-nav me-auto">
<li class="nav-item"><a class="nav-link active" href="index.html">Contact Input</a></li>
<li class="nav-item"><a class="nav-link" href="#">Setting</a></li>
</ul>
<div class="d-md-none my-2"><button class="btn btn-light me-2" type="button">Button</button><button class="btn btn-primary" type="button">Button</button></div>
</div>
<div class="d-none d-md-block"><a class="btn btn-primary" role="button" href="#">Login</a></div>
</div>
</nav>
<div class="vstack">
<div class="container">
<div class="row">
<div class="col-md-6"><label class="col-form-label w-100 h-100">SMTP Server</label></div>
<div class="col-md-6"><input class="w-100 h-100" type="text"></div>
</div>
<div class="row">
<div class="col-md-6"><label class="col-form-label w-100 h-100">SMTP Port</label></div>
<div class="col-md-6"><input class="w-100 h-100" type="text"></div>
</div>
<div class="row">
<div class="col-md-6"><label class="col-form-label w-100 h-100">SMTP Username</label></div>
<div class="col-md-6"><input class="w-100 h-100" type="text"></div>
</div>
<div class="row">
<div class="col-md-6"><label class="col-form-label w-100 h-100">SMTP Password</label></div>
<div class="col-md-6"><input class="w-100 h-100" type="text"></div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-6"><button class="btn btn-primary w-100 h-100" type="button">Reset Default</button></div>
<div class="col-md-6"><button class="btn btn-primary w-100 h-100" type="button">Apply</button></div>
</div>
</div>
</div>
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/setting.js"></script>
</body>
</html>

74
src/web/WebServer.java Normal file
View File

@@ -0,0 +1,74 @@
package web;
import io.javalin.Javalin;
import lombok.Getter;
import org.tinylog.Logger;
public class WebServer {
private Javalin app;
private @Getter boolean isRunning = false;
/**
* Start the web server on the specified port.
* @param listenport the port to listen on
*/
public void Start(int listenport){
isRunning = false;
app = null;
try{
var xx = Javalin.create(config -> {
config.useVirtualThreads = true;
config.staticFiles.add("/html");
}).start(listenport);
isRunning = true;
app = xx;
Logger.info("Web server started on port {}", listenport);
AssignRoutes();
} catch (Exception e){
Logger.error("Failed to start web server: {}", e.getMessage());
}
}
private void AssignRoutes(){
if (app == null) {
Logger.error("Web server is not running, cannot assign routes.");
return;
}
app.ws("/ws", ws->{
ws.onConnect(ctx -> {
Logger.info("WebSocket connected: {}", ctx.session.getRemoteAddress());
});
ws.onMessage(ctx -> {
Logger.info("WebSocket message received: {}", ctx.message());
// Handle incoming messages here
});
ws.onClose(ctx -> {
Logger.info("WebSocket closed: {} ", ctx.session.getRemoteAddress());
});
ws.onError(ctx -> {
Logger.error("WebSocket error: {}", ctx.error().getMessage());
});
});
}
/**
* Stop the web server if it is running.
*/
public void Stop(){
if (app!=null){
try{
app.stop();
} catch (Exception e){
Logger.error("Failed to stop web server: {}", e.getMessage());
}
app = null;
}
isRunning = false;
}
}