Create PsAdmin framework

PsAdmin uses a dedicated TCP port to allow for remote queries and
command to be sent to the running World/Login server. Commands are a
single command followed by zero or more arguments.

Commands may require access to the ActorSystem, so they will get their
own dedicated actors to be able to handle the different messages
required that can be sent in response to a query. The return line is in
JSON to allow for easy parsing by applications, such as web servers.
An interactive client is easy as being able to parse json and buffer
command input.

Some basic commands are implemented for now:

* shutdown - kills the actor system
* list_players - gets a list of players on the interstellar cluster
* dump_config - get the running config
* thread_dump - dumps all thread backtraces (useful for prod debugging)

More advanced commands like kick/ban will require additional testing.
This commit is contained in:
Chord 2020-01-26 02:04:17 +01:00
parent ceb58ed39a
commit 82e8840176
16 changed files with 418 additions and 7 deletions

View file

@ -190,6 +190,10 @@ trait ConfigParser {
config_map = map
}
def GetRawConfig : Map[String, Any] = {
config_map
}
def FormatErrors(invalidResult : Invalid) : Seq[String] = {
var count = 0;
@ -209,7 +213,7 @@ trait ConfigParser {
}
protected def parseSection(sectionIni : org.ini4j.Profile.Section, entry : ConfigEntry, map : Map[String, Any]) : ValidationResult = {
var rawValue = sectionIni.get(entry.key)
var rawValue = sectionIni.get(entry.key, 0)
val full_key : String = sectionIni.getName + "." + entry.key
val value = if (rawValue == null) {

View file

@ -64,6 +64,16 @@ class InterstellarCluster(zones : List[Zone]) extends Actor {
case None => //zone_number does not exist
sender ! Zone.Lattice.NoValidSpawnPoint(zone_number, None)
}
case InterstellarCluster.ListPlayers() =>
var players : List[String] = List()
for(zone <- zones) {
val zonePlayers = zone.Players
for (player <- zonePlayers) {
players ::= player.name
}
}
sender ! InterstellarCluster.PlayerList(players)
case msg @ Zone.Lattice.RequestSpecificSpawnPoint(zone_number, _, _, _) =>
recursiveFindWorldInCluster(zones.iterator, _.Number == zone_number) match {
@ -188,6 +198,9 @@ object InterstellarCluster {
*/
final case class GiveWorld(zoneId : String, zone : Zone)
final case class ListPlayers()
final case class PlayerList(players : List[String])
/**
* Signal to the cluster that a new client needs to be initialized for all listed `Zone` destinations.
* @see `Zone`