Repository navigation
Expand file tree
/
Copy pathhelp.go
More file actions
155 lines (131 loc) · 6.01 KB
/
Copy pathhelp.go
File metadata and controls
155 lines (131 loc) · 6.01 KB
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
153
154
155
package main
import (
"io"
"runtime"
"strings"
)
// Help is examples first, prose second. Someone reading this has already
// downloaded the thing and wants a line they can paste.
const helpCommon = `pingping {{VERSION}} — latency distribution and packet loss, as a service.
Not an average. pingping keeps every RTT sample so the chart shows the SHAPE
of a link's behaviour — the spread, the outliers, the loss bursts — for {{DAYS}} days.
USAGE
{{EXE}} [command] [flags]
COMMANDS
run run in the foreground; Ctrl-C stops it
(none) {{BAREDESC}}
console {{CONSOLEDESC}}
install {{INSTALLDESC}}
uninstall {{UNINSTALLDESC}}
tray {{TRAYDESC}}
selftest measure this machine's clock and scheduler (see below)
version print the version
help this text
FLAGS
--port N console port (default 8518)
--localhost {{LOCALHOSTDESC}}
--days N days of history to keep (default 300)
--data DIR where the database lives (see DATA below)
FIRST RUN
There is no password on the command line and no config file to edit. Start it,
open the console, and the first screen asks you to create the admin account.
Everything after that — targets, pacing, the password itself — is changed in the
console. A service command line is readable by every account on the machine, so
a credential does not belong there.
SELFTEST
{{EXE}} selftest
pingping's premise is that sub-millisecond RTT differences are real and worth
drawing. That is only true if the host's clock resolves finely enough and its
scheduler wakes goroutines on time. selftest measures both and tells you PASS or
FAIL. Run it once on any machine before trusting the graphs it draws.
`
const helpWindows = `
DATA
Portable a "data" folder next to pingping.exe → everything stays there,
nothing is written outside the folder, nothing touches the registry.
Installed no such folder → %ProgramData%\pingping
That is the whole rule. The portable .zip ships with an empty data folder and
the installer does not, so each build does the right thing with no flag.
EXAMPLES
pingping.exe run it now, in this window
pingping.exe --port 9000 ...on another port
pingping.exe install run as a service from now on
pingping.exe install --port 9000 --days 90
pingping.exe uninstall remove the service (data is kept)
install and uninstall need Administrator and will ask for it — accept the
prompt and the command finishes in the window you typed it in. Nothing else
prompts: running the console needs no privilege at all.
What install sets up:
account NT AUTHORITY\LocalService, with a per-service SID, so the
database is locked to this service and not to every other
LocalService process on the machine
start automatic (delayed) — the network is up before we probe
recovery restart after 5s, 20s, 60s; a monitor that stays down after a
crash draws a flat line that looks like a healthy link
firewall the console port, on the private and domain profiles
Defender an exclusion for the database, because real-time scanning shows
up as I/O jitter in the measurements
Service logs go to the Application event log, with event IDs you can filter on
(1xxx lifecycle, 2xxx degraded, 3xxx failed to start):
Get-WinEvent -ProviderName pingping -MaxEvents 30
The notification-area icon is a separate process, started at sign-in from the
all-users Startup folder. It has to be separate: a
Windows service runs in Session 0 and cannot display any UI at all. Its menu
therefore distinguishes hiding the icon from stopping the service, because
those are genuinely different things and conflating them is how people end up
believing they closed a program that is still running.
Upgrade: stop the service, replace pingping.exe, start it again.
`
const helpUnix = `
DATA
Portable a "data" folder next to the binary → everything stays there
Otherwise ./data, relative to the working directory
EXAMPLES
./pingping run it now
./pingping --port 9000 --days 90
./pingping --localhost bind loopback only
ICMP without root — pick one:
echo 'net.ipv4.ping_group_range = 0 2147483647' | sudo tee /etc/sysctl.d/99-pingping.conf
sudo sysctl --system
or:
sudo setcap cap_net_raw+ep ./pingping
Run it as a service with the unit file in deploy/pingping.service.
`
const helpFooter = `
Source, ADRs and the Windows notes: https://github.com/githubflyideas/pingping
`
func printHelp(w io.Writer) {
body := helpUnix
if runtime.GOOS == "windows" {
body = helpWindows
}
install, uninstall, exe := "(Windows only)", "(Windows only)", "./pingping"
trayDesc, consoleDesc := "(Windows only)", "(Windows only)"
bareDesc := "same as run"
localhostDesc := "bind 127.0.0.1 only — nobody else on the network can reach it"
if runtime.GOOS == "windows" {
install = "register as a Windows service (asks for elevation)"
uninstall = "stop and remove the service (data is kept)"
trayDesc = "notification-area icon for an installed service"
consoleDesc = "open the console; starts the service and icon if they are down"
bareDesc = "console if a service is installed here, otherwise run"
exe = "pingping.exe"
// An installed service is configured in the console, not by re-running
// the installer with flags. Saying so here is cheaper than the support
// round it saves.
localhostDesc = "foreground runs only — an installed service takes its bind address from Settings"
}
t := helpCommon + body + helpFooter
r := strings.NewReplacer(
"{{VERSION}}", version,
"{{DAYS}}", "300",
"{{INSTALLDESC}}", install,
"{{UNINSTALLDESC}}", uninstall,
"{{EXE}}", exe,
"{{TRAYDESC}}", trayDesc,
"{{CONSOLEDESC}}", consoleDesc,
"{{BAREDESC}}", bareDesc,
"{{LOCALHOSTDESC}}", localhostDesc,
)
io.WriteString(w, r.Replace(t))
}