From 3d50432ff438e250d8b1d44497668e43fee29265 Mon Sep 17 00:00:00 2001 From: Wirlaburla Date: Wed, 3 Apr 2024 22:08:54 -0500 Subject: [PATCH] Initial commit --- banner.png | Bin 0 -> 7192 bytes data/config.php.example | 61 ++++++++++++++++++ data/update.php | 136 ++++++++++++++++++++++++++++++++++++++++ style.css | 28 +++++++++ 4 files changed, 225 insertions(+) create mode 100644 banner.png create mode 100755 data/config.php.example create mode 100755 data/update.php create mode 100755 style.css diff --git a/banner.png b/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..733c4d6a548f85ad02ddbaed553cef72ba705995 GIT binary patch literal 7192 zcmeHMX;@Q9)~>L~BG@egZXhwJpct}3mIgugpeO=1h#+RUfwY7`5+K+>Xh2%Q7R5nr z0ReX%Z5jnPlugAQx3&=+Q5!*98&OmiA>65(Ama2q&y4eZGrz2)a!*yA^VWG!ox1nd zlXd=!yp0W~7ynE57u!wEnot#+h8?;{TL`#r{Hwe*Mm@=IxHW7vhA>r7L+N_))-z-!Aga) zDZE~URrI}P-oHWF6oToiKkib5D@O$QM3FoS@6GY^2XisMpw9a%)`_RuQ^@u-M~FzK z(%EGArQxX*wgZz*X96vdm8S??*Vt9KW2>H7+rlm zJv{>heM2KtW23QSjV7B+_`=k3iq$mBDHay^8TK}K!dz<$3tPtQxnv5RPPejQIWwtF z_B1*b1Hl;>7#NK;nq+J|i8|e4I`xwaS_{VO16Ld*O8{EqaoXc?=s92o{nW*&i-rnD zR9i=PjGn%M;aI3p`6ZS?+FCl=y1F_#a5M#u1D)}@CetbN$4pql)g#22Qoq|&s&DO9 zUS}3?^W_X0PnvFEXg+b$}+1SpWLw9gwFj;JO4^J;|AC7Ne(9*AiLzac|1&A;* zO7x9P9-ok?NLrndxhCuTwd=C;Hvc7m%hqi_Zr{0U_ny7`_8&NSziw zg;7&8`}c^Y|3}P5h<)JI0*thAaPhRq0~gRgRAp>cThr2-IJhvm%uX`+^Zmjns?y)X zt`$9LW(;+u{*l-~2{+DD9aVni*!F;Rz3=OIi@e)z54Q$J4w*?*UdrxZ6dc_(N%jei z*MrOkN>|s4O{y{!EOdE=f}u)j=!13h?mbrSjBc(P3XNo4I9@4Qv~+4yfX$?trB`lx zn%!Dyy2KNFN;P}B!fbILC$;H%bM^J3sx$YFr%-y8p|4w>Cr@aT^to5xM}Y|nj-~wd z3JSKguDD-S)68n@y0ueOxwqYO_uH@f>BS_gnnvYa6g!^K*`AbL zlCEQ&*I!1yyH#Z8(tQsFme`2)0b042p0#;?`;*@0>jPG*)z@E5JX-_ZxQ2oW5l2&s z69=oh?pIlL8l|+nIZ=?HI51~dz=D9Vz#DzfvTe&;+YD`YrhRIixAEoT4JdfT7)Tsk zkb1tyg*3Fhzo7R83IzPA%Fw5o)k^V+-fPJN4CY8H-XoWTG`9G!pshIU-8>;D)7|n=^Gw&PVPU}*>f!^_yWCImC-2c$yM!Ju{HjH zxOt#B;x|Y+cuTS<<-y%#{xs##?LBU-H^)`>kK@Y0}RkS*M&D(V<|a`iQ3Frjz1Yqv za^Bl3inH}rFSn-TsJ{B67=apdlds)7hJp&p4>gD5ynoxG>@Y^b<_OiA>3zG3`!i7R z7;X~ovV-x27n@>Yzqz)p)#z36Ai*jI1+D`TEvIYx#qFKO* z2?eTsVYxY{!%<)m40G{D>XjZb3c8z8JMSr*Ck@mbmO0!gO`07~={V93gHwUG-I)#k z-HJBnSo>DOTXm+$-QAz#?v9U@N`#_l1OP>0$|h%@v#yh}9_%&qoHH)r%eagF@#Q(@ zafg=Lx~=iIt9Z6j`nwffo_+(eFyDlSFC-t zp>100KOA**>2_ww#O9w7!+`|J@|ZUaAuU@TE3fb3&n;b>f2EEtxjL+#I|Ka z@yZRj%9Rv6-o$1bx8>Z_bF_kEbxFm{`pZXrlNULOZt1SGI{A}gu;Jw6BegVZp(Aav z#dPxp;fLfDyMifkh0KHBu-nJ7a+fwPFRc8gsIu!)#3cKtc2~moIb@rfm+Kf1On+H2 z-^`I$@qBm4#T!YtF1Y;mZl-kh$9o6%q+PLG*>`E9UvqwXMJ8{& z!ey7_vbOtiS9E*R@gCM9tF*aq=cH&`SZKA)yu6|}DKR4P!O&q*Z7$ z*)P@|i4ys&mLh?x7X|TGui~==1ebY+P6{>z5F>IfULlT-k+Bud1T`)j%2+pvfLE)? zS2+_x;QN-lM2g_)_H=tP(NiHxpc3X8;+>=dAv?gsYZwByoC#5Kc`TbmN=!_&Po&vP zq>&^Fi^U?5sU#|u2sMbZq!>9@L5z`EV-Ok)4@Ab7ielv=Nemvt=8-b6J4MzdSgQVcbk|_3Ml2}X{Z6T9;CP0v3hyJOBEGQ`!Aq5~ZNxYPgcqSk* za_i9$0{)17Y`ipDO-H~dA<>8!s>*U ziVp)pA~6yu=VH;MFep@*nhsPZok3+fjjBR-5On0c67>GOLL@t|$r=YRI6sL%Bux5O z+Sum7J3)Q8R3ceGB@^igl}ls_5IT{D(1i>>B1GsEO*W07%Opa1 zB3FvckA!iAv4ZKTKFQ&2)eANIV_y=Z5E$p-=#c&ge7Fe1(a`}R3LOP7AE`7tkxAnt zM1;m83u#=MBaO%S*u(#X4@>|Gk<1`cSXctUlPe82)d}!Fph!lTJSNMLOLU}SOC}JK zi7Ww`Ok_|UsX`jd0q$T;BL1J249jsM8GdR1nB&6~ok-Yi{(X`mnh4LgJR4*9*8nhx^;sqZz}_0GIK>{91lXx3=lFT*J=M|CVv`r% zVe(+nKHr1(%g8i^+bxz6lV&--Eo%p zJSxY9=Ib=a-(`-!tDPX&8wv4AS{0Hk@XSsUWUm(FN&SBOUQ(cpDEy9Bm@X*FM2gl# z6{m)jrmrZ?2-}$vwkJ<a{*+TKzJ?ZCm#GTup)liynVVB~vQnYloG{w}Dffx7G@~5o@FV6I~ z=JYB{r!81#>bZ_@ot24p&C)v0NwE)@YMbxjK~6&s?LOD_)*WZ+iem>x)SvJqLCLg) z_O>MbkuzTQzi^}3X<9ndYWMFsZEaZ+ zK47K`@uU3GaxYHU5vM(&KK}J4C(^2gzjj#pS}H3@uyNhq(2mur{+<^$|0s z4d(3BTgrB8ozcDFn88U4F>b82Er$7UYOz7?CdI?4$u6fahF*N^Z1FtF_SE{s75qW=UMZTr*(Jt8wkZGlFdC0OMu}array( + ## This will be the name of the service as displayed on the status page. + #'name'=>'Web Server', + + ## This will be the message displayed under the collapsable title. + #'message'=>'To be, or not to be.', + + ## The pid file of the service to check. If 'process' is also defined, + ## this will override its check. Make sure the runner has permissions + ## to read the file. + #'pidfile'=>'/run/nginx.pid', + + ## Icon to display alongside the service name. Path is relative to page. + ## You can also leave this blank for no icon. + #'icon'=>'http.png', + + ## Name of the process to query. This will search using pgrep. + #'process'=>'nginx', + + ## Hostname of the server to ping. This and 'ports' may be omitted if + ## you do not want to ping it. + #'hostname'=>'shakespear.lit', + + ## Array of ports to ping. If more than one port, the displayed ping will be averaged. Requires 'hostname' to function properly. + #'ports'=>array(80,443) + #) +); +?> \ No newline at end of file diff --git a/data/update.php b/data/update.php new file mode 100755 index 0000000..5e3dae4 --- /dev/null +++ b/data/update.php @@ -0,0 +1,136 @@ +errorCode() && $SQL->errorCode() !== '00000') { + die($SQL->errorCode()); + } + + $SQL->query('CREATE TABLE IF NOT EXISTS service_status(service TEXT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, ping INTEGER, status INTEGER, PRIMARY KEY(service, timestamp))'); + + foreach($CONFIG['services'] as $id=>$data) { + $services[$id] = array( + 'name'=>$data['name'], + 'message'=>$data['message'] + ); + if (isset($data['icon'])) $services[$id]['icon'] = $data['icon']; + $timestamp = date('Y-m-d H:i:s'); + // Ping is in ms. Status is 0 if okay, +1 for each unreachable, and -1 if offline completely. + $ping = -1; $status = 0; + // Check for ports (with ping) + if (isset($data['ports'])) { + $pings = array(); $i = 0; + foreach ($data['ports'] as $port) { + $starttime = microtime(true); + if ($fp = fsockopen($data['hostname'],$port,$errno,$errstr,15)) { + $stoptime = microtime(true); + $newping = ($stoptime - $starttime) * 1000; + $pings[$i++] = $newping; + } else $status++; + } + if ($i == 1) + $ping = round($pings[0], 2); + else if ($i > 0 && ($ping_sum = array_sum($pings)) > 0) + $ping = round($ping_sum / $i, 2); + } + + // Check for PID (status) + if (isset($data['pidfile'])) { + if (!posix_getpgid(file_get_contents($data['pidfile']))) + $status = -1; + } + + // Check for process (status) + if (isset($data['process']) && !isset($data['pidfile'])) { + $otp; $rtn; + exec('pgrep -fl "'.$data['process'].'"', $otp, $rtn); + if ($rtn!=0) $status = -1; + } + + if ($stmt = $SQL->prepare('INSERT INTO service_status(service, timestamp, ping, status) VALUES (?, ?, ?, ?)')) { + $stmt->bindParam(1, $id); + $stmt->bindParam(2, $timestamp); + $stmt->bindParam(3, $ping); + $stmt->bindParam(4, $status); + $stmt->execute(); + $stmt->closeCursor(); + } + + if ($stmt = $SQL->prepare('SELECT timestamp,ping,status FROM service_status WHERE service = ? ORDER BY timestamp DESC LIMIT ?')) { + $stmt->bindParam(1, $id); + $stmt->bindParam(2, $CONFIG['max_slices']); + if ($stmt->execute()) { + $services[$id]['status'] = array(); + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + array_push($services[$id]['status'], $row); + } + } + $stmt->closeCursor(); + } + $services[$id]['status'] = array_reverse($services[$id]['status']); + } +?> + + + + <?=$CONFIG['page_name'];?> + '> + + '> + '> + + + + + + + +
+ + '; + echo ''; + if (!empty($service['message'])) { + echo '
'; + if (!empty($service['icon'])) + echo ' '; + echo $service['name'].''.$service['message'].'
'; + } else { + if (!empty($service['icon'])) + echo ' '; + echo ''.$service['name'].''; + } + echo ''; + echo ''; + foreach ($service['status'] as $slice) { + $cell_status; $bgclrstyle = ''; + $_time = date($CONFIG['timestamp_format'], strtotime($slice['timestamp'])); + $_ping = $slice['ping'].'ms'; + + if ($slice['status'] > 0 || ($slice['status'] == -1 && $slice['ping'] > 0)) { + $cell_status = 'partial'; + $bgclrstyle = sprintf("#%02x%02x%02x", 255, 128, 0); + } else if ($slice['status'] == -1) { + $cell_status = 'offline'; + $bgclrstyle = sprintf("#%02x%02x%02x", 255, 0, 0); + } else { + $cell_status = 'ok'; + $bgclrstyle = sprintf( + "#%02x%02x%02x", + $slice['ping']!=-1?max(0, min(255, round($slice['ping'])*2)):0, + max(0, min(255, 128+(round($slice['ping'])/2))), + 0 + ); + } + + echo ''; + } + echo ''."\n"; + } + ?> +
+
+ + \ No newline at end of file diff --git a/style.css b/style.css new file mode 100755 index 0000000..de5b449 --- /dev/null +++ b/style.css @@ -0,0 +1,28 @@ +body { + background: #d3d3d3; +} + +body > center > * { + max-width: 800px; +} +details { + text-align: left; +} +details > summary { + cursor: pointer; +} + +table { width: 100%; } +table.status { margin: 8px 0; } +table.status tr:not(.title) td { height: 16px; } +table.status tr:not(.title) td:hover:after { + content: attr(value); + position: absolute; + background-color: rgba(0,0,0,0.75); + border-radius: 8px; + color: white; + padding: 2px 4px; + margin: -58px -8px; + white-space: pre; + pointer-events: none; +} \ No newline at end of file