-
Notifications
You must be signed in to change notification settings - Fork 6
/
ldarchive.js
152 lines (141 loc) · 4.88 KB
/
ldarchive.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
Load .json[.gz] file archive into database.
*/
'use strict';
var
fs = require('graceful-fs'),
mysql = require('mysql'),
async = require('async'),
request = require('request'),
log4js = require('log4js'),
zlib = require('zlib'),
Q = require('q'),
ld = require('./ldcore.js');
var __dirname; // current working directory (defined by node.js)
var _logger; // log4js logger
var _config; // config data from cfg.json file
var _dbpool; // DB connection pool
var _conn; // DB connection
var _cookieJar; // www.quakelive.com login cookies
var _profilingInfo;
var program = require( 'commander' );
program
.version( '0.0.1' )
.option( '-c, --config <file>', 'Use a different config file. Default ./cfg.json' )
.option( '-d, --dir <directory>', 'Directory to scan' )
.option( '-l, --loglevel <LEVEL>', 'Default is DEBUG. levels: TRACE, DEBUG, INFO, WARN, ERROR, FATAL' )
.option( '-n, --nologin', 'Don\'t log in to quakelive.com. For use with */update & */get routes' )
.parse( process.argv );
main();
function main() {
_logger = log4js.getLogger( 'ldarchive' );
_logger.setLevel( program.loglevel || log4js.levels.DEBUG );
var data = fs.readFileSync( program.config || __dirname + '/cfg.json' );
_config = JSON.parse(data);
_config.loader.jsondir = program.dir;
_config.mysql_db.database = 'qlstats2_new';
_dbpool = mysql.createPool( _config.mysql_db );
Q.longStackSupport = false;
Q
.ninvoke(_dbpool, "getConnection")
.then(function (conn) {
_conn = conn;
return ld.init( conn, { loglevel: program.loglevel } );
})
.then(loadAndProcessJsonFileLoop)
.fail(function (err) { _logger.error(err.stack); })
.done(function () { _logger.info("completed"); process.exit(); });
}
//==========================================================================================
// file data feed
//==========================================================================================
function Stats() {
this.incProcessed = function() {
++this.total;
++this.processed;
}
this.incSkipped = function () {
++this.total;
++this.skipped;
}
this.reset = function () {
this.timestamp = new Date().getTime();
this.processed = 0;
this.skipped = 0;
}
this.reset();
this.total = 0;
this.timestamp0 = this.timestamp;
}
function loadAndProcessJsonFileLoop() {
_profilingInfo = new Stats();
setInterval(function() {
_logger.info("" + (_profilingInfo.processed / 30) + " games per sec (" + _profilingInfo.total + " total)");
_profilingInfo.reset();
}, 30000);
return loadAndProcessJsonFilesInDirectory(_config.loader.jsondir)
.then(function() {
var secs = (new Date().getTime() - _profilingInfo.timestamp0) / 1000;
_logger.info("Total time: " + secs + " sec. Game files found: " + _profilingInfo.total
+ ", loaded: " + _profilingInfo.processed + ", skipped: " + _profilingInfo.skipped);
});
}
function loadAndProcessJsonFilesInDirectory(dir) {
_logger.info("Loading data from " + dir + "*.json[.gz]");
return Q
.nfcall(fs.readdir, dir)
.then(function (files) {
var subDirs = [];
var tasks = files.map(function (file) {
var path = dir + file;
var stats = fs.statSync(path);
if (stats.isDirectory()) {
subDirs.push(path + "/");
return undefined;
} else
return function() { return processFile(path); }
});
subDirs.forEach(function(subdir) {
tasks.push(function() { return loadAndProcessJsonFilesInDirectory(subdir); });
});
return tasks.reduce(Q.when, Q(undefined));
});
}
function processFile(file) {
if (!file.match(/.json(.gz)?$/))
return undefined;
var isGzip = file.slice(-3) == ".gz";
var basename;
var match = file.match(/.*[\/\\]([^\.]*).*/);
if (match)
basename = match[1];
return Q
.fcall(function() { return basename ? ld.query("select ID from Game where PUBLIC_ID=?", [basename]) : []; })
.then(function (result) {
/*
if (result.length > 0) {
_logger.debug("Skipping " + file + " (already in database)");
_profilingInfo.incSkipped();
return true;
}
*/
return Q
.fcall(function() { _logger.debug("Loading " + file); })
.then(function() { return Q.nfcall(fs.readFile, file); })
.then(function(data) { return isGzip ? Q.nfcall(zlib.gunzip, data) : data; })
.then(function(json) {
var game = JSON.parse(json);
// changed from PUBLIC_ID to GAME_EXPIRES_FULL as it is the last object in the json
/*
if (!game.GAME_EXPIRES_FULL) {
//_logger.warn(file + ": no PUBLIC_ID in json data. File was ignored.");
_logger.warn(file + ": Incomplete json data. File was ignored.");
return undefined;
}
*/
return ld.processGame(game)
.then(function() { _profilingInfo.incProcessed(); });
});
})
.catch(function (err) { _logger.error(file + ": " + err); });
}