Files
BirdDeterrentSystem/src/main/java/Web/WebServer.java
2024-11-14 10:49:50 +07:00

304 lines
13 KiB
Java

package Web;
import Other.SomeCodes;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DisconnectListener;
import io.javalin.Javalin;
import io.javalin.http.UploadedFile;
import io.javalin.util.FileUtil;
import io.javalin.util.JavalinException;
import io.javalin.websocket.*;
import lombok.Getter;
import lombok.Setter;
import org.tinylog.Logger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static Other.SomeCodes.*;
import static io.javalin.apibuilder.ApiBuilder.*;
@SuppressWarnings({"unused"})
public class WebServer {
private @Getter @Setter String webusername;
private @Getter @Setter String webpassword;
private final Javalin app;
private final Set<WsContext> connectedWebsocketClients = ConcurrentHashMap.newKeySet();
private final SocketIOServer socketServer;
private final Configuration socketConfig;
private final HashMap<String, SocketIOClient> socketIOClients = new HashMap<>();
public WebServer(WebsocketEvent event, String webusername, String webpassword){
this.webusername = webusername;
this.webpassword = webpassword;
app = Javalin.create(config -> {
config.staticFiles.add("/html");
config.router.apiBuilder(()-> path("setting", () ->{
get(ctx -> ctx.json(SettingInfo.getInstance()));
path("audiofile",()-> post(ctx -> {
Logger.info("api /setting/audiofile");
String audiofile1 = ctx.formParam("preset1");
String audiofile2 = ctx.formParam("preset2");
String audiofile3 = ctx.formParam("preset3");
String audiofile4 = ctx.formParam("preset4");
String audiofile5 = ctx.formParam("preset5");
Logger.info("audiofile1: {}", audiofile1);
Logger.info("audiofile2: {}", audiofile2);
Logger.info("audiofile3: {}", audiofile3);
Logger.info("audiofile4: {}", audiofile4);
Logger.info("audiofile5: {}", audiofile5);
Properties prop = SomeCodes.LoadProperties("config.properties");
prop.setProperty("AudioFile01", audiofile1!=null?audiofile1:"");
prop.setProperty("AudioFile02", audiofile2!=null?audiofile2:"");
prop.setProperty("AudioFile03", audiofile3!=null?audiofile3:"");
prop.setProperty("AudioFile04", audiofile4!=null?audiofile4:"");
prop.setProperty("AudioFile05", audiofile5!=null?audiofile5:"");
if (SaveProperties(prop, "config.properties")){
Logger.info("audiofile saved");
ctx.status(200);
} else {
Logger.error("Failed to save audiofile");
ctx.status(400);
ctx.result("Failed to save audiofile");
}
}));
path("uploadaudiofile", ()-> post(ctx -> {
List<UploadedFile> uploadedFileList = ctx.uploadedFiles();
int size = uploadedFileList.size();
if (size>0){
uploadedFileList.forEach(ff ->{
String targetsave = audioPath.resolve(ff.filename()).toString();
FileUtil.streamToFile(ff.content(), targetsave);
Logger.info("Uploaded file: {}", targetsave);
});
ctx.status(200);
ctx.result("UploadedFiles: "+size);
} else {
ctx.status(400);
ctx.result("No file uploaded");
}
}));
path("weblogin", ()-> post(ctx -> {
String username = ctx.formParam("username");
String password = ctx.formParam("password");
Logger.info("api /setting/weblogin");
Logger.info("username: {}", username);
Logger.info("password: {}", password);
Properties prop = SomeCodes.LoadProperties("config.properties");
prop.setProperty("WebUsername", ValidString(username)?username:"admin");
prop.setProperty("WebPassword", ValidString(password)?password:"bandara");
if (SaveProperties(prop, "config.properties")){
Logger.info("weblogin saved");
//ctx.status(200);
this.webusername = username;
this.webpassword = password;
ctx.redirect("/logout");
} else {
Logger.error("Failed to save weblogin");
ctx.status(400);
ctx.result("Failed to save weblogin");
}
}));
path("camera",()-> post(ctx -> {
String camera_ip = ctx.formParam("ip");
String camera_port = ctx.formParam("port");
String camera_username = ctx.formParam("username");
String camera_password = ctx.formParam("password");
Logger.info("api /setting/camera");
Logger.info("camera_ip: {}", camera_ip);
Logger.info("camera_port: {}", camera_port);
Logger.info("camera_username: {}", camera_username);
Logger.info("camera_password: {}", camera_password);
Properties prop = SomeCodes.LoadProperties("config.properties");
prop.setProperty("Camera_ip", ValidString(camera_ip)?camera_ip:"192.168.0.4");
prop.setProperty("Camera_port", ValidString(camera_port)?camera_port:"80");
prop.setProperty("Camera_user", ValidString(camera_username)?camera_username:"root");
prop.setProperty("Camera_password", ValidString(camera_password)?camera_password:"password");
if (SaveProperties(prop, "config.properties")){
Logger.info("IP camera setting saved");
ctx.status(200);
if (event!=null) event.NewCameraConfiguration();
} else {
Logger.error("Failed to save IP camera setting");
ctx.status(400);
ctx.result("Failed to save IP camera setting");
}
}));
}));
});
app.get("/", ctx-> {
if (ctx.sessionAttribute("username")==null) {
// belum login
ctx.redirect("/login.html");
} else if (Objects.equals(ctx.sessionAttribute("username"), this.webusername)){
// sudah login
ctx.redirect("/index.html");
} else {
// sudah login tapi bukan username yang benar
ctx.redirect("/login.html");
}
});
app.before("/index.html", ctx ->{
if (ctx.sessionAttribute("username")==null){
ctx.redirect("/login.html");
}
});
app.before("/setting.html", ctx ->{
if (ctx.sessionAttribute("username")==null){
ctx.redirect("/login.html");
}
});
app.post("/login", ctx ->{
String username = ctx.formParam("username");
String password = ctx.formParam("password");
if (Objects.equals(username, this.webusername) && Objects.equals(password, this.webpassword)){
ctx.sessionAttribute("username", username);
ctx.redirect("/index.html");
} else {
ctx.status(400);
ctx.redirect("/login.html");
}
});
app.get("/logout", ctx ->{
ctx.sessionAttribute("username", null);
ctx.redirect("/login.html");
});
/*
WebSocket Communication
This is temporary, later must choose either WebSocket or SocketIO
*/
app.ws("/ws", ws -> {
ws.onConnect(connectws);
ws.onClose(closews);
ws.onMessage(ctx -> {
try{
//Logger.info("WebSocket message {}", ctx.message());
WebsocketCommand command = ctx.messageAsClass(WebsocketCommand.class);
if (event!=null) {
WebsocketReply reply = event.onWebsocketCommand(command);
if (reply!=null) ctx.sendAsClass(reply, WebsocketReply.class);
//if (reply!=null) SendtoAll(reply);
}
} catch (Exception e){
Logger.error("Failed to parse WebSocketCommand message: {}", e.getMessage());
ctx.closeSession();
connectedWebsocketClients.remove(ctx);
}
});
});
/*
SocketIO Communication
This is temporary, later must choose either WebSocket or SocketIO
*/
socketConfig = new Configuration();
socketConfig.setHostname("0.0.0.0");
socketConfig.setPort(3001);
socketServer = new SocketIOServer(socketConfig);
socketServer.addConnectListener(connectListener);
socketServer.addDisconnectListener(disconnectListener);
socketServer.addNamespace("/socketio").addEventListener("message", String.class, (client, data, ackSender) -> {
//Logger.info("SocketIO message from namespace /socketio from {}: {}", client.getRemoteAddress(), data);
WebsocketCommand command = gson.fromJson(data, WebsocketCommand.class);
if (event!=null) {
WebsocketReply reply = event.onWebsocketCommand(command);
if (reply!=null) client.sendEvent("message", gson.toJson(reply));
}
});
}
/**
* Send Object message to all connected websocket clients
* @param obj Object to send
*/
public void SendtoAll(Object obj){
connectedWebsocketClients
.stream()
.filter(ws -> ws.session.isOpen())
.forEach(ws -> ws.send(obj));
socketIOClients.forEach((key, client) -> client.sendEvent("message", gson.toJson(obj)));
}
/**
* Start the web server
* @param localip Local IP address to bind
* @param port Port to bind
*/
public void Start(String localip, int port){
try{
app.start(localip, port);
Logger.info("Web server started at {}:{}", localip, port);
socketServer.start();
Logger.info("SocketIO server started at {}:{}", socketConfig.getHostname(), socketConfig.getPort());
} catch (JavalinException e){
Logger.error("Web server failed to start: {}", e.getMessage());
}
}
/**
* Stop the web server
*/
public void Stop(){
try{
connectedWebsocketClients.forEach(WsContext::closeSession);
connectedWebsocketClients.clear();
app.stop();
Logger.info("Web server stopped");
socketIOClients.forEach((key, client) -> client.disconnect());
socketIOClients.clear();
socketServer.stop();
Logger.info("SocketIO server stopped");
} catch (JavalinException e){
Logger.error("Web server failed to stop: {}", e.getMessage());
}
}
WsConnectHandler connectws = ws ->{
Logger.info("WebSocket connected from {}", ws.sessionId());
//ws.headerMap().forEach((key, value) -> Logger.info("HeaderMap {}: {}", key, value));
connectedWebsocketClients.add(ws);
};
WsCloseHandler closews = ws ->{
Logger.info("WebSocket closed from {}, code {}, reason {}", ws.sessionId(), ws.status(), ws.reason());
connectedWebsocketClients.remove(ws);
};
ConnectListener connectListener = client -> {
Logger.info("SocketIO connected, id {} from {}", client.getSessionId(), client.getRemoteAddress());
socketIOClients.put(client.getSessionId().toString(), client);
};
DisconnectListener disconnectListener = client -> {
Logger.info("SocketIO disconnected, id {} from {}", client.getSessionId(), client.getRemoteAddress());
socketIOClients.remove(client.getSessionId().toString());
};
}