1
|
|
|
<?php |
2
|
|
|
namespace PHPDaemon\Examples; |
3
|
|
|
|
4
|
|
|
use PHPDaemon\HTTPRequest\Generic; |
5
|
|
|
|
6
|
|
|
/** |
7
|
|
|
* @package GameMonitor |
8
|
|
|
* |
9
|
|
|
* @author Vasily Zorin <[email protected]> |
10
|
|
|
*/ |
11
|
|
|
// db.servers.ensureIndex({address:1}, {unique:true}); |
|
|
|
|
12
|
|
|
class GameMonitor extends \PHPDaemon\Core\AppInstance |
13
|
|
|
{ |
14
|
|
|
public $client; |
15
|
|
|
public $db; |
16
|
|
|
public $servers; |
17
|
|
|
public $jobMap = []; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Constructor. |
21
|
|
|
* @return void |
22
|
|
|
*/ |
23
|
|
|
public function init() |
24
|
|
|
{ |
25
|
|
|
if ($this->isEnabled()) { |
26
|
|
|
$this->client = \PHPDaemon\Clients\Valve\Pool::getInstance(); |
27
|
|
|
$this->db = \MongoClient::getInstance(); |
28
|
|
|
$this->servers = $this->db->{$this->config->dbname->value . '.servers'}; |
29
|
|
|
} |
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Creates Request. |
34
|
|
|
* @param object Request. |
35
|
|
|
* @param object Upstream application instance. |
36
|
|
|
* @return GameMonitorHTTPRequest Request. |
37
|
|
|
*/ |
38
|
|
|
public function beginRequest($req, $upstream) |
39
|
|
|
{ |
40
|
|
|
return new GameMonitorHTTPRequest($this, $upstream, $req); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Called when the worker is ready to go. |
45
|
|
|
* @return void |
46
|
|
|
*/ |
47
|
|
|
public function onReady() |
48
|
|
|
{ |
49
|
|
|
if ($this->isEnabled()) { |
50
|
|
|
$this->updateTimer = setTimeout(function ($timer) { |
|
|
|
|
51
|
|
|
$this->updateAllServers(); |
52
|
|
|
$timer->timeout(2e6); |
53
|
|
|
}, 1); |
54
|
|
|
} |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
public function updateAllServers() |
58
|
|
|
{ |
59
|
|
|
gc_collect_cycles(); |
60
|
|
|
$app = $this; |
61
|
|
|
$amount = 1000 - sizeof($this->jobMap); |
62
|
|
|
\PHPDaemon\Core\Daemon::log('amount: ' . $amount); |
63
|
|
|
if ($amount <= 0) { |
64
|
|
|
return; |
65
|
|
|
} |
66
|
|
|
$this->servers->find(function ($cursor) use ($app, $amount) { |
67
|
|
|
if (isset($cursor->items[0]['$err'])) { |
68
|
|
|
\PHPDaemon\Core\Daemon::log(\PHPDaemon\Core\Debug::dump($cursor->items)); |
69
|
|
|
return; |
70
|
|
|
} |
71
|
|
|
foreach ($cursor->items as $server) { |
72
|
|
|
$app->updateServer($server); |
73
|
|
|
} |
74
|
|
|
$cursor->destroy(); |
75
|
|
|
}, [ |
76
|
|
|
'where' => [ |
77
|
|
|
'$or' => [ |
78
|
|
|
['atime' => ['$lte' => time() - 30], 'latency' => ['$ne' => false]], |
79
|
|
|
['atime' => ['$lte' => time() - 120], 'latency' => false], |
80
|
|
|
['atime' => null], |
81
|
|
|
//['address' => 'dimon4ik.no-ip.org:27016'], |
|
|
|
|
82
|
|
|
|
83
|
|
|
] |
84
|
|
|
], |
85
|
|
|
//'fields' => '_id,atime,address', |
|
|
|
|
86
|
|
|
'limit' => -max($amount, 100), |
87
|
|
|
'sort' => ['atime' => 1], |
88
|
|
|
]); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
public function updateServer($server) |
92
|
|
|
{ |
93
|
|
|
if (!isset($server['address'])) { |
94
|
|
|
return; |
95
|
|
|
} |
96
|
|
|
$server['address'] = trim($server['address']); |
97
|
|
|
$app = $this; |
98
|
|
|
if (isset($app->jobMap[$server['address']])) { |
99
|
|
|
//\PHPDaemon\Daemon::log('already doing: '.$server['address']); |
|
|
|
|
100
|
|
|
return; |
101
|
|
|
} |
102
|
|
|
$job = new \PHPDaemon\Core\ComplexJob(function ($job) use ($app, $server) { |
103
|
|
|
unset($app->jobMap[$server['address']]); |
104
|
|
|
//\PHPDaemon\Daemon::log('Removed job for '.$server['address']. ' ('.sizeof($app->jobMap).')'); |
|
|
|
|
105
|
|
|
$set = $job->results['info']; |
106
|
|
|
$set['address'] = $server['address']; |
107
|
|
|
$set['players'] = $job->results['players']; |
108
|
|
|
$set['latency'] = $job->results['latency']; |
109
|
|
|
$set['atime'] = time(); |
110
|
|
|
if (0) { |
111
|
|
|
\PHPDaemon\Core\Daemon::log('Updated server (' . round(memory_get_usage(true) / 1024 / 1024, |
112
|
|
|
5) . '): ' . $server['address'] . ' latency = ' . round($set['latency'] * 1000, 2) . ' ==== ' |
113
|
|
|
. (isset($server['atime']) ? |
114
|
|
|
round($set['atime'] - $server['atime']) . ' secs. from last update.' |
115
|
|
|
: ' =---= ' . json_encode($server)) |
116
|
|
|
); |
117
|
|
|
} |
118
|
|
|
try { |
119
|
|
|
$app->servers->upsert(['_id' => $server['_id']], ['$set' => $set]); |
120
|
|
|
} catch (\MongoException $e) { |
121
|
|
|
\PHPDaemon\Core\Daemon::uncaughtExceptionHandler($e); |
122
|
|
|
$app->servers->upsert(['_id' => $server['_id']], ['$set' => ['atime' => time()]]); |
123
|
|
|
} |
124
|
|
|
}); |
125
|
|
|
$app->jobMap[$server['address']] = $job; |
126
|
|
|
//\PHPDaemon\Daemon::log('Added job for '.$server['address']); |
|
|
|
|
127
|
|
|
|
128
|
|
|
$job('info', function ($jobname, $job) use ($app, $server) { |
129
|
|
|
$app->client->requestInfo($server['address'], |
130
|
|
|
function ($conn, $result) use ($app, $server, $jobname, $job) { |
131
|
|
|
|
132
|
|
|
$job('players', function ($jobname, $job) use ($app, $server, $conn) { |
133
|
|
|
|
134
|
|
|
$conn->requestPlayers(function ($conn, $result) use ($app, $jobname, $job) { |
135
|
|
|
|
136
|
|
|
$job->setResult($jobname, $result); |
137
|
|
|
$conn->finish(); |
138
|
|
|
|
139
|
|
|
}); |
140
|
|
|
}); |
141
|
|
|
|
142
|
|
|
$job->setResult($jobname, $result); |
143
|
|
|
}); |
144
|
|
|
}); |
145
|
|
|
|
146
|
|
|
$job('latency', function ($jobname, $job) use ($app, $server) { |
147
|
|
|
|
148
|
|
|
$app->client->ping($server['address'], function ($conn, $result) use ($app, $jobname, $job) { |
149
|
|
|
|
150
|
|
|
$job->setResult($jobname, $result); |
151
|
|
|
|
152
|
|
|
$conn->finish(); |
153
|
|
|
|
154
|
|
|
}); |
155
|
|
|
|
156
|
|
|
}); |
157
|
|
|
|
158
|
|
|
$job(); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Called when worker is going to update configuration. |
163
|
|
|
* @return void |
164
|
|
|
*/ |
165
|
|
|
public function onConfigUpdated() |
166
|
|
|
{ |
167
|
|
|
if ($this->client) { |
168
|
|
|
$this->client->config = $this->config; |
169
|
|
|
$this->client->onConfigUpdated(); |
170
|
|
|
} |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Called when application instance is going to shutdown. |
175
|
|
|
* @return boolean Ready to shutdown? |
176
|
|
|
*/ |
177
|
|
|
public function onShutdown() |
178
|
|
|
{ |
179
|
|
|
if ($this->client) { |
180
|
|
|
return $this->client->onShutdown(); |
181
|
|
|
} |
182
|
|
|
return true; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Setting default config options |
187
|
|
|
* Overriden from AppInstance::getConfigDefaults |
188
|
|
|
* Uncomment and return array with your default options |
189
|
|
|
* @return array|false |
190
|
|
|
*/ |
191
|
|
|
protected function getConfigDefaults() |
192
|
|
|
{ |
193
|
|
|
return [ |
194
|
|
|
'dbname' => 'gamemonitor', |
195
|
|
|
]; |
196
|
|
|
} |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
class GameMonitorHTTPRequest extends Generic |
|
|
|
|
200
|
|
|
{ |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Constructor. |
204
|
|
|
* @return void |
205
|
|
|
*/ |
206
|
|
|
public function init() |
207
|
|
|
{ |
208
|
|
|
$req = $this; |
209
|
|
|
|
210
|
|
|
$job = $this->job = new \PHPDaemon\Core\ComplexJob(function () use ($req) { // called when job is done |
|
|
|
|
211
|
|
|
|
212
|
|
|
$req->wakeup(); // wake up the request immediately |
213
|
|
|
|
214
|
|
|
}); |
215
|
|
|
|
216
|
|
|
$job('getServers', function ($name, $job) use ($req) { // registering job named 'pingjob' |
217
|
|
|
|
218
|
|
|
$req->appInstance->servers->find(function ($cursor) use ($name, $job) { |
|
|
|
|
219
|
|
|
$job->setResult($name, $cursor->items); |
220
|
|
|
}); |
221
|
|
|
}); |
222
|
|
|
|
223
|
|
|
$job(); // let the fun begin |
224
|
|
|
|
225
|
|
|
$this->sleep(5); // setting timeout |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Called when request iterated. |
230
|
|
|
* @return integer Status. |
|
|
|
|
231
|
|
|
*/ |
232
|
|
|
public function run() |
233
|
|
|
{ |
234
|
|
|
$this->header('Content-Type: text/html'); |
235
|
|
|
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
236
|
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
237
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml"> |
238
|
|
|
<head> |
239
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
240
|
|
|
<title>Game servers</title> |
241
|
|
|
</head> |
242
|
|
|
<body> |
243
|
|
|
</body> |
244
|
|
|
</html><?php |
245
|
|
|
|
246
|
|
|
} |
247
|
|
|
} |
248
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.