aboutsummaryrefslogtreecommitdiff
path: root/web/pw-server
diff options
context:
space:
mode:
Diffstat (limited to 'web/pw-server')
-rw-r--r--web/pw-server/src/lib/components/OutputPane.svelte80
-rw-r--r--web/pw-server/src/lib/log_parser.ts55
2 files changed, 134 insertions, 1 deletions
diff --git a/web/pw-server/src/lib/components/OutputPane.svelte b/web/pw-server/src/lib/components/OutputPane.svelte
index 759fd4c..efd0d2c 100644
--- a/web/pw-server/src/lib/components/OutputPane.svelte
+++ b/web/pw-server/src/lib/components/OutputPane.svelte
@@ -4,6 +4,8 @@
export let matchLog: string;
let playerLog: PlayerLog;
+ let showRawStderr = false;
+
$: if (matchLog) {
playerLog = parsePlayerLog(1, matchLog);
} else {
@@ -13,9 +15,38 @@
<div class="output">
<h3 class="output-header">Player log</h3>
+ {#if showRawStderr}
<div class="output-text stderr-text">
{playerLog.flatMap((turn) => turn.stderr).join("\n")}
</div>
+ {:else}
+ <div class="output-text">
+ {#each playerLog as logTurn, i}
+ <div class="turn">
+ <div class="turn-header">
+ <span class="turn-header-text">Turn {i}</span>
+ {#if logTurn.action?.type === "bad_command"}
+ <span class="turn-error">invalid command</span>
+ {/if}
+ </div>
+ {#if logTurn.action?.type === "bad_command"}
+ <div class="bad-command-container">
+ <div class="bad-command-text">{logTurn.action.command}</div>
+ <div class="bad-command-error">Parse error: {logTurn.action.error}</div>
+ </div>
+ {/if}
+ {#if logTurn.stderr.length > 0}
+ <div class="stderr-header">stderr</div>
+ <div class="stderr-text-box">
+ {#each logTurn.stderr as stdErrMsg}
+ <div class="stderr-text">{stdErrMsg}</div>
+ {/each}
+ </div>
+ {/if}
+ </div>
+ {/each}
+ </div>
+ {/if}
</div>
<style lang="scss">
@@ -26,15 +57,62 @@
padding: 15px;
}
+ .turn {
+ margin: 16px 4px;
+ }
+
.output-text {
color: #ccc;
}
+ .turn-header {
+ display: flex;
+ justify-content: space-between;
+ }
+
+ .turn-header-text {
+ color: #eee;
+ font-size: 14px;
+ font-weight: 600;
+ text-transform: uppercase;
+ }
+
+ .turn-error {
+ color: red;
+ }
+
+ .bad-command-container {
+ border-left: 1px solid red;
+ margin-left: 4px;
+ padding-left: 8px;
+ }
+
+ .bad-command-text {
+ font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
+ padding-bottom: 4px;
+ }
+
+ .bad-command-error {
+ color: whitesmoke;
+ }
+
.stderr-text {
- font-family: monospace;
+ // font-family: monospace;
+ font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
white-space: pre-wrap;
}
+ .stderr-header {
+ color: #eee;
+ padding-top: 4px;
+ }
+
+ .stderr-text-box {
+ border-left: 1px solid #ccc;
+ margin-left: 4px;
+ padding-left: 8px;
+ }
+
.output-header {
color: #eee;
padding-bottom: 20px;
diff --git a/web/pw-server/src/lib/log_parser.ts b/web/pw-server/src/lib/log_parser.ts
new file mode 100644
index 0000000..77c459f
--- /dev/null
+++ b/web/pw-server/src/lib/log_parser.ts
@@ -0,0 +1,55 @@
+export type PlayerLog = PlayerLogTurn[];
+
+export type PlayerLogTurn = {
+ action?: PlayerAction;
+ stderr: string[];
+};
+
+type PlayerAction = BadCommand;
+
+type BadCommand = {
+ type: "bad_command";
+ command: string;
+ error: string;
+};
+
+function createEmptyLogTurn(): PlayerLogTurn {
+ return {
+ stderr: [],
+ };
+}
+
+export function parsePlayerLog(playerId: number, logText: string): PlayerLog {
+ const logLines = logText.split("\n").slice(0, -1);
+
+ const playerLog: PlayerLog = [];
+
+ let turn = null;
+
+ logLines.forEach((logLine) => {
+ const logMessage = JSON.parse(logLine);
+
+ if (logMessage["type"] === "gamestate") {
+ if (turn) {
+ playerLog.push(turn);
+ turn = createEmptyLogTurn();
+ }
+ } else if (logMessage["player_id"] === playerId) {
+ if (!turn) {
+ // older match logs don't have an initial game state due to a bug.
+ turn = createEmptyLogTurn();
+ }
+ switch (logMessage["type"]) {
+ case "stderr": {
+ let msg = logMessage["message"];
+ turn.stderr.push(msg);
+ }
+ case "bad_command": {
+ turn.action = logMessage;
+ }
+ }
+ }
+ });
+
+ return playerLog;
+}