hping 0.0.5 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ node-version: [20.x, 22.x, 24.x]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-node@v4
17
+ with:
18
+ node-version: ${{ matrix.node-version }}
19
+ cache: npm
20
+ - run: npm ci
21
+ - run: npm test
package/README.md CHANGED
@@ -1,54 +1,71 @@
1
1
  hPING (HTTP ping)
2
2
  =====
3
3
 
4
- Node.js CLI that sends HTTP HEAD or GET or POST requests to any web or api servers.
4
+ Node.js CLI that sends HTTP `HEAD`, `GET`, or `POST` requests to web/api servers.
5
5
 
6
- hPING is the fastest and easiest way to check or quickly monitor for http servers availability.
6
+ <img src="http://www.anothervision.com/img/github/hping.gif" width="1126"/>
7
+ hPING is a quick way to check and monitor HTTP server availability.
8
+
9
+ ## Node.js Support
10
+
11
+ - Supported: `Node.js 20+` (validated against current major runtimes, including Node `22+`).
7
12
 
8
13
  ## Installation
9
- The latest hPING version is installable via NPM:
14
+
15
+ hPING is installable via npm:
16
+
10
17
  ```bash
11
18
  $ npm install hping -g
12
19
  ```
13
- If the above fails try this:
14
- ```bash
15
- $ npm install git://github.com/kurdin/hping#master -g
16
- ```
17
- or
18
- ```bash
19
- $ git clone https://github.com/kurdin/hping
20
- $ cd hping
21
- $ npm install
22
- $ npm link
23
- ```
20
+
24
21
  ## Usage
25
22
 
26
- hPING single server ``www.google.com``:
23
+ hPING single server `www.google.com`:
24
+
27
25
  ```bash
28
- $ hping www.google.com
26
+ $ hping www.google.com
29
27
  ```
30
- hPING server ``www.google.com`` with 10 seconds interval:
28
+
29
+ hPING server `www.google.com` with a 10-second interval:
30
+
31
31
  ```bash
32
- $ hping www.google.com -i 10
32
+ $ hping www.google.com -i 10
33
33
  ```
34
- hPING single server with ``GET`` method:
34
+
35
+ hPING single server with `GET` method:
36
+
35
37
  ```bash
36
38
  $ hping get www.google.com
37
39
  ```
38
- hPING multiple servers ``www.google.com`` and ``www.apple.com`` and ``www.microsoft.com``):
40
+
41
+ hPING multiple servers:
42
+
39
43
  ```bash
40
44
  $ hping www.google.com www.apple.com www.microsoft.com
41
45
  ```
42
- hPING group of servers from config file (default config: ``~/.hping/hping.conf.yaml``):
46
+
47
+ hPING group of servers from config file (default config: `~/.hping/hping.conf.yaml`):
48
+
43
49
  ```bash
44
50
  $ hping "apple production"
45
51
  ```
52
+
46
53
  hPING can mix group of servers and separate hosts with single command:
54
+
47
55
  ```bash
48
56
  $ hping "apple production" www.github.com
49
57
  ```
58
+
59
+ Explicit `ping` command (modern style):
60
+
61
+ ```bash
62
+ $ hping ping www.google.com
63
+ ```
64
+
50
65
  ## Settings
51
- hPING default settings, default ``~/.hping/hping.conf.yaml``:
66
+
67
+ hPING default settings (`~/.hping/hping.conf.yaml`):
68
+
52
69
  ```bash
53
70
  interval: 1 # (seconds) interval between hPING requests
54
71
  type: HEAD # (type or requests): HEAD, GET, POST, PUT
@@ -68,80 +85,63 @@ display_in_output: # use true || fasle to turn on/off log output sections
68
85
  type: false
69
86
  status_code: true
70
87
  status_info: true
71
- server: true
72
- content_length: false
73
- response_time: true
88
+ server: true
89
+ content_length: false
90
+ response_time: true
74
91
  ```
75
- Show hPING server groups from config file, default ``~/.hping/hping.conf.yaml``:
92
+
93
+ Show hPING server groups:
94
+
76
95
  ```bash
77
96
  $ hping servers
78
- "microsoft live":
79
- "http://www.live.com"
80
- "http://www.live.fr"
81
- "http://www.live.de"
82
- "http://www.live.ru"
83
- "http://www.live.com/api"
84
-
85
- "apple production":
86
- "http://www.apple.com"
87
- "http://www.icloud.com"
88
- "https://itunes.apple.com"
89
-
90
- "eurohosting":
91
- "http://www.leaseweb.eu"
92
- "http://www.hetzner.de"
93
- "http://www.1and1.co.uk"
94
97
  ```
98
+
95
99
  Display hPING current settings:
100
+
96
101
  ```bash
97
102
  $ hping settings
98
103
  ```
99
- hPING server ``www.goolge.com`` and use settings from config file ``/etc/hping.conf.yaml``:
104
+
105
+ hPING server `www.google.com` with custom config:
106
+
100
107
  ```bash
101
- $ hping www.google.com -c /etc/hping.conf.yaml
108
+ $ hping www.google.com -c /etc/hping.conf.yaml
102
109
  ```
110
+
103
111
  ## Help
112
+
104
113
  hPING quick usage help:
114
+
105
115
  ```bash
106
116
  $ hping
107
- usage: hping [head|get|post] [http(s)://]www.webserver.com[:port] [another host] [server group]
117
+ usage: hping [ping|head|get|post] [http(s)://]www.webserver.com[:port] [another host] [server group]
108
118
  ```
119
+
109
120
  hPING full help:
121
+
110
122
  ```bash
111
123
  $ hping -h
112
- Usage: hping [head|get|post] [http(s)://]www.webserver.com[:port] [another host] [server group]
113
-
114
- Commands:
115
-
116
- servers
117
- Show server groups information from config file
118
-
119
- settings
120
- Show hPING settings from config file
121
-
122
- get
123
- Sends HTTP GET requests to web or api server (set default in ~/.hping/hping.conf.yaml)
124
-
125
- post
126
- Sends HTTP POST requests to web or api server (set default in ~/.hping/hping.conf.yaml)
127
-
128
- head
129
- Sends HTTP HEAD requests to web or api server (set default in ~/.hping/hping.conf.yaml)
130
-
131
-
132
- Options:
133
-
134
- -h, --help output usage information
135
- -V, --version output the version number
136
- -c, --config [~/.hping/hping.conf.yaml] hping config file in YAML format
137
- -i, --interval [1]
138
124
  ```
125
+
139
126
  ## Log to file
140
- You can setup hPING to log status change to separate log file. Default log file located in ``~/.hping/logs`` folder, you can change it with ``log_file`` option.
141
127
 
142
- To enable log output, you need to edit ``~/.hping/hping.conf.yaml`` config file and set: ``log_status_change`` : ``true``
128
+ Enable status-change logging with `log_status_change: true`.
129
+
130
+ Default log file location: `~/.hping/logs/hping.log` (override with `log_file`).
131
+
132
+ ## Development
133
+
134
+ Install deps:
143
135
 
144
- Also, you can make hPING to output statistics to log file with option ``log_stats_on_exit`` : ``true``
136
+ ```bash
137
+ $ npm install
138
+ ```
139
+
140
+ Run tests:
141
+
142
+ ```bash
143
+ $ npm test
144
+ ```
145
145
 
146
146
  ##License
147
147
  The MIT License (MIT)
package/bin/hping CHANGED
@@ -2,388 +2,9 @@
2
2
 
3
3
  'use strict';
4
4
 
5
- var program = require('commander'),
6
- util = require('util'),
7
- pkg = require('../package.json'),
8
- fs = require('fs'),
9
- log4js = require('log4js'),
10
- dns = require('dns'),
11
- path = require('path'),
12
- color = require('cli-color'),
13
- request = require('request'),
14
- status_codes = require('../lib/status'),
15
- config = require('yaml-config'),
16
- helpers = require('../lib/helpers'),
17
- info = 'hPING sends HEAD or GET or POST requests to web or api servers to check if they alive',
18
- usage = '[head|get|post] [http(s)://]www.webserver.com[:port] [another host] [server group]',
19
- hping_home_dir = getHPINGHome(),
20
- defconfile = path.resolve(__dirname, '../config/hping.yaml'),
21
- confile = path.resolve(hping_home_dir, 'hping.conf.yaml'),
22
- colors = {
23
- r: 'red',
24
- g: 'green',
25
- bb: 'blackBright',
26
- u: 'underline',
27
- m: 'magenta',
28
- y: 'yellow'
29
- },
30
- defaults = {
31
- confile: confile,
32
- interval: 1
33
- };
5
+ const { runCli } = require('../lib/cli');
34
6
 
35
- var settings, stats = {},
36
- logger_file;
37
-
38
- program
39
- .version(pkg.version)
40
- .usage(usage)
41
- .option('-c, --config [' + confile + ']', 'hping config file in YAML format', defaults.confile)
42
- .option('-i, --interval [1]', 'hping interval in seconds (set default in ' + confile + ')', defaults.interval);
43
-
44
- program
45
- .command('servers')
46
- .description('Show server groups information from config file')
47
- .action(function() {
48
- hping('servers');
49
- });
50
-
51
- program
52
- .command('settings')
53
- .description('Show hPING settings from config file')
54
- .action(function() {
55
- hping('settings');
56
- });
57
-
58
- program
59
- .command('get')
60
- .description('Sends HTTP GET requests to web or api server (set default in ' + confile + ')')
61
- .action(function() {
62
- if (program.args.length > 1) {
63
- hping(program.args, 'GET');
64
- } else {
65
- console.log(usage);
66
- }
67
- });
68
-
69
- program
70
- .command('post')
71
- .description('Sends HTTP POST requests to web or api server (set default in ' + confile + ')')
72
- .action(function() {
73
- if (program.args.length > 1) {
74
- hping(program.args, 'POST');
75
- } else {
76
- console.log(usage);
77
- }
78
- });
79
-
80
- program
81
- .command('head')
82
- .description('Sends HTTP HEAD requests to web or api server (set default in ' + confile + ')')
83
- .action(function() {
84
- if (program.args.length > 1) {
85
- hping(program.args, 'HEAD');
86
- } else {
87
- console.log(usage);
88
- }
89
- });
90
-
91
- program
92
- .on('*', function(e) {
93
- hping(e);
94
- });
95
-
96
- program.parse(process.argv);
97
-
98
- if (program.args.length < 1) {
99
- console.log('usage: hping ' + usage);
100
- }
101
-
102
- function hping(args, type) {
103
- fs.exists(confile, function(exists) {
104
- if (exists) {
105
- hping_run(args, type);
106
- } else {
107
- fs.mkdir(path.resolve(hping_home_dir), function(e) {
108
- if (!e || (e && e.code === 'EEXIST')) {
109
- fs.mkdir(path.resolve(hping_home_dir + '/logs'), function(e) {
110
- fs.createReadStream(defconfile).pipe(fs.createWriteStream(confile)).on('error', function(err) {
111
- console.log(err);
112
- }).on('close', function() {
113
- hping_run(args, type);
114
- });
115
- });
116
- } else {
117
- console.log(e);
118
- }
119
- });
120
- }
121
- });
122
- }
123
-
124
- function hping_run(args, type) {
125
- var cnf = (program.config !== defaults.confile) ? program.config : defaults.confile;
126
- settings = config.readConfig(cnf);
127
- if (!settings.interval) {
128
- console.error('Specified config file: %s could not be used, see error above. Using default config: %s', cnf, defaults.confile);
129
- settings = config.readConfig(defaults.confile);
130
- cnf = defaults.confile;
131
- }
132
- if (settings.log_status_change) logger_file = require('../lib/logger')(settings.log_file);
133
- settings.interval = (program.interval === 1) ? settings.interval : program.interval;
134
- if (args == 'servers') {
135
- showServers();
136
- return;
137
- }
138
- if (args == 'settings') {
139
- showSettings(cnf);
140
- return;
141
- }
142
- args.forEach(function(url) {
143
- if (typeof url == 'string' || url instanceof String) {
144
- if (settings.servers && settings.servers[url]) {
145
- settings.servers[url].forEach(function(url) {
146
- prerequest(url, type);
147
- });
148
- } else {
149
- prerequest(url, type);
150
- }
151
- }
152
- });
153
- }
154
-
155
- function prerequest(url, t) {
156
- if (!/^(https?):\/\//i.test(url)) url = 'http://' + url;
157
-
158
- var type = t || settings.type.toUpperCase(),
159
- run_time = 0,
160
- interval = ints(settings.interval),
161
- max_run_time = ints(settings.max_run_time),
162
- options = {
163
- url: url,
164
- timeout: ints(settings.timeout) || 5000,
165
- method: type,
166
- headers: {
167
- 'User-Agent': 'hPING [git.io/hping]'
168
- }
169
- };
170
-
171
- dns.resolve4(require('url').parse(url).hostname, function(err, ip) {
172
- if (err) ip = [''];
173
- stats[url] = [];
174
- (function dorequest() {
175
- var start = new Date();
176
- request(options, function(e, r) {
177
- var res_time = new Date() - start;
178
- var line = predisplay(e, r, url, type, ip[0], res_time);
179
- display(line);
180
- });
181
- if (max_run_time === 0 || max_run_time > (interval * run_time)) {
182
- setTimeout(dorequest, interval * 1000);
183
- run_time++;
184
- } else {
185
- console.log('hPING: Maximum running time has been reached (set in config), exiting.');
186
- gracefulExit();
187
- }
188
- })();
189
- });
190
- }
191
-
192
- function predisplay(err, res, url_org, type, ip, ms) {
193
- var hcode, hlength, hserver, hinfo, hip, htime, code, status_color, empty,
194
- sdo = settings.display_in_output,
195
- status = '[UP]',
196
- down = '[DOWN]',
197
- hstatus = status,
198
- htype = cc('type', type.toLowerCase()),
199
- hurl = url_org,
200
- line = [],
201
- url_p = require('url').parse(url_org);
202
-
203
- if (ip && hurl.indexOf(ip) == -1) hip = '(' + ip + ')';
204
- if (err && err.code) {
205
- code = 'error';
206
- status_color = colors.r;
207
- status = down;
208
- hcode = cc('error', err.code.toLowerCase(), colors.r);
209
- ms = 0;
210
- switch (err.code) {
211
- case 'ETIMEDOUT':
212
- hinfo = cc('info', 'connection_timeout', colors.r);
213
- break;
214
- case 'ENOTFOUND':
215
- hinfo = cc('info', 'server_not_found', colors.r);
216
- break;
217
- case 'ECONNRESET':
218
- hinfo = cc('info', 'connection_closed', colors.r);
219
- break;
220
- case 'ECONNREFUSED':
221
- hinfo = cc('info', 'connection_refused', colors.r);
222
- break;
223
- }
224
- } else if (res && res.headers) {
225
- htime = cc('time', ms, colors.u, 'ms');
226
- code = res.statusCode;
227
- status_color = statusColor(code);
228
- if (code >= 500) status = down;
229
- hcode = cc('code', code, (status_color !== colors.g) ? status_color : '');
230
- if (status_codes[code]) hinfo = cc('info', status_codes[code].replace(/\s+/g, '_'), (status_color !== colors.g) ? status_color : '');
231
- if (res.headers['content-length'] && res.headers['content-length'] > 0) hlength = 'content-length=' + res.headers['content-length'];
232
- if (res.headers.server) hserver = 'server=' + res.headers.server;
233
- } else {
234
- status = hstatus = 'unknown_error';
235
- }
236
-
237
- hurl = hurl.replace(url_p.hostname, colr('bold', colr(status_color, url_p.hostname))).replace(url_p.port, colr('bold', colr(status_color, url_p.port)));
238
- if (url_p.path && url_p.path != '/' && code !== 'error') hurl = hurl.replace(url_p.path, colr(status_color, url_p.path));
239
- hstatus = colr('bold', colr(status_color, status));
240
- hip = colr(colors.bb, hip);
241
-
242
- line = [
243
- 'hPING:', (sdo.status) ? hstatus : empty, (sdo.url) ? hurl : empty, (sdo.ip) ? hip : empty, (sdo.type) ? htype : empty, (sdo.status_code) ? hcode : empty, (sdo.status_info) ? hinfo : empty, (sdo.server) ? hserver : empty, (sdo.content_length) ? hlength : empty, (sdo.response_time) ? htime : empty
244
- ];
245
-
246
- if (stats[url_org].length >= ints(settings.stats_for_last)) stats[url_org].shift();
247
- if (settings.log_status_change) {
248
- if (stats[url_org][stats[url_org].length - 1] === undefined || (stats[url_org][stats[url_org].length - 1] !== undefined && stats[url_org][stats[url_org].length - 1].status !== status)) {
249
- log(line);
250
- }
251
- }
252
- stats[url_org].push({
253
- status: status,
254
- code: code,
255
- time: ms
256
- });
257
-
258
- return line;
259
- }
260
-
261
- function showServers() {
262
- console.log(info, (settings.servers) ? '\nServer groups (set in config):' + pp(settings.servers) : '', 'usage: hping ' + usage);
263
- }
264
-
265
- function showSettings(cnf) {
266
- console.log('Settings from config file: %s %s', cnf, pp(settings));
267
- }
268
-
269
- function display(line) {
270
- console.log(pline(line));
271
- }
272
-
273
- function log(line) {
274
- if (settings.log_status_change) logger_file.info(pline(line));
275
- }
276
-
277
- function gracefulExit() {
278
- var updateNotifier = require('update-notifier');
279
-
280
- if (ints(settings.show_stats_for_last) > 0) {
281
- for (var url in stats) {
282
- if (url) {
283
- display(displayStat(url));
284
- if (settings.log_stats_on_exit) log(displayStat(url));
285
- }
286
- }
287
- }
288
- log4js.shutdown(function() {
289
- updateNotifier({packageName: pkg.name, packageVersion: pkg.version}).notify();
290
- process.exit(1);
291
- });
292
- }
293
-
294
- function statusColor(code) {
295
- var status_color = colors.g;
296
-
297
- if (code >= 500 || code == 'error') {
298
- status_color = colors.r;
299
- } else if (code >= 400) {
300
- status_color = colors.y;
301
- }
302
- return status_color;
303
- }
304
-
305
- function displayStat(url) {
306
- if (stats[url].length === 0) return;
307
-
308
- var codes = [],
309
- out = [],
310
- total = {
311
- requests: stats[url].length,
312
- codes: {},
313
- time: [],
314
- up: 0,
315
- down: 0
316
- },
317
- timesrange,
318
- requests = '[' + ((total.requests > settings.show_stats_for_last) ? 'last ' : '') + total.requests + ' requests] ',
319
- stat_line = '\n--- ' + url + ' hPING statistics ' + requests + '---\n';
320
-
321
- stats[url].forEach(function(stat) {
322
-
323
- if (!total.codes[stat.code]) total.codes[stat.code] = 1;
324
- else total.codes[stat.code]++;
325
-
326
- if (stat.status == '[UP]') total.up++;
327
- else total.down++;
328
-
329
- if (stat.time > 0) total.time.push(stat.time);
330
- });
331
-
332
- for (var code in total.codes) {
333
- if (code) codes.push(statProcess(code, total.codes[code], total.requests, statusColor(code), ''));
334
- }
335
-
336
- timesrange = total.time.range();
337
-
338
- out = [
339
- stat_line,
340
- statProcess('UP', total.up, total.requests, colors.g, 'bold'),
341
- statProcess('DOWN', total.down, total.requests, colors.r, 'bold'),
342
- codes.join(' '), (timesrange.min) ? 'time(min=' + timesrange.min + ' avg=' + timesrange.avg + ' max=' + timesrange.max + ')ms' : ''
343
- ];
344
-
345
- function statProcess(lb, tv, tr, tc, tb) {
346
- if (lb === 'error') lb += 's';
347
- var st = lb + '=' + Math.floor10((tv / tr) * 100) + '%';
348
- return (tv > 0) ? colr(tb, colr(tc, st)) : '';
349
- }
350
-
351
- return out;
352
- }
353
-
354
- process.on('SIGTERM', function() {
355
- gracefulExit();
356
- }).on('SIGINT', function() {
357
- gracefulExit();
7
+ runCli(process.argv.slice(2)).catch((error) => {
8
+ console.error(error.message || error);
9
+ process.exitCode = 1;
358
10
  });
359
-
360
- function cc(s1, s2, c, s3) {
361
- if (!s3) s3 = '';
362
- return (c && settings.use_colors) ? s1 + '=' + (color[c](s2)) + s3 : s1 + '=' + s2 + s3;
363
- }
364
-
365
- function colr(c, s) {
366
- return (!settings.use_colors || !c) ? s : color[c](s);
367
- }
368
-
369
- function ints(s) {
370
- return parseInt(s, 10);
371
- }
372
-
373
- function pp(s) {
374
- return JSON.stringify(s, null, ' ').replace(/[{}]|\,|[\[\]]|/g, '').replace(/\n\s*\n\s*\n/g, '\n');
375
- }
376
-
377
- function pline(l) {
378
- if (util.isArray(l)) {
379
- l = l.filter(function(e) {
380
- return e;
381
- });
382
- return l.join(' ').replace(/\n\s/g, '\n');
383
- }
384
- return '';
385
- }
386
-
387
- function getHPINGHome() {
388
- return path.resolve(process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE, '.hping/');
389
- }
package/config/hping.yaml CHANGED
@@ -1,17 +1,18 @@
1
1
  default:
2
2
 
3
3
  interval: 1 # (seconds) interval between hPING requests
4
- type: HEAD # (type or requests): HEAD, GET, POST, PUT
4
+ type: HEAD # (request type): HEAD, GET, POST
5
5
  timeout: 5000 # (milliseconds) request connection timeout
6
6
  use_colors: true # (true || false), use colors for hPING output
7
7
  show_stats_for_last: 100 # (number of requests) show hPING statistics for last X number of requests, set 0 to disable
8
+ stats_for_last: 100 # (number of requests) keep stats for last X requests per target
8
9
  max_run_time: 600 # (seconds) hPING maximum running time, set 0 to disable
9
10
 
10
11
  log_status_change: false # (true || false) if true, hPING will log status changes to log file
11
12
  log_file: logs/hping.log # (path) to hPING log file, default path in users home .hping folder
12
13
  log_stats_on_exit: true # (true || false) if true, hPING will log statistics to file on exit
13
14
 
14
- display_in_output: # use true || fasle to turn on/off log output sections
15
+ display_in_output: # use true || false to turn on/off log output sections
15
16
  status: true
16
17
  url: true
17
18
  ip: true