mirror of
https://github.com/tiennm99/BSK-All-in-One-Clinic-Management-System.git
synced 2026-10-16 02:15:10 +00:00
[update] Implement connection error handling in Client class with user-friendly dialog messages. Enhance server startup process with dashboard updates for better visibility of server status. Refactor user session management in ServerHandler to ensure accurate role updates and connection tracking.
This commit is contained in:
1 parent
46182568a5
commit
bc78cdf1f4
7 files changed
+201
-100
No files matched your search
@@ -24,12 +24,54 @@ import java.util.Properties;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
@Slf4j
|
||||
public class Client {
|
||||
private static void showConnectionErrorDialog(String serverAddress, int port, Exception error) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
String message = String.format(
|
||||
"""
|
||||
Không thể kết nối đến máy chủ!
|
||||
|
||||
Địa chỉ máy chủ: %s
|
||||
Cổng: %d
|
||||
|
||||
Nguyên nhân có thể:
|
||||
1. Máy chủ chưa được khởi động
|
||||
2. Địa chỉ hoặc cổng không chính xác
|
||||
3. Tường lửa đang chặn kết nối
|
||||
|
||||
Giải pháp:
|
||||
1. Kiểm tra xem máy chủ đã được khởi động chưa
|
||||
2. Kiểm tra lại cấu hình trong file config.properties
|
||||
3. Tắt ứng dụng và khởi động lại
|
||||
|
||||
Chi tiết lỗi: %s
|
||||
""",
|
||||
serverAddress,
|
||||
port,
|
||||
error.getMessage()
|
||||
);
|
||||
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
message,
|
||||
"Lỗi Kết Nối",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
|
||||
// Exit the application after showing the error
|
||||
System.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
var thread = new Thread(() -> {
|
||||
Properties props = new Properties();
|
||||
String serverAddress = "localhost";
|
||||
int port = 1999;
|
||||
|
||||
// First try to load from external config file
|
||||
File externalConfig = new File("config/config.properties");
|
||||
@@ -47,37 +89,32 @@ public class Client {
|
||||
try (InputStream input = Client.class.getClassLoader().getResourceAsStream("config.properties")) {
|
||||
if (input == null) {
|
||||
log.error("Unable to find config.properties");
|
||||
showConnectionErrorDialog(serverAddress, port,
|
||||
new Exception("Không tìm thấy file cấu hình config.properties"));
|
||||
return;
|
||||
}
|
||||
props.load(input);
|
||||
log.info("Loaded configuration from internal resources");
|
||||
} catch (IOException e) {
|
||||
log.error("Error loading internal config file", e);
|
||||
showConnectionErrorDialog(serverAddress, port, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get server configuration
|
||||
var serverAddress = props.getProperty("server.address");
|
||||
var portStr = props.getProperty("server.port");
|
||||
serverAddress = props.getProperty("server.address", "localhost");
|
||||
String portStr = props.getProperty("server.port");
|
||||
|
||||
// Use defaults if not configured
|
||||
if (serverAddress == null) {
|
||||
serverAddress = "localhost";
|
||||
log.info("Using default server address: {}", serverAddress);
|
||||
} else {
|
||||
log.info("Using configured server address: {}", serverAddress);
|
||||
}
|
||||
|
||||
int port;
|
||||
if (portStr != null) {
|
||||
port = Integer.parseInt(portStr);
|
||||
log.info("Using configured port: {}", port);
|
||||
} else {
|
||||
port = 1999;
|
||||
log.info("Using default port: {}", port);
|
||||
}
|
||||
|
||||
log.info("Using server address: {}", serverAddress);
|
||||
if ("127.0.0.1".equals(serverAddress)) {
|
||||
log.info("Connecting to localhost");
|
||||
}
|
||||
@@ -86,8 +123,10 @@ public class Client {
|
||||
try {
|
||||
uri = new URI("ws://" + serverAddress + ":" + port + "/");
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
showConnectionErrorDialog(serverAddress, port, e);
|
||||
return;
|
||||
}
|
||||
|
||||
EventLoopGroup group = new NioEventLoopGroup();
|
||||
try {
|
||||
URI finalUri = uri;
|
||||
@@ -120,18 +159,17 @@ public class Client {
|
||||
channel.closeFuture().sync();
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
throw new RuntimeException(e);
|
||||
log.error("Connection error", e);
|
||||
showConnectionErrorDialog(serverAddress, port, e);
|
||||
return;
|
||||
} finally {
|
||||
try {
|
||||
group.shutdownGracefully().sync();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
log.error("Error shutting down", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -398,7 +398,7 @@ public class CheckUpPage extends JPanel {
|
||||
// Configure the Details/Actions Panel (rightBottomPanel)
|
||||
rightBottomPanel.setLayout(new BorderLayout());
|
||||
rightBottomPanel.setBorder(BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createEmptyBorder(5, 5, 5, 5),
|
||||
BorderFactory.createEmptyBorder(5, 5, 5, 5),
|
||||
BorderFactory.createTitledBorder(
|
||||
BorderFactory.createLineBorder(new Color(63, 81, 181), 1, true),
|
||||
"Chi tiết và Thao tác",
|
||||
@@ -974,7 +974,7 @@ public class CheckUpPage extends JPanel {
|
||||
|
||||
// Create a more modern action panel
|
||||
JPanel iconPanel = new JPanel(new GridLayout(1, 5, 10, 0)); // 5 buttons, 10px horizontal gap
|
||||
iconPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
iconPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
iconPanel.setBackground(Color.WHITE);
|
||||
|
||||
// Define button properties
|
||||
@@ -994,9 +994,9 @@ public class CheckUpPage extends JPanel {
|
||||
JButton button = createActionButton(name, text, color);
|
||||
button.addActionListener(e -> {
|
||||
if (checkupIdField == null || checkupIdField.getText().isEmpty()) {
|
||||
JOptionPane.showMessageDialog(null, "Vui lòng chọn một bệnh nhân từ hàng đợi", "Chưa chọn bệnh nhân", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
JOptionPane.showMessageDialog(null, "Vui lòng chọn một bệnh nhân từ hàng đợi", "Chưa chọn bệnh nhân", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
handleActionPanelClick(name);
|
||||
});
|
||||
iconPanel.add(button);
|
||||
@@ -1101,53 +1101,53 @@ public class CheckUpPage extends JPanel {
|
||||
private void handleActionPanelClick(String name) {
|
||||
switch (name) {
|
||||
case "service":
|
||||
if(serDialog == null) {
|
||||
serDialog = new ServiceDialog(mainFrame);
|
||||
}
|
||||
serDialog.setVisible(true);
|
||||
saved = false;
|
||||
servicePrescription = serDialog.getServicePrescription();
|
||||
updatePrescriptionTree();
|
||||
log.info("Service prescription: {}", (Object) servicePrescription);
|
||||
break;
|
||||
case "save": {
|
||||
int option = JOptionPane.showOptionDialog(null, "Bạn có muốn lưu các thay đổi?",
|
||||
"Lưu thay đổi", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
|
||||
null, null, null);
|
||||
if (option == JOptionPane.NO_OPTION) {
|
||||
return;
|
||||
}
|
||||
saved = true;
|
||||
callingStatusLabel.setBackground(new Color(230, 255, 230));
|
||||
callingStatusLabel.setForeground(new Color(0, 100, 0));
|
||||
// TODO: Add logic to actually save medicinePrescription and servicePrescription with other checkup data
|
||||
break;
|
||||
}
|
||||
case "medicine":
|
||||
if(medDialog == null) {
|
||||
medDialog = new MedicineDialog(mainFrame);
|
||||
}
|
||||
medDialog.setVisible(true);
|
||||
saved = false;
|
||||
medicinePrescription = medDialog.getMedicinePrescription();
|
||||
updatePrescriptionTree();
|
||||
log.info("Medicine prescription: {}", (Object) medicinePrescription);
|
||||
break;
|
||||
case "printer":
|
||||
if ((medicinePrescription == null || medicinePrescription.length == 0) &&
|
||||
(servicePrescription == null || servicePrescription.length == 0)) {
|
||||
if(serDialog == null) {
|
||||
serDialog = new ServiceDialog(mainFrame);
|
||||
}
|
||||
serDialog.setVisible(true);
|
||||
saved = false;
|
||||
servicePrescription = serDialog.getServicePrescription();
|
||||
updatePrescriptionTree();
|
||||
log.info("Service prescription: {}", (Object) servicePrescription);
|
||||
break;
|
||||
case "save": {
|
||||
int option = JOptionPane.showOptionDialog(null, "Bạn có muốn lưu các thay đổi?",
|
||||
"Lưu thay đổi", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
|
||||
null, null, null);
|
||||
if (option == JOptionPane.NO_OPTION) {
|
||||
return;
|
||||
}
|
||||
saved = true;
|
||||
callingStatusLabel.setBackground(new Color(230, 255, 230));
|
||||
callingStatusLabel.setForeground(new Color(0, 100, 0));
|
||||
// TODO: Add logic to actually save medicinePrescription and servicePrescription with other checkup data
|
||||
break;
|
||||
}
|
||||
case "medicine":
|
||||
if(medDialog == null) {
|
||||
medDialog = new MedicineDialog(mainFrame);
|
||||
}
|
||||
medDialog.setVisible(true);
|
||||
saved = false;
|
||||
medicinePrescription = medDialog.getMedicinePrescription();
|
||||
updatePrescriptionTree();
|
||||
log.info("Medicine prescription: {}", (Object) medicinePrescription);
|
||||
break;
|
||||
case "printer":
|
||||
if ((medicinePrescription == null || medicinePrescription.length == 0) &&
|
||||
(servicePrescription == null || servicePrescription.length == 0)) {
|
||||
JOptionPane.showMessageDialog(null, "Không có thuốc hoặc dịch vụ để in.", "Không có dữ liệu", JOptionPane.INFORMATION_MESSAGE);
|
||||
return;
|
||||
}
|
||||
MedicineInvoice medicineInvoice = new MedicineInvoice(checkupIdField.getText(),
|
||||
customerLastNameField.getText() + " " + customerFirstNameField.getText(),
|
||||
dobPicker.getJFormattedTextField().getText(), customerPhoneField.getText(),
|
||||
genderComboBox.getSelectedItem().toString(),
|
||||
customerAddressField.getText() + ", " + (wardComboBox.getSelectedItem() != null ? wardComboBox.getSelectedItem().toString() : "") + ", " + (districtComboBox.getSelectedItem() != null ? districtComboBox.getSelectedItem().toString() : "") + ", " + (provinceComboBox.getSelectedItem() != null ? provinceComboBox.getSelectedItem().toString() : ""),
|
||||
doctorComboBox.getSelectedItem().toString(), diagnosisField.getText(),
|
||||
notesField.getText(), medicinePrescription, servicePrescription);
|
||||
medicineInvoice.createDialog(mainFrame);
|
||||
break;
|
||||
}
|
||||
MedicineInvoice medicineInvoice = new MedicineInvoice(checkupIdField.getText(),
|
||||
customerLastNameField.getText() + " " + customerFirstNameField.getText(),
|
||||
dobPicker.getJFormattedTextField().getText(), customerPhoneField.getText(),
|
||||
genderComboBox.getSelectedItem().toString(),
|
||||
customerAddressField.getText() + ", " + (wardComboBox.getSelectedItem() != null ? wardComboBox.getSelectedItem().toString() : "") + ", " + (districtComboBox.getSelectedItem() != null ? districtComboBox.getSelectedItem().toString() : "") + ", " + (provinceComboBox.getSelectedItem() != null ? provinceComboBox.getSelectedItem().toString() : ""),
|
||||
doctorComboBox.getSelectedItem().toString(), diagnosisField.getText(),
|
||||
notesField.getText(), medicinePrescription, servicePrescription);
|
||||
medicineInvoice.createDialog(mainFrame);
|
||||
break;
|
||||
case "ultrasound":
|
||||
JOptionPane.showMessageDialog(null, "Tính năng in kết quả siêu âm sẽ được triển khai.", "TODO", JOptionPane.INFORMATION_MESSAGE);
|
||||
break;
|
||||
|
||||
@@ -16,6 +16,7 @@ import io.netty.handler.codec.http.HttpServerCodec;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -119,6 +120,12 @@ public class Server {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException, SQLException {
|
||||
// Initialize and show server dashboard
|
||||
ServerDashboard dashboard = ServerDashboard.getInstance();
|
||||
dashboard.setVisible(true);
|
||||
dashboard.updateStatus("Starting...", Color.ORANGE);
|
||||
dashboard.updatePort(PORT);
|
||||
|
||||
EventLoopGroup parentGroup =
|
||||
Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup();
|
||||
EventLoopGroup childGroup =
|
||||
@@ -152,8 +159,19 @@ public class Server {
|
||||
log.info("To connect, clients should use:");
|
||||
log.info(" - If on same machine: ws://localhost:{} or ws://127.0.0.1:{}", PORT, PORT);
|
||||
log.info(" - If on network: ws://<this-computer's-ip>:{}", PORT);
|
||||
|
||||
// Update dashboard status to running
|
||||
dashboard.updateStatus("Running", Color.GREEN);
|
||||
dashboard.addLog("Server started successfully on port " + PORT);
|
||||
|
||||
f.channel().closeFuture().sync();
|
||||
} catch (Exception e) {
|
||||
dashboard.updateStatus("Error", Color.RED);
|
||||
dashboard.addLog("Server error: " + e.getMessage());
|
||||
throw e;
|
||||
} finally {
|
||||
dashboard.updateStatus("Shutting down", Color.ORANGE);
|
||||
dashboard.addLog("Server shutting down...");
|
||||
parentGroup.shutdownGracefully();
|
||||
childGroup.shutdownGracefully();
|
||||
}
|
||||
|
||||
@@ -265,15 +265,17 @@ public class ServerDashboard extends JFrame {
|
||||
}
|
||||
|
||||
public static void decrementClients() {
|
||||
connectedClients--;
|
||||
connectedClients = Math.max(0, connectedClients - 1); // Ensure we don't go below 0
|
||||
updateClientCount();
|
||||
}
|
||||
|
||||
private static void updateClientCount() {
|
||||
if (instance != null) {
|
||||
SwingUtilities.invokeLater(() ->
|
||||
instance.clientsLabel.setText("Connected Clients: " + connectedClients)
|
||||
);
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
instance.clientsLabel.setText("Connected Clients: " + connectedClients);
|
||||
// Also update the network table since client count changed
|
||||
instance.refreshNetworkTable();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ public class User {
|
||||
public User(Channel channel, int sessionId) {
|
||||
this.channel = channel;
|
||||
this.sessionId = sessionId;
|
||||
|
||||
}
|
||||
|
||||
public void authenticate(String username, String password) {
|
||||
@@ -36,14 +35,13 @@ public class User {
|
||||
log.info(rs.getString("user_name") + " logged in");
|
||||
role = Role.valueOf(rs.getString("role_name"));
|
||||
userId = rs.getInt("user_id");
|
||||
// Update the client connection with the new role
|
||||
SessionManager.updateUserRole(channel.id().asLongText(), role.toString(), userId);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public boolean isAuthenticated() {
|
||||
|
||||
@@ -8,6 +8,7 @@ import BsK.common.packet.res.ErrorResponse.Error;
|
||||
import BsK.common.entity.Status;
|
||||
import BsK.common.util.date.DateUtils;
|
||||
import BsK.server.Server;
|
||||
import BsK.server.ServerDashboard;
|
||||
import BsK.server.network.manager.SessionManager;
|
||||
import BsK.server.network.util.UserUtil;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
@@ -39,6 +40,12 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) {
|
||||
log.debug("Received message: {}", frame.text());
|
||||
// Update last activity time for the client
|
||||
var connectedUser = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
||||
if (connectedUser != null) {
|
||||
ServerDashboard.getInstance().refreshNetworkTable();
|
||||
}
|
||||
|
||||
Packet packet = PacketSerializer.GSON.fromJson(frame.text(), Packet.class);
|
||||
|
||||
|
||||
@@ -51,6 +58,8 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
if (user.isAuthenticated()) {
|
||||
UserUtil.sendPacket(user.getSessionId(), new LoginSuccessResponse(user.getUserId(), user.getRole()));
|
||||
log.info("Send response to client User {} authenticated, role {}, session {}", user.getUserId(), user.getRole(), user.getSessionId());
|
||||
// Update client connection info
|
||||
SessionManager.updateUserRole(ctx.channel().id().asLongText(), user.getRole().toString(), user.getUserId());
|
||||
} else {
|
||||
log.info("User {} failed to authenticate", user.getUserId());
|
||||
UserUtil.sendPacket(user.getSessionId(), new ErrorResponse(Error.INVALID_CREDENTIALS));
|
||||
@@ -63,9 +72,9 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
// Tạo user trong database hoặc check exist
|
||||
boolean isUserExist = false;
|
||||
} else if (packet instanceof LogoutRequest) {
|
||||
var user = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
||||
if (user != null) {
|
||||
log.info("User {} (Session {}) requested logout.", user.getUserId(), user.getSessionId());
|
||||
var logoutUser = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
||||
if (logoutUser != null) {
|
||||
log.info("User {} (Session {}) requested logout.", logoutUser.getUserId(), logoutUser.getSessionId());
|
||||
SessionManager.onUserDisconnect(ctx.channel());
|
||||
// Optionally, you could send a LogoutResponse back to the client if needed,
|
||||
// but since the client navigates away, it might not be processed.
|
||||
@@ -74,8 +83,8 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
}
|
||||
} else {
|
||||
// Check if user is authenticated
|
||||
var user = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
||||
if (!user.isAuthenticated()) {
|
||||
var currentUser = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
||||
if (!currentUser.isAuthenticated()) {
|
||||
log.warn("Received packet from unauthenticated user: {}", packet);
|
||||
return;
|
||||
}
|
||||
@@ -140,7 +149,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
for (int i = 0; i < resultString.length; i++) {
|
||||
resultArray[i] = resultString[i].split("\\|");
|
||||
}
|
||||
UserUtil.sendPacket(user.getSessionId(), new GetCheckUpQueueResponse(resultArray));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetCheckUpQueueResponse(resultArray));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -237,7 +246,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
resultList.add(doctorName);
|
||||
}
|
||||
String[] resultString = resultList.toArray(new String[0]);
|
||||
UserUtil.sendPacket(user.getSessionId(), new GetDoctorGeneralInfoResponse(resultString));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetDoctorGeneralInfoResponse(resultString));
|
||||
log.info("Send response to client GetDoctorGeneralInfo");
|
||||
}
|
||||
}
|
||||
@@ -260,7 +269,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
|
||||
if (!rs.isBeforeFirst()) {
|
||||
System.out.println("No history data found in the checkup table.");
|
||||
UserUtil.sendPacket(user.getSessionId(), new GetCustomerHistoryResponse(new String[0][7]));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetCustomerHistoryResponse(new String[0][7]));
|
||||
} else {
|
||||
ArrayList<String> resultList = new ArrayList<>();
|
||||
while (rs.next()) {
|
||||
@@ -286,7 +295,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
resultArray[i] = resultString[i].split("\\|");
|
||||
}
|
||||
|
||||
UserUtil.sendPacket(user.getSessionId(), new GetCustomerHistoryResponse(resultArray));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetCustomerHistoryResponse(resultArray));
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
@@ -327,7 +336,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
resultArray[i] = resultString[i].split("\\|");
|
||||
}
|
||||
|
||||
UserUtil.sendPacket(user.getSessionId(), new GetMedInfoResponse(resultArray));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetMedInfoResponse(resultArray));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -361,7 +370,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
resultArray[i] = resultString[i].split("\\|");
|
||||
}
|
||||
|
||||
UserUtil.sendPacket(user.getSessionId(), new GetSerInfoResponse(resultArray));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetSerInfoResponse(resultArray));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -383,7 +392,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
String clinicAddress = rs.getString("address");
|
||||
String clinicPhone = rs.getString("phone");
|
||||
|
||||
UserUtil.sendPacket(user.getSessionId(), new ClinicInfoResponse(clinicName, clinicAddress, clinicPhone));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new ClinicInfoResponse(clinicName, clinicAddress, clinicPhone));
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
@@ -426,7 +435,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
resultArray[i] = resultString[i].split("\\|");
|
||||
}
|
||||
|
||||
UserUtil.sendPacket(user.getSessionId(), new GetRecentPatientResponse(resultArray));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetRecentPatientResponse(resultArray));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -456,7 +465,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
}
|
||||
|
||||
String[] resultString = resultList.toArray(new String[0]);
|
||||
UserUtil.sendPacket(user.getSessionId(), new GetProvinceResponse(resultString, provinceIdMap));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetProvinceResponse(resultString, provinceIdMap));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -493,7 +502,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
|
||||
String[] resultString = resultList.toArray(new String[0]);
|
||||
|
||||
UserUtil.sendPacket(user.getSessionId(), new GetDistrictResponse(resultString, districtIdMap));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetDistrictResponse(resultString, districtIdMap));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -529,10 +538,10 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
}
|
||||
|
||||
String[] resultString = resultList.toArray(new String[0]);
|
||||
UserUtil.sendPacket(user.getSessionId(), new GetWardResponse(resultString));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetWardResponse(resultString));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
UserUtil.sendPacket(user.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@@ -559,10 +568,10 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
customerId = rs.getInt(1);
|
||||
}
|
||||
|
||||
UserUtil.sendPacket(user.getSessionId(), new AddPatientResponse(true, customerId, "Thêm bệnh nhân thành công"));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new AddPatientResponse(true, customerId, "Thêm bệnh nhân thành công"));
|
||||
} catch (SQLException e) {
|
||||
String errorMessage = e.getMessage();
|
||||
UserUtil.sendPacket(user.getSessionId(), new AddPatientResponse(false,-1, "Lỗi: " + errorMessage));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new AddPatientResponse(false,-1, "Lỗi: " + errorMessage));
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@@ -598,7 +607,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
// Commit the transaction
|
||||
Server.connection.commit();
|
||||
|
||||
UserUtil.sendPacket(user.getSessionId(), new AddCheckupResponse(true, "Thêm bệnh nhân thành công"));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new AddCheckupResponse(true, "Thêm bệnh nhân thành công"));
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
@@ -608,7 +617,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
log.error("Error during rollback", rollbackEx);
|
||||
}
|
||||
String errorMessage = e.getMessage();
|
||||
UserUtil.sendPacket(user.getSessionId(), new AddCheckupResponse(false, "Lỗi: " + errorMessage));
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new AddCheckupResponse(false, "Lỗi: " + errorMessage));
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally {
|
||||
@@ -638,9 +647,14 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (cause instanceof IOException) {
|
||||
var user = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
||||
if (user != null) {
|
||||
ServerDashboard.getInstance().addLog("Client disconnected: Session " + user.getSessionId());
|
||||
}
|
||||
SessionManager.onUserDisconnect(ctx.channel());
|
||||
} else {
|
||||
log.error("ERROR: ", cause);
|
||||
ServerDashboard.getInstance().addLog("Error: " + cause.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,14 +663,21 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
if (evt instanceof IdleStateEvent event) {
|
||||
if (event.state() == IdleState.READER_IDLE) {
|
||||
try {
|
||||
var user = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
||||
if (user != null) {
|
||||
ServerDashboard.getInstance().addLog("Client timed out: Session " + user.getSessionId());
|
||||
}
|
||||
SessionManager.onUserDisconnect(ctx.channel());
|
||||
ctx.channel().close();
|
||||
} catch (Exception e) {
|
||||
ServerDashboard.getInstance().addLog("Error during client timeout: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} else if (evt instanceof HandshakeComplete) {
|
||||
int SessionId = SessionManager.onUserLogin(ctx.channel());
|
||||
log.info("Session {} logged in", SessionId);
|
||||
ServerDashboard.getInstance().addLog("New client connected: Session " + SessionId);
|
||||
ServerDashboard.incrementClients();
|
||||
|
||||
UserUtil.sendPacket(SessionId, new HandshakeCompleteResponse());
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package BsK.server.network.manager;
|
||||
|
||||
import BsK.server.network.entity.User;
|
||||
import BsK.server.network.entity.ClientConnection;
|
||||
import io.netty.channel.Channel;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
@@ -17,6 +19,8 @@ public class SessionManager {
|
||||
|
||||
private static final Map<String, User> CHANNEL_TO_USER_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Map<String, ClientConnection> CHANNEL_TO_CONNECTION_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private static final AtomicInteger SESSION_ID = new AtomicInteger(0);
|
||||
|
||||
|
||||
@@ -36,17 +40,37 @@ public class SessionManager {
|
||||
return SESSION_ID.get();
|
||||
}
|
||||
|
||||
public static Collection<ClientConnection> getAllConnections() {
|
||||
return CHANNEL_TO_CONNECTION_MAP.values();
|
||||
}
|
||||
|
||||
public static int onUserLogin(Channel channel) {
|
||||
int sessionId = SESSION_ID.incrementAndGet();
|
||||
var user = new User(channel, sessionId);
|
||||
SESSION_ID_MAP.put(sessionId, channel.id().asLongText());
|
||||
CHANNEL_SESSION_ID_MAP.put(channel.id().asLongText(), sessionId);
|
||||
CHANNEL_TO_USER_MAP.put(channel.id().asLongText(), user);
|
||||
var connection = new ClientConnection(channel, sessionId);
|
||||
|
||||
String channelId = channel.id().asLongText();
|
||||
SESSION_ID_MAP.put(sessionId, channelId);
|
||||
CHANNEL_SESSION_ID_MAP.put(channelId, sessionId);
|
||||
CHANNEL_TO_USER_MAP.put(channelId, user);
|
||||
CHANNEL_TO_CONNECTION_MAP.put(channelId, connection);
|
||||
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public static void onUserDisconnect(Channel channel) {
|
||||
int sessionId = CHANNEL_SESSION_ID_MAP.remove(channel.id().asLongText());
|
||||
String channelId = channel.id().asLongText();
|
||||
int sessionId = CHANNEL_SESSION_ID_MAP.remove(channelId);
|
||||
SESSION_ID_MAP.remove(sessionId);
|
||||
CHANNEL_TO_USER_MAP.remove(channelId);
|
||||
CHANNEL_TO_CONNECTION_MAP.remove(channelId);
|
||||
}
|
||||
|
||||
public static void updateUserRole(String channelId, String role, int userId) {
|
||||
ClientConnection conn = CHANNEL_TO_CONNECTION_MAP.get(channelId);
|
||||
if (conn != null) {
|
||||
conn.setUserRole(role);
|
||||
conn.setUserId(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user