|
|
@ -4,14 +4,22 @@ import eu.jonahbauer.wizard.common.messages.server.*;
|
|
|
|
import eu.jonahbauer.wizard.common.model.Configuration;
|
|
|
|
import eu.jonahbauer.wizard.common.model.Configuration;
|
|
|
|
import eu.jonahbauer.wizard.server.debug.DebugSession;
|
|
|
|
import eu.jonahbauer.wizard.server.debug.DebugSession;
|
|
|
|
import eu.jonahbauer.wizard.server.machine.Player;
|
|
|
|
import eu.jonahbauer.wizard.server.machine.Player;
|
|
|
|
|
|
|
|
import eu.jonahbauer.wizard.server.management.LobbyMBean;
|
|
|
|
|
|
|
|
import eu.jonahbauer.wizard.server.management.SessionMBean;
|
|
|
|
|
|
|
|
import lombok.extern.log4j.Log4j2;
|
|
|
|
import org.intellij.lang.annotations.Language;
|
|
|
|
import org.intellij.lang.annotations.Language;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import javax.management.MBeanServer;
|
|
|
|
|
|
|
|
import javax.management.ObjectName;
|
|
|
|
|
|
|
|
import javax.management.StandardMBean;
|
|
|
|
|
|
|
|
import java.lang.management.ManagementFactory;
|
|
|
|
import java.util.*;
|
|
|
|
import java.util.*;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
|
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
|
|
|
|
|
|
|
|
|
|
public class Lobby {
|
|
|
|
@Log4j2
|
|
|
|
|
|
|
|
public class Lobby implements LobbyMBean {
|
|
|
|
@Language("RegExp")
|
|
|
|
@Language("RegExp")
|
|
|
|
private static final String SESSION_NAME_PATTERN = "[a-zA-Z0-9_' ]{1,20}";
|
|
|
|
private static final String SESSION_NAME_PATTERN = "[a-zA-Z0-9_' ]{1,20}";
|
|
|
|
private static final Lobby INSTANCE = new Lobby();
|
|
|
|
private static final Lobby INSTANCE = new Lobby();
|
|
|
@ -19,12 +27,17 @@ public class Lobby {
|
|
|
|
return INSTANCE;
|
|
|
|
return INSTANCE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final MBeanServer mBeanServer;
|
|
|
|
|
|
|
|
|
|
|
|
private final Map<UUID, Session> sessions = new ConcurrentHashMap<>();
|
|
|
|
private final Map<UUID, Session> sessions = new ConcurrentHashMap<>();
|
|
|
|
private final List<Player> players = new ArrayList<>();
|
|
|
|
private final List<Player> players = new ArrayList<>();
|
|
|
|
// read lock is required whenever players are read or sessions are modified, write lock is required when players are modified
|
|
|
|
// read lock is required whenever players are read or sessions are modified, write lock is required when players are modified
|
|
|
|
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
|
|
|
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
|
|
|
|
|
|
|
|
|
|
|
private Lobby() {}
|
|
|
|
private Lobby() {
|
|
|
|
|
|
|
|
mBeanServer = ManagementFactory.getPlatformMBeanServer();
|
|
|
|
|
|
|
|
registerLobbyMBean();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Session createSession(@NotNull String name, long timeout, @NotNull Configuration configuration) {
|
|
|
|
public Session createSession(@NotNull String name, long timeout, @NotNull Configuration configuration) {
|
|
|
|
if (!name.matches(SESSION_NAME_PATTERN)) {
|
|
|
|
if (!name.matches(SESSION_NAME_PATTERN)) {
|
|
|
@ -42,6 +55,9 @@ public class Lobby {
|
|
|
|
session = new Session(UUID.randomUUID(), name, timeout, configuration);
|
|
|
|
session = new Session(UUID.randomUUID(), name, timeout, configuration);
|
|
|
|
} while (sessions.putIfAbsent(session.getUuid(), session) != null);
|
|
|
|
} while (sessions.putIfAbsent(session.getUuid(), session) != null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.info("Created session {}.", session.getUuid());
|
|
|
|
|
|
|
|
registerSessionMBean(session);
|
|
|
|
|
|
|
|
|
|
|
|
notifyPlayers(new SessionCreatedMessage(session.toData()));
|
|
|
|
notifyPlayers(new SessionCreatedMessage(session.toData()));
|
|
|
|
|
|
|
|
|
|
|
|
return session;
|
|
|
|
return session;
|
|
|
@ -58,6 +74,9 @@ public class Lobby {
|
|
|
|
session = new DebugSession(UUID.randomUUID(), name, timeout, configuration);
|
|
|
|
session = new DebugSession(UUID.randomUUID(), name, timeout, configuration);
|
|
|
|
} while (sessions.putIfAbsent(session.getUuid(), session) != null);
|
|
|
|
} while (sessions.putIfAbsent(session.getUuid(), session) != null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.info("Created debug session {}.", session.getUuid());
|
|
|
|
|
|
|
|
registerSessionMBean(session);
|
|
|
|
|
|
|
|
|
|
|
|
notifyPlayers(new SessionCreatedMessage(session.toData()));
|
|
|
|
notifyPlayers(new SessionCreatedMessage(session.toData()));
|
|
|
|
|
|
|
|
|
|
|
|
return session;
|
|
|
|
return session;
|
|
|
@ -73,8 +92,11 @@ public class Lobby {
|
|
|
|
public void removeSession(UUID uuid) {
|
|
|
|
public void removeSession(UUID uuid) {
|
|
|
|
lock.readLock().lock();
|
|
|
|
lock.readLock().lock();
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
sessions.remove(uuid);
|
|
|
|
if (sessions.remove(uuid) != null) {
|
|
|
|
|
|
|
|
log.info("Removed session {}.", uuid);
|
|
|
|
|
|
|
|
unregisterSessionMBean(uuid);
|
|
|
|
notifyPlayers(new SessionRemovedMessage(uuid));
|
|
|
|
notifyPlayers(new SessionRemovedMessage(uuid));
|
|
|
|
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
} finally {
|
|
|
|
lock.readLock().unlock();
|
|
|
|
lock.readLock().unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -117,4 +139,53 @@ public class Lobby {
|
|
|
|
lock.readLock().unlock();
|
|
|
|
lock.readLock().unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//<editor-fold desc="JMX" defaultstate="collapsed">
|
|
|
|
|
|
|
|
private void registerLobbyMBean() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
var name = new ObjectName("eu.jonahbauer.wizard.server:type=Lobby");
|
|
|
|
|
|
|
|
mBeanServer.registerMBean(new StandardMBean(this, LobbyMBean.class), name);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.warn("Could not register LobbyMBean.", e);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void registerSessionMBean(@NotNull Session session) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
var name = new ObjectName("eu.jonahbauer.wizard.server:type=Session,name=" + session.getUuid());
|
|
|
|
|
|
|
|
mBeanServer.registerMBean(new StandardMBean(session, SessionMBean.class), name);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.warn("Could not register SessionMBean for session {}.", session.getUuid(), e);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void unregisterSessionMBean(@NotNull UUID uuid) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
var name = new ObjectName("eu.jonahbauer.wizard.server:type=Session,name=" + uuid);
|
|
|
|
|
|
|
|
mBeanServer.unregisterMBean(name);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.warn("Could not unregister SessionMBean for session {}.", uuid, e);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public int getPlayerCount() {
|
|
|
|
|
|
|
|
lock.readLock().lock();
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
return players.size();
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
|
|
lock.readLock().unlock();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public int getTotalPlayerCount() {
|
|
|
|
|
|
|
|
return sessions.values().stream().mapToInt(Session::getPlayerCount).sum() + getPlayerCount();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public int getSessionCount() {
|
|
|
|
|
|
|
|
return sessions.size();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//</editor-fold>
|
|
|
|
}
|
|
|
|
}
|
|
|
|