From 417d065aa6c2a19b691e355e5bf55ad96e4cb43d Mon Sep 17 00:00:00 2001 From: czechbol Date: Sun, 9 Apr 2023 14:28:09 +0200 Subject: [PATCH 1/4] improved report objects --- report/csv.go | 18 --------- report/{json.go => testreport.go} | 30 ++++++++++++++- speedtest/helper.go | 64 ++++++++++++------------------- speedtest/speedtest.go | 2 +- 4 files changed, 54 insertions(+), 60 deletions(-) delete mode 100644 report/csv.go rename report/{json.go => testreport.go} (54%) diff --git a/report/csv.go b/report/csv.go deleted file mode 100644 index 946a275..0000000 --- a/report/csv.go +++ /dev/null @@ -1,18 +0,0 @@ -package report - -import ( - "time" -) - -// CSVReport represents the output data fields in a CSV file -type CSVReport struct { - Timestamp time.Time `csv:"Timestamp"` - Name string `csv:"Server Name"` - Address string `csv:"Address"` - Ping float64 `csv:"Ping"` - Jitter float64 `csv:"Jitter"` - Download float64 `csv:"Download"` - Upload float64 `csv:"Upload"` - Share string `csv:"Share"` - IP string `csv:"IP"` -} diff --git a/report/json.go b/report/testreport.go similarity index 54% rename from report/json.go rename to report/testreport.go index fee05b3..2440a1b 100644 --- a/report/json.go +++ b/report/testreport.go @@ -7,7 +7,7 @@ import ( ) // JSONReport represents the output data fields in a JSON file -type JSONReport struct { +type Report struct { Timestamp time.Time `json:"timestamp"` Server Server `json:"server"` Client Client `json:"client"` @@ -20,6 +20,18 @@ type JSONReport struct { Share string `json:"share"` } +type FlatReport struct { + Timestamp time.Time `csv:"Timestamp"` + Name string `csv:"Server Name"` + Address string `csv:"Address"` + Ping float64 `csv:"Ping"` + Jitter float64 `csv:"Jitter"` + Download float64 `csv:"Download"` + Upload float64 `csv:"Upload"` + Share string `csv:"Share"` + IP string `csv:"IP"` +} + // Server represents the speed test server's information type Server struct { Name string `json:"name"` @@ -30,3 +42,19 @@ type Server struct { type Client struct { defs.IPInfoResponse } + +func (r Report) GetFlatReport() FlatReport { + var rep FlatReport + rep.Timestamp = time.Now() + + rep.Name = r.Server.Name + rep.Address = r.Server.URL + rep.Ping = r.Ping + rep.Jitter = r.Jitter + rep.Download = r.Download + rep.Upload = r.Upload + rep.Share = r.Share + rep.IP = r.Client.IP + + return rep +} diff --git a/speedtest/helper.go b/speedtest/helper.go index ddc9bc1..c4236bf 100644 --- a/speedtest/helper.go +++ b/speedtest/helper.go @@ -33,8 +33,7 @@ func doSpeedTest(c *cli.Context, servers []defs.Server, telemetryServer defs.Tel log.Infof("Testing against %d servers", serverCount) } - var reps_json []report.JSONReport - var reps_csv []report.CSVReport + var reps []report.Report // fetch current user's IP info for _, currentServer := range servers { @@ -141,43 +140,24 @@ func doSpeedTest(c *cli.Context, servers []defs.Server, telemetryServer defs.Tel } } - // check for --csv or --json. the program prioritize the --csv before the --json. this is the same behavior as speedtest-cli - if c.Bool(defs.OptionCSV) { - // print csv if --csv is given - var rep report.CSVReport - rep.Timestamp = time.Now() - - rep.Name = currentServer.Name - rep.Address = u.String() - rep.Ping = math.Round(p*100) / 100 - rep.Jitter = math.Round(jitter*100) / 100 - rep.Download = math.Round(downloadValue*100) / 100 - rep.Upload = math.Round(uploadValue*100) / 100 - rep.Share = shareLink - rep.IP = ispInfo.RawISPInfo.IP - - reps_csv = append(reps_csv, rep) - } else if c.Bool(defs.OptionJSON) { - // print json if --json is given - var rep report.JSONReport - rep.Timestamp = time.Now() - - rep.Ping = math.Round(p*100) / 100 - rep.Jitter = math.Round(jitter*100) / 100 - rep.Download = math.Round(downloadValue*100) / 100 - rep.Upload = math.Round(uploadValue*100) / 100 - rep.BytesReceived = bytesRead - rep.BytesSent = bytesWritten - rep.Share = shareLink - - rep.Server.Name = currentServer.Name - rep.Server.URL = u.String() - - rep.Client = report.Client{ispInfo.RawISPInfo} - rep.Client.Readme = "" - - reps_json = append(reps_json, rep) - } + var rep report.Report + rep.Timestamp = time.Now() + + rep.Ping = math.Round(p*100) / 100 + rep.Jitter = math.Round(jitter*100) / 100 + rep.Download = math.Round(downloadValue*100) / 100 + rep.Upload = math.Round(uploadValue*100) / 100 + rep.BytesReceived = bytesRead + rep.BytesSent = bytesWritten + rep.Share = shareLink + + rep.Server.Name = currentServer.Name + rep.Server.URL = u.String() + + rep.Client = report.Client{IPInfoResponse: ispInfo.RawISPInfo} + rep.Client.Readme = "" + + reps = append(reps, rep) } else { log.Infof("Selected server %s (%s) is not responding at the moment, try again later", currentServer.Name, u.Hostname()) } @@ -191,13 +171,17 @@ func doSpeedTest(c *cli.Context, servers []defs.Server, telemetryServer defs.Tel // check for --csv or --json. the program prioritize the --csv before the --json. this is the same behavior as speedtest-cli if c.Bool(defs.OptionCSV) { var buf bytes.Buffer + var reps_csv []report.FlatReport + for _, rep := range reps { + reps_csv = append(reps_csv, rep.GetFlatReport()) + } if err := gocsv.MarshalWithoutHeaders(&reps_csv, &buf); err != nil { log.Errorf("Error generating CSV report: %s", err) } else { os.Stdout.WriteString(buf.String()) } } else if c.Bool(defs.OptionJSON) { - if b, err := json.Marshal(&reps_json); err != nil { + if b, err := json.Marshal(&reps); err != nil { log.Errorf("Error generating JSON report: %s", err) } else { os.Stdout.Write(b[:]) diff --git a/speedtest/speedtest.go b/speedtest/speedtest.go index 8a68092..ea755ef 100644 --- a/speedtest/speedtest.go +++ b/speedtest/speedtest.go @@ -79,7 +79,7 @@ func SpeedTest(c *cli.Context) error { // if --csv-header is given, print the header and exit (same behavior speedtest-cli) if c.Bool(defs.OptionCSVHeader) { - var rep []report.CSVReport + var rep []report.FlatReport b, _ := gocsv.MarshalBytes(&rep) os.Stdout.WriteString(string(b)) return nil From 456facdf712bd24fcbfbf66fc1c0ea1f0424ec79 Mon Sep 17 00:00:00 2001 From: czechbol Date: Sun, 9 Apr 2023 14:28:09 +0200 Subject: [PATCH 2/4] improved JSON and CSV printing --- speedtest/helper.go | 11 +++++------ speedtest/speedtest.go | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/speedtest/helper.go b/speedtest/helper.go index c4236bf..74bff60 100644 --- a/speedtest/helper.go +++ b/speedtest/helper.go @@ -8,7 +8,6 @@ import ( "math" "mime/multipart" "net/http" - "os" "strconv" "strings" "time" @@ -170,21 +169,21 @@ func doSpeedTest(c *cli.Context, servers []defs.Server, telemetryServer defs.Tel // check for --csv or --json. the program prioritize the --csv before the --json. this is the same behavior as speedtest-cli if c.Bool(defs.OptionCSV) { - var buf bytes.Buffer var reps_csv []report.FlatReport for _, rep := range reps { reps_csv = append(reps_csv, rep.GetFlatReport()) } - if err := gocsv.MarshalWithoutHeaders(&reps_csv, &buf); err != nil { + if resultStrig, err := gocsv.MarshalStringWithoutHeaders(&reps_csv); err != nil { log.Errorf("Error generating CSV report: %s", err) } else { - os.Stdout.WriteString(buf.String()) + fmt.Println("MarshalStringWithoutHeaders") + fmt.Print(resultStrig) } } else if c.Bool(defs.OptionJSON) { - if b, err := json.Marshal(&reps); err != nil { + if jsonBytes, err := json.Marshal(&reps); err != nil { log.Errorf("Error generating JSON report: %s", err) } else { - os.Stdout.Write(b[:]) + fmt.Println(string(jsonBytes)) } } diff --git a/speedtest/speedtest.go b/speedtest/speedtest.go index ea755ef..8ef69f3 100644 --- a/speedtest/speedtest.go +++ b/speedtest/speedtest.go @@ -80,8 +80,8 @@ func SpeedTest(c *cli.Context) error { // if --csv-header is given, print the header and exit (same behavior speedtest-cli) if c.Bool(defs.OptionCSVHeader) { var rep []report.FlatReport - b, _ := gocsv.MarshalBytes(&rep) - os.Stdout.WriteString(string(b)) + header, _ := gocsv.MarshalString(&rep) + fmt.Print(header) return nil } From a23b9c848f1d74e7c342197b2b041802442dbd33 Mon Sep 17 00:00:00 2001 From: czechbol Date: Sun, 9 Apr 2023 15:51:40 +0200 Subject: [PATCH 3/4] typo fix --- report/testreport.go | 2 +- speedtest/helper.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/report/testreport.go b/report/testreport.go index 2440a1b..deb7f20 100644 --- a/report/testreport.go +++ b/report/testreport.go @@ -45,8 +45,8 @@ type Client struct { func (r Report) GetFlatReport() FlatReport { var rep FlatReport - rep.Timestamp = time.Now() + rep.Timestamp = r.Timestamp rep.Name = r.Server.Name rep.Address = r.Server.URL rep.Ping = r.Ping diff --git a/speedtest/helper.go b/speedtest/helper.go index 74bff60..3d81683 100644 --- a/speedtest/helper.go +++ b/speedtest/helper.go @@ -176,7 +176,6 @@ func doSpeedTest(c *cli.Context, servers []defs.Server, telemetryServer defs.Tel if resultStrig, err := gocsv.MarshalStringWithoutHeaders(&reps_csv); err != nil { log.Errorf("Error generating CSV report: %s", err) } else { - fmt.Println("MarshalStringWithoutHeaders") fmt.Print(resultStrig) } } else if c.Bool(defs.OptionJSON) { From 391dc65b4729838ba3528d016a6a1416d743a339 Mon Sep 17 00:00:00 2001 From: czechbol Date: Sun, 9 Apr 2023 18:33:50 +0200 Subject: [PATCH 4/4] docstring fix --- report/testreport.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/report/testreport.go b/report/testreport.go index deb7f20..2f086d8 100644 --- a/report/testreport.go +++ b/report/testreport.go @@ -6,7 +6,7 @@ import ( "github.com/librespeed/speedtest-cli/defs" ) -// JSONReport represents the output data fields in a JSON file +// Report represents the output data fields in a nestable file data such as JSON. type Report struct { Timestamp time.Time `json:"timestamp"` Server Server `json:"server"` @@ -20,6 +20,7 @@ type Report struct { Share string `json:"share"` } +// FlatReport represents the output data fields in a flat file data such as CSV. type FlatReport struct { Timestamp time.Time `csv:"Timestamp"` Name string `csv:"Server Name"`