diff --git a/.gitignore b/.gitignore
index 397f1f7..d8d9592 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ dist/
node_modules/
.parcel-cache/
static/
+hostmonitor
diff --git a/core/printer.go b/core/printer.go
index 599c8b2..0f4d115 100644
--- a/core/printer.go
+++ b/core/printer.go
@@ -48,7 +48,7 @@ func (p *Printer) ToTable(results *Store) {
p.t.AppendRow(table.Row{
r.Id,
r.Tcp,
- r.HttpStatus,
+ r.HttpResponse,
r.Duration,
})
return true
diff --git a/core/store.go b/core/store.go
index 81168b8..fe575d6 100644
--- a/core/store.go
+++ b/core/store.go
@@ -22,11 +22,12 @@ func (s *Store) AddOrUpdate(res TestResult) {
} else {
prev := existing.(TestResult)
s.results.Store(res.Id, TestResult{
- Id: prev.Id,
- InProgress: true,
- Tcp: prev.Tcp,
- HttpStatus: prev.HttpStatus,
- Duration: prev.Duration,
+ Id: prev.Id,
+ InProgress: true,
+ Tcp: prev.Tcp,
+ HttpResponse: prev.HttpResponse,
+ Duration: prev.Duration,
+ Status: prev.Status,
})
}
} else {
diff --git a/core/test-result.go b/core/test-result.go
new file mode 100644
index 0000000..f114c4f
--- /dev/null
+++ b/core/test-result.go
@@ -0,0 +1,19 @@
+package core
+
+import "net/url"
+
+const (
+ StatusOK = "OK"
+ StatusErr = "Error"
+ StatusErrResponse = "ErrorResponse"
+)
+
+type TestResult struct {
+ Id string `json:"id"`
+ InProgress bool `json:"inProgress"`
+ url url.URL
+ Tcp string `json:"tcp"`
+ HttpResponse string `json:"httpResponse"`
+ Duration string `json:"duration"`
+ Status string `json:"status"`
+}
diff --git a/core/tester.go b/core/tester.go
index 431fbd5..6ad95f2 100644
--- a/core/tester.go
+++ b/core/tester.go
@@ -9,15 +9,6 @@ import (
"time"
)
-type TestResult struct {
- Id string `json:"id"`
- InProgress bool `json:"inProgress"`
- url url.URL
- Tcp string `json:"tcp"`
- HttpStatus string `json:"httpStatus"`
- Duration string `json:"duration"`
-}
-
type Tester struct {
requestTimeout time.Duration
testInterval time.Duration
@@ -40,23 +31,25 @@ func (t *Tester) Test(url *url.URL) {
case <-t.quit:
return
default:
+ tcp := "-"
t.out <- TestResult{
Id: url.String(),
InProgress: true,
- HttpStatus: "Testing...",
+ Tcp: tcp,
}
- var pass int
if url.Scheme == "tcp" {
- pass = t.tcp(url)
+ pass := t.tcp(url)
+ tcp = fmt.Sprintf("%d/10", pass)
}
- status, duration := t.http(url)
+ response, duration, status := t.http(url)
t.out <- TestResult{
- Id: url.String(),
- url: *url,
- Tcp: fmt.Sprintf("%d/10", pass),
- HttpStatus: status,
- Duration: strconv.FormatInt(duration.Milliseconds(), 10) + "ms",
+ Id: url.String(),
+ url: *url,
+ Tcp: tcp,
+ HttpResponse: response,
+ Duration: strconv.FormatInt(duration.Milliseconds(), 10) + "ms",
+ Status: status,
}
time.Sleep(t.testInterval)
}
@@ -76,18 +69,25 @@ func (t *Tester) tcp(url *url.URL) int {
return pass
}
-func (t *Tester) http(url *url.URL) (status string, duration time.Duration) {
+func (t *Tester) http(url *url.URL) (statusMessage string, duration time.Duration, status string) {
tp := NewTransport(t.requestTimeout)
client := http.Client{Transport: tp, Timeout: t.requestTimeout}
addr := strings.Replace(url.String(), "tcp", "http", 1)
res, err := client.Get(addr)
duration = tp.Duration()
if err == nil {
- status = res.Status
+ statusMessage = res.Status
+ if res.StatusCode >= 500 {
+ status = StatusErrResponse
+ } else {
+ status = StatusOK
+ }
} else if duration >= t.requestTimeout {
- status = "TIMEOUT"
+ statusMessage = "TIMEOUT"
+ status = StatusErrResponse
} else {
- status = formatError(err, url)
+ statusMessage = formatError(err, url)
+ status = StatusErr
}
return
diff --git a/hostmonitor b/hostmonitor
deleted file mode 100755
index ad92f1d..0000000
Binary files a/hostmonitor and /dev/null differ
diff --git a/web/client/src/main.tsx b/web/client/src/main.tsx
index 984866f..09fd0e4 100644
--- a/web/client/src/main.tsx
+++ b/web/client/src/main.tsx
@@ -1,5 +1,6 @@
import { lift } from '@grammarly/focal'
import {
+ Chip,
Paper,
Table,
TableBody,
@@ -14,23 +15,14 @@ import { Stream } from './stream'
const Body = lift(TableBody)
-const getBg = (item: Stream.Item) => {
- switch (true) {
- case item.httpStatus.includes('OK'):
- return '#a1ffc3'
- case item.httpStatus.includes('connection refused'):
- return '#ebffa1'
- case item.httpStatus.includes('TIMEOUT'):
- return '#fc8672'
- default:
- return undefined
- }
-}
+const Tcp = ({ item }: { item: Stream.Item }) => (
+
+)
export const Main = () => (
-
+
Address
@@ -47,14 +39,16 @@ export const Main = () => (
key={item.id}
sx={{
'&:last-child td, &:last-child th': { border: 0 },
- background: getBg(item)
+ background: Stream.Item.getStatusColor(item)
}}
>
-
- {item.id}
+
+ {item.id}
+
+
+
- {item.tcp}
- {item.httpStatus}
+ {item.httpResponse}
{item.duration}
))
diff --git a/web/client/src/stream.ts b/web/client/src/stream.ts
index 83f7380..a5f272f 100644
--- a/web/client/src/stream.ts
+++ b/web/client/src/stream.ts
@@ -1,17 +1,68 @@
+import { pipe } from 'fp-ts/es6/function'
+import { isNumber } from 'fp-ts/es6/number'
+import * as Ord from 'fp-ts/es6/Ord'
import { fromEvent, map, mergeMap, Observable, retryWhen, scan, take, timer } from 'rxjs'
import { WebSocketSubject } from 'rxjs/webSocket'
+import * as A from 'fp-ts/es6/Array'
+import { string } from 'fp-ts'
export type Stream = Observable
export namespace Stream {
const RETRY_DELAY = 5000
export interface Item {
- id: string
- inProgress: boolean
- tcp: string
- httpStatus: string
- duration: string
+ readonly id: string
+ readonly inProgress: boolean
+ readonly tcp: string
+ readonly httpResponse: string
+ readonly duration: string
+ readonly status: Stream.Item.Status
}
+
+ export namespace Item {
+ export enum Status {
+ StatusOK = 'OK',
+ StatusErr = 'Error',
+ StatusErrResponse = 'ErrorResponse'
+ }
+
+ export const ord: Ord.Ord = pipe(
+ Ord.contramap(x => x.status)(string.Ord),
+ Ord.reverse
+ )
+
+ export const getStatusColor = (item: Stream.Item) => {
+ switch (item.status) {
+ case Stream.Item.Status.StatusOK:
+ return '#a1ffc3'
+ case Stream.Item.Status.StatusErr:
+ return '#ebffa1'
+ case Stream.Item.Status.StatusErrResponse:
+ return '#fc8672'
+ default:
+ return undefined
+ }
+ }
+
+ export const getTcpStatus = (item: Stream.Item) => {
+ const success = +item.tcp.split('/')[0]
+ if (isNumber(success)) {
+ switch (true) {
+ case success >= 6:
+ return 'success'
+ case success < 6 && success > 3:
+ return 'warning'
+ case success <= 3:
+ return 'error'
+ default:
+ return 'default'
+ }
+ }
+
+ return 'default'
+ }
+ }
+
export const create = () => {
const sock = new WebSocketSubject(`ws://${location.host}/ws`)
return sock.pipe(
@@ -31,7 +82,7 @@ export namespace Stream {
(a, c) => (a.set(c.id, c), a),
new Map()
),
- map(items => [...items.values()])
+ map(items => pipe([...items.values()], A.sort(Stream.Item.ord)))
)
}
}
diff --git a/web/server.go b/web/server.go
index fbea28e..3b15c18 100644
--- a/web/server.go
+++ b/web/server.go
@@ -68,7 +68,6 @@ Loop:
s.store.ForEach(func(res core.TestResult) bool {
err := c.WriteJSON(res)
if err != nil {
- log.Println("Error sending a message to client", err.Error())
close <- true
return false
}