Changed: Now Disconnection request can be sent , (TUI,RMI,TCP)

This commit is contained in:
rubenpirreram
2026-05-25 16:31:29 +02:00
parent 68be7feff7
commit 36d348dc1e
11 changed files with 72 additions and 10 deletions
@@ -1,5 +1,6 @@
package it.polimi.ingsw.gc14; package it.polimi.ingsw.gc14;
import it.polimi.ingsw.gc14.Controller.ClientController; import it.polimi.ingsw.gc14.Controller.ClientController;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Character;
import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.RMI.Client.RMIClient; import it.polimi.ingsw.gc14.Network.RMI.Client.RMIClient;
import it.polimi.ingsw.gc14.Network.TCP.Client.TCPClient; import it.polimi.ingsw.gc14.Network.TCP.Client.TCPClient;
@@ -38,6 +39,7 @@ public class ClientLauncherTUI {
*/ */
public void main() throws InterruptedException { public void main() throws InterruptedException {
view = new TUI(null); view = new TUI(null);
admissibleChar.add("0");
admissibleChar.add("1"); admissibleChar.add("1");
admissibleChar.add("2"); admissibleChar.add("2");
admissibleChar.add("3"); admissibleChar.add("3");
@@ -137,7 +139,16 @@ public class ClientLauncherTUI {
if(admissibleChar.contains(action)) if(admissibleChar.contains(action))
{ {
if (!action.equals("6") && !action.equals("A") && !action.equals("B") && !action.equals("C")&&!action.equals("a") && !action.equals("b") && !action.equals("c")) { if(action.equals("0"))
{
System.out.println("Are you sure? Y/N");
String c= scanner.next();
if(!c.equals("Y") && !c.equals("y"))
{
view.render();
return;
}
}else if (!action.equals("6") && !action.equals("A") && !action.equals("B") && !action.equals("C")&&!action.equals("a") && !action.equals("b") && !action.equals("c")) {
try { try {
System.out.println("Insert the required position:"); System.out.println("Insert the required position:");
pos = scanner.nextInt(); pos = scanner.nextInt();
@@ -147,6 +158,10 @@ public class ClientLauncherTUI {
} }
} }
switch (action) { switch (action) {
case "0" -> {
controller.disconnect();
System.exit(0);
}
case "1" -> controller.slotChoice(username, pos); case "1" -> controller.slotChoice(username, pos);
case "2" -> controller.drawUpperTribeCard(username, pos); case "2" -> controller.drawUpperTribeCard(username, pos);
case "3" -> controller.drawUpperBuildingCard(username, pos); case "3" -> controller.drawUpperBuildingCard(username, pos);
@@ -195,4 +195,9 @@ public class ClientController {
client.totemChoice(playerUsername, String.valueOf(miniModel.availableTotems.get(pos))); client.totemChoice(playerUsername, String.valueOf(miniModel.availableTotems.get(pos)));
} }
} }
public void disconnect()
{
client.notifyDisconnection();
}
} }
@@ -70,4 +70,7 @@ public interface IClient {
* @param totem the name of the selected totem. * @param totem the name of the selected totem.
*/ */
void totemChoice(String playerUsername, String totem); void totemChoice(String playerUsername, String totem);
//TODO
void notifyDisconnection();
} }
@@ -124,7 +124,7 @@ public class RMIClient implements IClient {
if (!running) return; if (!running) return;
running = false; running = false;
if (pingSender != null) pingSender.shutdownNow(); if (pingSender != null) pingSender.shutdownNow();
controller.view.showError("Connessione al server persa"); controller.view.showError("Connection with server closed");
} }
@@ -235,5 +235,15 @@ public class RMIClient implements IClient {
} }
} }
public void notifyDisconnection() {
pingSender.shutdownNow();
try{
stub.disconnectPlayer(username);
}
catch (RemoteException e){
System.out.println("Error during remote disconnection");
}
}
} }
@@ -93,4 +93,6 @@ public interface IGameServer extends Remote {
* @throws RemoteException if an RMI communication error occurs. * @throws RemoteException if an RMI communication error occurs.
*/ */
void ping(String username) throws RemoteException; void ping(String username) throws RemoteException;
void disconnectPlayer(String username) throws RemoteException;
} }
@@ -89,7 +89,7 @@ public class RMIHeartbeat {
* the associated RMI callback is removed, and a disconnection event is * the associated RMI callback is removed, and a disconnection event is
* added to the action queue for server-side processing. * added to the action queue for server-side processing.
*/ */
private void disconnect() { public void disconnect() {
if (!running) return; if (!running) return;
running = false; running = false;
watchdog.shutdownNow(); watchdog.shutdownNow();
@@ -332,6 +332,10 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
watchdogs.put(username, wd); watchdogs.put(username, wd);
wd.start(); wd.start();
} }
public void disconnectPlayer(String username) {
RMIHeartbeat wd = watchdogs.get(username);
wd.disconnect();
}
@@ -107,8 +107,12 @@ public class TCPClient implements IClient {
ScheduledExecutorService sender = Executors.newSingleThreadScheduledExecutor(); ScheduledExecutorService sender = Executors.newSingleThreadScheduledExecutor();
sender.scheduleAtFixedRate(() -> { sender.scheduleAtFixedRate(() -> {
try { try {
heartbeatOut.write(PING); synchronized (heartbeatOut)
heartbeatOut.flush(); {
heartbeatOut.write(PING);
heartbeatOut.flush();
}
} catch (IOException e) { } catch (IOException e) {
sender.shutdownNow(); sender.shutdownNow();
disconnect(); disconnect();
@@ -263,4 +267,17 @@ public class TCPClient implements IClient {
public void totemChoice(String playerUsername,String totems) { public void totemChoice(String playerUsername,String totems) {
doEvent(new TotemChoice(playerUsername,totems)); doEvent(new TotemChoice(playerUsername,totems));
} }
public void notifyDisconnection()
{
synchronized (heartbeatOut)
{
try {
heartbeatOut.write(-1);
} catch (IOException e) {
disconnect();
}
}
disconnect();
}
} }
@@ -94,10 +94,9 @@ public class ClientHandler implements Runnable {
} }
} }
} catch (IOException e) { } catch (IOException e) {
clientHandlers.remove(this); System.err.println("Error in incoming connection/disconnection");
e.printStackTrace();
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new RuntimeException(e); System.err.println("Class not found");
} }
} }
@@ -94,7 +94,13 @@ public class HeartbeatHandler implements Runnable {
try { try {
while (running) { while (running) {
int b = in.read(); // blocca finché non arriva un byte int b = in.read(); // blocca finché non arriva un byte
if (b == -1) { disconnect(); break; } // stream chiusa if (b == -1) {
synchronized (this)
{
out.write(-1);
}
disconnect(); break;
} // stream chiusa
if (b == PING) { if (b == PING) {
lastReceivedTime = System.currentTimeMillis(); lastReceivedTime = System.currentTimeMillis();
out.write(PONG); out.write(PONG);
@@ -127,7 +133,7 @@ public class HeartbeatHandler implements Runnable {
* <p>The handler is stopped, the watchdog task is terminated, the main * <p>The handler is stopped, the watchdog task is terminated, the main
* {@link ClientHandler} is disconnected, and the heartbeat socket is closed. * {@link ClientHandler} is disconnected, and the heartbeat socket is closed.
*/ */
private void disconnect() { private synchronized void disconnect() {
running = false; running = false;
watchdog.shutdownNow(); watchdog.shutdownNow();
mainHandler.disconnect(); // disconnette anche il socket principale mainHandler.disconnect(); // disconnette anche il socket principale
@@ -257,6 +257,7 @@ public class TUI implements IView {
table.addRow(List.of("4-DrawLowerTribe(pos)", "")); table.addRow(List.of("4-DrawLowerTribe(pos)", ""));
table.addRow(List.of("5-DrawLowerBuilding(pos)", "")); table.addRow(List.of("5-DrawLowerBuilding(pos)", ""));
table.addRow(List.of("6-SkipTurn", "")); table.addRow(List.of("6-SkipTurn", ""));
table.addRow(List.of("0-Disconnect", ""));
return table.build(); return table.build();
} }