@ -1,25 +1,34 @@
'use strict' ;
'use strict' ;
var tz_offset = 240 ; //subtract this from server time to get local time; 4hrs is 240; 5hrs is 300
//TODO: handle tz_offset not divisible by 60
//var selected_date_s = null;
//selected_date_s = "2018-05-08";
var express = require ( 'express' ) ,
var express = require ( 'express' ) ,
//var exphbs = require("express-handlebars");
//var exphbs = require("express-handlebars");
// exphbs = require('../../'); // "express-handlebars"
// exphbs = require('../../'); // "express-handlebars"
cookieParser = require ( 'cookie-parser' ) ,
cookieParser = require ( 'cookie-parser' ) ,
bodyParser = require ( 'body-parser' ) ,
bodyParser = require ( 'body-parser' ) ,
//session = require('express-session'),
//session = require('express-session'),
fs = require ( 'fs' ) ;
fs = require ( 'fs' ) ,
readlines = require ( 'n-readlines' ) ;
const os = require ( 'os' ) ;
const os = require ( 'os' ) ;
var app = express ( ) ;
var app = express ( ) ;
//app.engine('handlebars', exphbs({defaultLayout: 'main'}));
//app.engine('handlebars', exphbs({defaultLayout: 'main'}));
//app.set('view engine', 'handlebars');
//app.set('view engine', 'handlebars');
var players = [ ] ;
var players = [ ] ;
var player_indices = { } ;
//see https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction
//see https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction
var prev_line = null ;
var prev_line = null ;
//#region derived from mtsenliven.py
//#region derived from mtsenliven.py
var msg_flags = [ "WARNING[Server]: " , "ACTION[Server]: " ]
var msgprefix_flags = [ "WARNING[Server]: " , "ACTION[Server]: " ]
var msg_lists = { } // where flag is key
var msgprefix_lists = { } // where flag is key
for ( flag in msg_flags ) {
var mf_len = msgprefix_flags . length ;
msg_lists [ flag ] = [ ] ;
for ( var mf_i = 0 ; mf_i < mf_len ; mf_i ++ ) {
msgprefix_lists [ msgprefix_flags [ mf_i ] ] = [ ] ;
}
}
var non_unique_wraps = [ ] ;
var non_unique_wraps = [ ] ;
@ -33,32 +42,98 @@ var unique_flags = [
] ;
] ;
//#endregion derived from mtsenliven.py
//#endregion derived from mtsenliven.py
function process_logline ( line ) {
function process_logline ( line , line_number , selected_date_s ) {
var player_name = "" ;
//TODO: use store_unique_log_data instead of this function
var player_name = null ;
var verb = "" ;
var verb = "" ;
index = - 1 ;
var time_s = "" ;
var date_s = "" ;
if ( player_name != "" ) {
var player_ip = null ;
if ( player_indices . hasOwnProperty ( player_name ) ) {
const time_start_i = 11 ;
index = player_indices [ player_name ] ;
var uf_len = unique_flags . length ;
mf_len = msgprefix_flags . length ;
var verb_i = - 1 ;
var verb_number = - 1 ;
var msgprefix_i = - 1 ;
var msgprefix_number = - 1 ;
var msgprefix = null ;
var index_msg = "" ;
for ( var mf_i = 0 ; mf_i < mf_len ; mf_i ++ ) {
msgprefix_i = line . indexOf ( msgprefix_flags [ mf_i ] ) ;
if ( msgprefix_i > - 1 ) {
msgprefix_number = mf_i ;
msgprefix = msgprefix_flags [ mf_i ] ;
break ;
}
}
var skip_date_enable = false ;
for ( var uf_i = 0 ; uf_i < uf_len ; uf_i ++ ) {
verb_i = line . indexOf ( unique_flags [ uf_i ] ) ;
if ( verb_i > - 1 ) {
verb_number = uf_i ;
verb = unique_flags [ uf_i ] ;
date_s = line . substring ( 0 , 10 ) . trim ( ) ;
if ( selected_date_s == null || selected_date_s == date_s ) {
//console.log("(verbose message in process_logline) using '" + date_s + "' since selected '"+selected_date_s+"'");
time_s = line . substring ( time_start_i , time_start_i + 8 ) ;
//console.log("using time "+time_s);
if ( msgprefix != null ) {
player_name = line . substring ( msgprefix_i + msgprefix . length , verb_i ) . trim ( ) ;
var ip_flag = " [" ;
var ip_i = player_name . indexOf ( ip_flag ) ;
if ( ip_i > - 1 ) {
player_ip = player_name . substring ( ip_i + ip_flag . length , player_name . length - 1 ) ;
player_name = player_name . substring ( 0 , ip_i ) ;
}
}
else {
player_name = "<missing msgprefix&rt;" ;
}
}
else {
skip_date_enable = true ;
//console.log("WARNING in process_logline: skipping '" + date_s + "' since not '"+selected_date_s+"'");
}
break ;
}
}
var index = - 1 ; // player index
if ( player_name != null ) {
if ( player_name . length > 0 ) {
if ( player_indices . hasOwnProperty ( player_name ) ) {
index = player_indices [ player_name ] ;
index_msg = "cached " ;
}
else {
index = players . length ;
//players.push({});
players [ index ] = { } ;
players [ index ] . display_name = player_name ;
player_indices [ player_name ] = index ;
//console.log("created new index "+index);
}
}
}
else {
else {
index = player_count ;
console . log ( "WARNING in process_logline: zero-length player name" ) ;
players [ index ] = { } ;
players [ index ] . display_name = player_name ;
player_count ++ ;
}
}
}
if ( index < 0 && ! skip_date_enable ) {
//console.log("(verbose message in process_logline) "+index_msg+"index was '"+index+"' but date was good '" + date_s + "' for '"+line+"'");
}
}
if ( verb == "leaves game" ) {
if ( verb == "leaves game" ) {
players [ index ] . logout_time = "" ;
if ( index > - 1 ) {
players [ index ] . logout_time = time_s ;
}
}
}
else if ( verb == "joins game" ) {
else if ( verb == "joins game" ) {
players [ index ] . login_time = "" ;
if ( index > - 1 ) {
//console.log("using index " + index);
players [ index ] . login_time = time_s ;
}
}
}
}
}
function relog_unique_only ( output , err_flag = false ) {
function store_unique_log_data ( output , line_number , err_flag = false ) {
var ret = "" ;
var ret = "" ;
var output_strip = output . trim ( ) ;
var output_strip = output . trim ( ) ;
var u_prefix = "active block modifiers took " ;
var u_prefix = "active block modifiers took " ;
@ -76,13 +151,13 @@ function relog_unique_only(output, err_flag=false) {
}
}
}
}
if ( ! always_show_enable ) {
if ( ! always_show_enable ) {
var mf_len = msg_flags . length ;
var mf_len = msgprefix _flags . length ;
for ( var mf_i = 0 ; mf_i < mf_len ; mf_i ++ ) {
for ( var mf_i = 0 ; mf_i < mf_len ; mf_i ++ ) {
// such as '2018-02-06 21:08:06: WARNING[Server]: Deprecated call to get_look_yaw, use get_look_horizontal instead'
// such as '2018-02-06 21:08:06: WARNING[Server]: Deprecated call to get_look_yaw, use get_look_horizontal instead'
// or 2018-02-06 21:08:05: ACTION[Server]: [playereffects] Wrote playereffects data into /home/owner/.minetest/worlds/FCAGameAWorld/playereffects.mt.
// or 2018-02-06 21:08:05: ACTION[Server]: [playereffects] Wrote playereffects data into /home/owner/.minetest/worlds/FCAGameAWorld/playereffects.mt.
f_i = output . find ( msg_flags [ mf_i ] ) ;
f_i = output . find ( msgprefix _flags [ mf_i ] ) ;
if ( f_i >= 0 ) {
if ( f_i >= 0 ) {
found_flag = msg_flags [ mf_i ] ;
found_flag = msgprefix _flags [ mf_i ] ;
break ;
break ;
}
}
}
}
@ -98,11 +173,11 @@ function relog_unique_only(output, err_flag=false) {
break ;
break ;
}
}
}
}
if ( msg_lists [ found_flag ] . indexOf ( sub_msg ) > - 1 ) {
if ( msgprefix _lists [ found_flag ] . indexOf ( sub_msg ) > - 1 ) {
show_enable = false ;
show_enable = false ;
}
}
else {
else {
msg_lists [ found_flag ] . push ( sub_msg ) ;
msgprefix _lists [ found_flag ] . push ( sub_msg ) ;
}
}
}
}
}
}
@ -114,9 +189,10 @@ function relog_unique_only(output, err_flag=false) {
}
}
return ret ;
return ret ;
}
}
var cached_date = null ;
app . get ( '/' , function ( req , res ) {
app . get ( '/' , function ( req , res ) {
var ret = "" ;
var ret = "" ;
ret += '<html><body style="font-family:calibri,sans">' ;
// Whenever server starts the following is logged
// Whenever server starts the following is logged
// (see also etc/example-input.txt):
// (see also etc/example-input.txt):
//
//
@ -124,11 +200,47 @@ app.get('/', function (req, res) {
// Separator
// Separator
//-------------
//-------------
//
//
ret += os . homedir ( ) ;
var selected_date_s = null ;
if ( req . query . date ) selected_date_s = req . query . date
ret += "assuming minetestserver ran as: " + os . homedir ( ) + "<br/>\n" ;
ret += "timezone (tz_offset/60*-1): " + ( Math . floor ( tz_offset / 60 ) * - 1 ) + "<br/>\n" ;
ret += "date (this YYYY-MM-DD filter limits all log processing): " + selected_date_s + "<br/>\n" ;
if ( selected_date_s == null ) {
ret += '<a href="?date=2018-05-08">2018-05-08</a>' ;
}
if ( cached_date != selected_date_s && selected_date_s != null ) {
cached_date = selected_date_s ;
players = [ ] ;
player_indices = [ ] ;
var log_paths = [ os . homedir ( ) + "/.minetest/debug_archived/2018/05/08.txt" , os . homedir ( ) + "/.minetest/debug.txt" ] ;
var lp_len = log_paths . length ;
for ( var lp_i = 0 ; lp_i < lp_len ; lp_i ++ ) {
var this_log_path = log_paths [ lp_i ] ;
console . log ( "EnlivenMinetest webapp reading '" + this_log_path + "'..." ) ;
var line_number = 1 ;
if ( fs . existsSync ( this_log_path ) ) {
//uses n-readlines package: see https://stackoverflow.com/questions/34223065/read-lines-synchronously-from-file-in-node-js
var liner = new readlines ( this_log_path ) ;
var next = true ;
while ( next ) {
next = liner . next ( ) ;
if ( next != false ) {
process_logline ( next . toString ( 'ascii' ) , line_number , selected_date_s ) ;
line_number ++ ;
}
}
}
else {
console . log ( "WARNING: file not found: '" + this_log_path + "' (listing actual archived log folders is not yet implemented, so this is a hard-coded demo folder only on poikilos' server)" ) ;
}
}
}
//see ~/.minetest/debug.txt
//see ~/.minetest/debug.txt
//and logs archived by EnlivenMinetest:
//and logs archived by EnlivenMinetest:
//~/.minetest/debug_archived/2018/05/08.txt
//~/.minetest/debug_archived/2018/05/08.txt
var ret += ` <canvas id="myCanvas" width="100" height="1540"> <!--style="border:1px solid #c3c3c3;">-->
ret += ` <canvas id="myCanvas" width="100" height="1540"> <!--style="border:1px solid #c3c3c3;">-->
Your browser does not support the canvas element .
Your browser does not support the canvas element .
< / c a n v a s >
< / c a n v a s >
< div style = "color:gray" id = "outputArea" > loading ... < / d i v >
< div style = "color:gray" id = "outputArea" > loading ... < / d i v >
@ -161,12 +273,6 @@ outputE.innerHTML = stats_html;`;
var arrayLength = players . length ;
var arrayLength = players . length ;
player_count = 0 ;
player_indices = { } ;
var index = - 1 ;
for ( ) {
process_logline ( line ) ;
}
for ( var i = 0 ; i < arrayLength ; i ++ ) {
for ( var i = 0 ; i < arrayLength ; i ++ ) {
ret += 'players[' + i + '] = {};' + "\n" ;
ret += 'players[' + i + '] = {};' + "\n" ;
ret += 'players[' + i + '].login_time = "' + players [ i ] . login_time + '";' + "\n" ;
ret += 'players[' + i + '].login_time = "' + players [ i ] . login_time + '";' + "\n" ;
@ -179,8 +285,9 @@ var ctx = canvas.getContext("2d");
ctx . font = text_size + "px Arial" ;
ctx . font = text_size + "px Arial" ;
var arrayLength = players . length ;
var arrayLength = players . length ;
var text_x ;
var text_x ;
var index = - 1 ;
var index = - 1 ; `
for ( var i = 0 ; index < arrayLength ; i ++ ) {
ret += 'var tz_offset = ' + tz_offset + ';' ;
ret += ` for (var i = 0; index < arrayLength; i++) {
text_x = text_start_x ;
text_x = text_start_x ;
ctx . fillStyle = "#dce5ea" ;
ctx . fillStyle = "#dce5ea" ;
ctx . fillRect ( 0 , border_y + 1.0 , player_name_width , row_y_offset - 1.0 ) ;
ctx . fillRect ( 0 , border_y + 1.0 , player_name_width , row_y_offset - 1.0 ) ;
@ -213,7 +320,13 @@ for (var i = 0; index < arrayLength; i++) {
ctx . fillText ( players [ index ] . display_name , text_x , text_y ) ;
ctx . fillText ( players [ index ] . display_name , text_x , text_y ) ;
var border_x = border_start_x ;
var border_x = border_start_x ;
var login_places = players [ index ] . login_time . split ( ':' ) ;
var login_places = players [ index ] . login_time . split ( ':' ) ;
if ( login_places . length >= 3 ) {
login_places [ 0 ] -= Math . floor ( tz_offset / 60 ) ;
}
var logout_places = players [ index ] . logout_time . split ( ':' ) ;
var logout_places = players [ index ] . logout_time . split ( ':' ) ;
if ( logout_places . length >= 3 ) {
logout_places [ 0 ] -= Math . floor ( tz_offset / 60 ) ;
}
var login_second = ( + login_places [ 0 ] ) * 60 * 60 + ( + login_places [ 1 ] ) * 60 + ( + login_places [ 2 ] ) ;
var login_second = ( + login_places [ 0 ] ) * 60 * 60 + ( + login_places [ 1 ] ) * 60 + ( + login_places [ 2 ] ) ;
var login_m = login_second / 60.0 ;
var login_m = login_second / 60.0 ;
var logout_second = ( + logout_places [ 0 ] ) * 60 * 60 + ( + logout_places [ 1 ] ) * 60 + ( + logout_places [ 2 ] ) ;
var logout_second = ( + logout_places [ 0 ] ) * 60 * 60 + ( + logout_places [ 1 ] ) * 60 + ( + logout_places [ 2 ] ) ;
@ -236,16 +349,16 @@ for (var i = 0; index < arrayLength; i++) {
index ++ ;
index ++ ;
}
}
< / s c r i p t > ` ;
< / s c r i p t > ` ;
ret += '</body></html>' ;
res . send ( ret ) ;
res . send ( ret ) ;
//res.render('home');
//res.render('home');
} ) ;
} ) ;
var server = app . listen ( 3000 , function ( ) {
var server = app . listen ( 3000 , function ( ) {
//console.log('express-handlebars example server listening on: 3000');
//console.log('express-handlebars example server listening on: 3000');
var host = server . address ( ) . address ;
var host = server . address ( ) . address ;
var port = server . address ( ) . port ;
var port = server . address ( ) . port ;
var this_log_path = os . homedir ( ) + "/.minetest/debug_archived/2018/05/08.txt" ;
console . log ( "EnlivenMinetest webapp reading '" + this_log_path + "'..." ) ;
console . log ( "EnlivenMinetest webapp listening at http://%s:%s" , host , port ) ;
console . log ( "EnlivenMinetest webapp listening at http://%s:%s" , host , port ) ;
} ) ;
} ) ;