-
-
Save moiph/7977253 to your computer and use it in GitHub Desktop.
Server status / online players page for Starbound. Parses the log file to grab data.
Naturally this won't scale with an ever increasing log file, but does the job for now!
Hopefully Starbound will add server APIs to get the data in a more efficient manner :)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%@ Page Language="C#" AutoEventWireup="true" %> | |
<%@ Import Namespace="System.IO" %> | |
<%@ Import Namespace="System.Linq" %> | |
<%@ Import Namespace="System.Web" %> | |
<%@ Import Namespace="System.Net" %> | |
<%@ Import Namespace="System.Net.Sockets" %> | |
<script runat="server"> | |
//// This is a replica of https://gist.github.com/dkesberg/7926899, but built for asp.net instead of PHP. | |
//// CONFIGURATION | |
// set logpath | |
const string logPath = @"C:\steamcmd\starbound\starbound_server.log"; | |
const string serverIP = "YOUR IP HERE"; | |
const int serverPort = 21025; | |
const int connectionTimeout = 5; | |
//// END CONFIGURATION | |
public long startTime; | |
public bool serverIsRunning = true; | |
public string version = "Unknown"; | |
public IList<string> offlineClients; | |
public IList<string> onlineClients; | |
public Regex clientRx = new Regex("^Info:.*Client", RegexOptions.Compiled | RegexOptions.IgnoreCase); | |
public Regex clientDetailsRx = new Regex(@".*?'(.*?)'.*?\(.*?\)(.*)", RegexOptions.Compiled | RegexOptions.IgnoreCase); | |
protected override void OnLoad(EventArgs e) | |
{ | |
base.OnLoad(e); | |
startTime = DateTime.UtcNow.Millisecond; | |
// read the log file | |
var lines = new List<string>(); | |
try | |
{ | |
using (var fs = new FileStream(logPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) | |
{ | |
using (var sr = new StreamReader(fs)) | |
{ | |
while (!sr.EndOfStream) | |
{ | |
lines.Add(sr.ReadLine()); | |
} | |
} | |
} | |
} | |
catch (FileNotFoundException) | |
{ | |
// no log file. | |
} | |
// filter down to just the lines regarding clients connecting/disconnecting | |
var linesToUse = lines.Where(l => clientRx.IsMatch(l)); | |
var clients = new SortedDictionary<string, string>(); | |
// the same client may disconnect/reconnect multiple times. we just want the latest status. | |
// could traverse backwards and ignore dupe keys instead but ultimately we need to walk through all the lines anyway. | |
foreach (string logClient in linesToUse) | |
{ | |
Match clientMatch = clientDetailsRx.Match(logClient); | |
if (clientMatch.Success) | |
{ | |
string clientName = HttpUtility.HtmlEncode(clientMatch.Groups[1].Value.Trim()); | |
clients[clientName] = clientMatch.Groups[2].Value.Trim(); | |
} | |
} | |
// only keep "connected" status | |
onlineClients = clients.Where(kvp => kvp.Value == "connected").Select(kvp => kvp.Key).ToList(); | |
offlineClients = clients.Where(kvp => kvp.Value != "connected").Select(kvp => kvp.Key).ToList(); | |
// get server version | |
var logVersion = lines.Where(s => s.StartsWith("Info: Server version")); | |
if (logVersion.Count() > 0) | |
{ | |
string[] versionParts = logVersion.Last().Split(new char[] { '\'' }); | |
if (versionParts.Length > 1) | |
{ | |
version = versionParts[1]; | |
} | |
} | |
// verify that the server is online | |
var ipe = new IPEndPoint(IPAddress.Parse(serverIP), serverPort); | |
var tempSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp); | |
IAsyncResult result = tempSocket.BeginConnect(ipe, null, null); | |
bool success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(connectionTimeout), true); | |
if (success) | |
{ | |
tempSocket.EndConnect(result); | |
} | |
else | |
{ | |
tempSocket.Close(); | |
serverIsRunning = false; | |
} | |
} | |
</script> | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Starbound Server Info</title> | |
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"> | |
<style type="text/css"> | |
body { | |
padding-top: 70px; | |
} | |
table > tbody > tr > td.server-status { | |
vertical-align: middle; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation"> | |
<div class="container"> | |
<div class="navbar-header"> | |
<a class="navbar-brand" href="#">Starbound Server Info</a> | |
</div> | |
</div> | |
</div> | |
<div class="container"> | |
<div class="row"> | |
<div class="col-md-12"> | |
<div class="panel panel-default"> | |
<div class="panel-heading"><span class="glyphicon glyphicon-globe"></span> Server</div> | |
<div class="panel-body"> | |
<table class="table table-condensed table-bordered"> | |
<tbody> | |
<tr> | |
<th>Status</th> | |
<td class="server-status"> | |
<span class="label label-<%= serverIsRunning ? "success" : "danger" %>"> | |
<%= serverIsRunning ? "Online" : "Offline"%> | |
</span> | |
</td> | |
</tr> | |
<tr> | |
<th>Version</th> | |
<td><%= version %></td> | |
</tr> | |
<tr> | |
<th>IP</th> | |
<td><%= serverIP %></td> | |
</tr> | |
<tr> | |
<th>Players Online</th> | |
<td><%= onlineClients.Count() %></td> | |
</tr> | |
<tr> | |
<th>Players seen</th> | |
<td><%= onlineClients.Count() + offlineClients.Count() %></td> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col-md-12"> | |
<div class="panel panel-default"> | |
<div class="panel-heading"><span class="glyphicon glyphicon-user"></span> Players</div> | |
<div class="panel-body"> | |
<% if (onlineClients.Count() > 0) | |
{ %> | |
<table class="table table-condensed table-bordered"> | |
<thead> | |
<tr> | |
<th>Playername</th> | |
</tr> | |
</thead> | |
<tbody> | |
<% foreach (var client in onlineClients) | |
{ %> | |
<tr> | |
<td> | |
<%= client %> | |
</td> | |
</tr> | |
<% } %> | |
</tbody> | |
</table> | |
<% } else { %> | |
No active players | |
<% } %> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col-md-12"> | |
<span class="label label-default"> | |
Parse time: <%= DateTime.UtcNow.Millisecond - startTime %> ms. | |
</span> | |
</div> | |
</div> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment