Make sure ooniprobe show <id>
is WAI (#61)
1. the description of the command and the helper function are clear hints that the command is intended to show a single JSON measurement at a time (also the use case seems clear) [*] 2. the function used to read lines was failing for all my measurements that take input. Since that was not the optimal pattern anyway, use a better pattern to fix it. 3. some changes are automatically applied by my editor (VSCode with the Go plugin) and I am fine with them. 4. while reading code, I also applied my preferred pattern wrt whitespaces, i.e.: no whitespace inside functions, if a function feels too long in this way, just break it. Closes #57 [*] Even if we want to show many measurements at a time, which does not seem needed, given the UI patterns, this functionality won't be P0. What is P0 is to bless a new beta and give to @sarathms binaries for all archs that support a basic `show`.
This commit is contained in:
parent
f3865d2ec0
commit
7cde93fca4
|
@ -10,9 +10,7 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cmd := root.Command("list", "List results")
|
cmd := root.Command("list", "List results")
|
||||||
|
|
||||||
resultID := cmd.Arg("id", "the id of the result to list measurements for").Int64()
|
resultID := cmd.Arg("id", "the id of the result to list measurements for").Int64()
|
||||||
|
|
||||||
cmd.Action(func(_ *kingpin.ParseContext) error {
|
cmd.Action(func(_ *kingpin.ParseContext) error {
|
||||||
ctx, err := root.Init()
|
ctx, err := root.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -25,7 +23,6 @@ func init() {
|
||||||
log.WithError(err).Error("failed to list measurements")
|
log.WithError(err).Error("failed to list measurements")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
msmtSummary := output.MeasurementSummaryData{
|
msmtSummary := output.MeasurementSummaryData{
|
||||||
TotalCount: 0,
|
TotalCount: 0,
|
||||||
AnomalyCount: 0,
|
AnomalyCount: 0,
|
||||||
|
@ -45,7 +42,6 @@ func init() {
|
||||||
if idx == len(measurements)-1 {
|
if idx == len(measurements)-1 {
|
||||||
isLast = true
|
isLast = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// We assume that since these are summary level information the first
|
// We assume that since these are summary level information the first
|
||||||
// item will contain the information necessary.
|
// item will contain the information necessary.
|
||||||
if isFirst {
|
if isFirst {
|
||||||
|
@ -70,7 +66,6 @@ func init() {
|
||||||
log.WithError(err).Error("failed to list results")
|
log.WithError(err).Error("failed to list results")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(incompleteResults) > 0 {
|
if len(incompleteResults) > 0 {
|
||||||
output.SectionTitle("Incomplete results")
|
output.SectionTitle("Incomplete results")
|
||||||
}
|
}
|
||||||
|
@ -92,7 +87,6 @@ func init() {
|
||||||
DataUsageDown: result.DataUsageDown,
|
DataUsageDown: result.DataUsageDown,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
resultSummary := output.ResultSummaryData{}
|
resultSummary := output.ResultSummaryData{}
|
||||||
netCount := make(map[uint]int)
|
netCount := make(map[uint]int)
|
||||||
output.SectionTitle("Results")
|
output.SectionTitle("Results")
|
||||||
|
@ -127,10 +121,8 @@ func init() {
|
||||||
resultSummary.TotalDataUsageDown += result.DataUsageDown
|
resultSummary.TotalDataUsageDown += result.DataUsageDown
|
||||||
}
|
}
|
||||||
resultSummary.TotalNetworks = int64(len(netCount))
|
resultSummary.TotalNetworks = int64(len(netCount))
|
||||||
|
|
||||||
output.ResultSummary(resultSummary)
|
output.ResultSummary(resultSummary)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,7 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cmd := root.Command("show", "Show a specific measurement")
|
cmd := root.Command("show", "Show a specific measurement")
|
||||||
|
msmtID := cmd.Arg("id", "the id of the measurement to show").Required().Int64()
|
||||||
msmtID := cmd.Arg("id", "the id of the measurement to show").Int64()
|
|
||||||
|
|
||||||
cmd.Action(func(_ *kingpin.ParseContext) error {
|
cmd.Action(func(_ *kingpin.ParseContext) error {
|
||||||
ctx, err := root.Init()
|
ctx, err := root.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"bufio"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
@ -11,9 +11,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/ooni/probe-cli/utils"
|
|
||||||
"github.com/ooni/probe-cli/internal/enginex"
|
"github.com/ooni/probe-cli/internal/enginex"
|
||||||
"github.com/ooni/probe-cli/internal/util"
|
"github.com/ooni/probe-cli/utils"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
db "upper.io/db.v3"
|
db "upper.io/db.v3"
|
||||||
"upper.io/db.v3/lib/sqlbuilder"
|
"upper.io/db.v3/lib/sqlbuilder"
|
||||||
|
@ -22,7 +21,6 @@ import (
|
||||||
// ListMeasurements given a result ID
|
// ListMeasurements given a result ID
|
||||||
func ListMeasurements(sess sqlbuilder.Database, resultID int64) ([]MeasurementURLNetwork, error) {
|
func ListMeasurements(sess sqlbuilder.Database, resultID int64) ([]MeasurementURLNetwork, error) {
|
||||||
measurements := []MeasurementURLNetwork{}
|
measurements := []MeasurementURLNetwork{}
|
||||||
|
|
||||||
req := sess.Select(
|
req := sess.Select(
|
||||||
db.Raw("networks.*"),
|
db.Raw("networks.*"),
|
||||||
db.Raw("urls.*"),
|
db.Raw("urls.*"),
|
||||||
|
@ -34,7 +32,6 @@ func ListMeasurements(sess sqlbuilder.Database, resultID int64) ([]MeasurementUR
|
||||||
LeftJoin("urls").On("urls.url_id = measurements.url_id").
|
LeftJoin("urls").On("urls.url_id = measurements.url_id").
|
||||||
OrderBy("measurements.measurement_start_time").
|
OrderBy("measurements.measurement_start_time").
|
||||||
Where("results.result_id = ?", resultID)
|
Where("results.result_id = ?", resultID)
|
||||||
|
|
||||||
if err := req.All(&measurements); err != nil {
|
if err := req.All(&measurements); err != nil {
|
||||||
log.Errorf("failed to run query %s: %v", req.String(), err)
|
log.Errorf("failed to run query %s: %v", req.String(), err)
|
||||||
return measurements, err
|
return measurements, err
|
||||||
|
@ -42,20 +39,18 @@ func ListMeasurements(sess sqlbuilder.Database, resultID int64) ([]MeasurementUR
|
||||||
return measurements, nil
|
return measurements, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMeasurementJSON will a map[string]interface{} given a database and a measurementID
|
// GetMeasurementJSON returns a map[string]interface{} given a database and a measurementID
|
||||||
func GetMeasurementJSON(sess sqlbuilder.Database, measurementID int64) (map[string]interface{}, error) {
|
func GetMeasurementJSON(sess sqlbuilder.Database, measurementID int64) (map[string]interface{}, error) {
|
||||||
var (
|
var (
|
||||||
measurement MeasurementURLNetwork
|
measurement MeasurementURLNetwork
|
||||||
msmtJSON map[string]interface{}
|
msmtJSON map[string]interface{}
|
||||||
)
|
)
|
||||||
|
|
||||||
req := sess.Select(
|
req := sess.Select(
|
||||||
db.Raw("urls.*"),
|
db.Raw("urls.*"),
|
||||||
db.Raw("measurements.*"),
|
db.Raw("measurements.*"),
|
||||||
).From("measurements").
|
).From("measurements").
|
||||||
LeftJoin("urls").On("urls.url_id = measurements.url_id").
|
LeftJoin("urls").On("urls.url_id = measurements.url_id").
|
||||||
Where("measurements.measurement_id= ?", measurementID)
|
Where("measurements.measurement_id= ?", measurementID)
|
||||||
|
|
||||||
if err := req.One(&measurement); err != nil {
|
if err := req.One(&measurement); err != nil {
|
||||||
log.Errorf("failed to run query %s: %v", req.String(), err)
|
log.Errorf("failed to run query %s: %v", req.String(), err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -63,7 +58,7 @@ func GetMeasurementJSON(sess sqlbuilder.Database, measurementID int64) (map[stri
|
||||||
reportFilePath := measurement.Measurement.ReportFilePath
|
reportFilePath := measurement.Measurement.ReportFilePath
|
||||||
// If the url->url is NULL then we are dealing with a single entry
|
// If the url->url is NULL then we are dealing with a single entry
|
||||||
// measurement and all we have to do is read the file and return it.
|
// measurement and all we have to do is read the file and return it.
|
||||||
if (measurement.URL.URL.Valid == false) {
|
if measurement.URL.URL.Valid == false {
|
||||||
b, err := ioutil.ReadFile(reportFilePath)
|
b, err := ioutil.ReadFile(reportFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -73,7 +68,6 @@ func GetMeasurementJSON(sess sqlbuilder.Database, measurementID int64) (map[stri
|
||||||
}
|
}
|
||||||
return msmtJSON, nil
|
return msmtJSON, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the URL is a string then we need to seek until we reach the
|
// When the URL is a string then we need to seek until we reach the
|
||||||
// measurement line in the file that matches the target input
|
// measurement line in the file that matches the target input
|
||||||
url := measurement.URL.URL.String
|
url := measurement.URL.URL.String
|
||||||
|
@ -82,20 +76,19 @@ func GetMeasurementJSON(sess sqlbuilder.Database, measurementID int64) (map[stri
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
reader := bufio.NewReader(file)
|
reader := bufio.NewReader(file)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
line, err := util.ReadLine(reader)
|
line, err := reader.ReadString('\n')
|
||||||
if (err == io.EOF) {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
}
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal([]byte(line), &msmtJSON); err != nil {
|
if err := json.Unmarshal([]byte(line), &msmtJSON); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if (msmtJSON["input"].(string) == url) {
|
if msmtJSON["input"].(string) == url {
|
||||||
return msmtJSON, nil
|
return msmtJSON, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,21 +159,18 @@ func GetMeasurementCounts(sess sqlbuilder.Database, resultID int64) (uint64, uin
|
||||||
func ListResults(sess sqlbuilder.Database) ([]ResultNetwork, []ResultNetwork, error) {
|
func ListResults(sess sqlbuilder.Database) ([]ResultNetwork, []ResultNetwork, error) {
|
||||||
doneResults := []ResultNetwork{}
|
doneResults := []ResultNetwork{}
|
||||||
incompleteResults := []ResultNetwork{}
|
incompleteResults := []ResultNetwork{}
|
||||||
|
|
||||||
req := sess.Select(
|
req := sess.Select(
|
||||||
db.Raw("networks.*"),
|
db.Raw("networks.*"),
|
||||||
db.Raw("results.*"),
|
db.Raw("results.*"),
|
||||||
).From("results").
|
).From("results").
|
||||||
Join("networks").On("results.network_id = networks.network_id").
|
Join("networks").On("results.network_id = networks.network_id").
|
||||||
OrderBy("results.result_start_time")
|
OrderBy("results.result_start_time")
|
||||||
|
|
||||||
if err := req.Where("result_is_done = true").All(&doneResults); err != nil {
|
if err := req.Where("result_is_done = true").All(&doneResults); err != nil {
|
||||||
return doneResults, incompleteResults, errors.Wrap(err, "failed to get result done list")
|
return doneResults, incompleteResults, errors.Wrap(err, "failed to get result done list")
|
||||||
}
|
}
|
||||||
if err := req.Where("result_is_done = false").All(&incompleteResults); err != nil {
|
if err := req.Where("result_is_done = false").All(&incompleteResults); err != nil {
|
||||||
return doneResults, incompleteResults, errors.Wrap(err, "failed to get result done list")
|
return doneResults, incompleteResults, errors.Wrap(err, "failed to get result done list")
|
||||||
}
|
}
|
||||||
|
|
||||||
return doneResults, incompleteResults, nil
|
return doneResults, incompleteResults, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -30,6 +29,8 @@ var ansiEscapes = regexp.MustCompile(`[\x1B\x9B][[\]()#;?]*` +
|
||||||
`(?:(?:(?:[a-zA-Z\d]*(?:;[a-zA-Z\\d]*)*)?\x07)` +
|
`(?:(?:(?:[a-zA-Z\d]*(?:;[a-zA-Z\\d]*)*)?\x07)` +
|
||||||
`|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PRZcf-ntqry=><~]))`)
|
`|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PRZcf-ntqry=><~]))`)
|
||||||
|
|
||||||
|
// EscapeAwareRuneCountInString counts the number of runes in a
|
||||||
|
// string taking into account escape sequences.
|
||||||
func EscapeAwareRuneCountInString(s string) int {
|
func EscapeAwareRuneCountInString(s string) int {
|
||||||
n := utf8.RuneCountInString(s)
|
n := utf8.RuneCountInString(s)
|
||||||
for _, sm := range ansiEscapes.FindAllString(s, -1) {
|
for _, sm := range ansiEscapes.FindAllString(s, -1) {
|
||||||
|
@ -38,6 +39,7 @@ func EscapeAwareRuneCountInString(s string) int {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RightPadd adds right padding in from of a string
|
||||||
func RightPad(str string, length int) string {
|
func RightPad(str string, length int) string {
|
||||||
c := length - EscapeAwareRuneCountInString(str)
|
c := length - EscapeAwareRuneCountInString(str)
|
||||||
if c < 0 {
|
if c < 0 {
|
||||||
|
@ -113,17 +115,3 @@ func WrapString(s string, lim uint) string {
|
||||||
|
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadLine will read a single line from a bufio.Reader
|
|
||||||
func ReadLine(r *bufio.Reader) (string, error) {
|
|
||||||
var (
|
|
||||||
isPrefix bool
|
|
||||||
err error
|
|
||||||
line, ln []byte
|
|
||||||
)
|
|
||||||
for isPrefix && err == nil {
|
|
||||||
line, isPrefix, err = r.ReadLine()
|
|
||||||
ln = append(ln, line...)
|
|
||||||
}
|
|
||||||
return string(ln), err
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user