Skip to content
This repository has been archived by the owner on Jan 29, 2023. It is now read-only.

Feat: Add filter by GeoIP #12

Merged
merged 2 commits into from
Apr 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ bin
cover
alertcovid19
coverage.html
dist
dist
*.zip
63 changes: 44 additions & 19 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,44 @@ import (
"encoding/json"
"flag"
"fmt"
"os"
"log"
"net/http"
"os"
"time"

"github.com/gen2brain/beeep"
)

// Exported ...
const (
IMG string = "https://static.poder360.com.br/2020/03/23312-868x644.png"
URL = "https://covid19-brazil-api.now.sh/api/report/v1/brazil"
myIP = "http://ip-api.com/json"
IMG = "https://static.poder360.com.br/2020/03/23312-868x644.png"
URL = "https://corona.lmao.ninja/countries/"
StateBrazil = "https://covid19-brazil-api.now.sh/api/report/v1/brazil/uf/"
TIMEOUT = time.Second * 2
)

type geoIP struct {
CountryCode string `json:"countryCode"`
Region string `json:"region"`
}

// LastValues ...
type LastValues struct {
Confirmed int `json:"confirmed"`
Cases int `json:"cases"`
Deaths int `json:"deaths"`
Recovered int `json:"recovered"`
}

func (l LastValues) String() string {
return fmt.Sprintf("Confirmed: %d, Deaths: %d, Recovered: %d", l.Confirmed, l.Deaths, l.Recovered)
message := "Cases: %d, Deaths: %d, Recovered: %d"
return fmt.Sprintf(message, l.Cases, l.Deaths, l.Recovered)
}

// fetch runs on its own goroutine
func fetch(ctx context.Context, req *http.Request, ch chan LastValues) error {
defer close(ch)
var r struct {
Data LastValues `json:"data"`
}
var r LastValues
body, err := http.DefaultClient.Do(req)
if err != nil {
log.Printf("fetchCOVID19Data: %v", err)
Expand All @@ -47,34 +54,33 @@ func fetch(ctx context.Context, req *http.Request, ch chan LastValues) error {
log.Printf("fetchCOVID19Data: %v", err)
return err
}

select {
case ch <- LastValues{r.Data.Confirmed, r.Data.Deaths, r.Data.Recovered}:
case ch <- LastValues{r.Cases, r.Deaths, r.Recovered}:
case <-ctx.Done():
}
return nil
}

// fetchCOVID19Data ...
func fetchCOVID19Data(ctx context.Context) <-chan LastValues {
func fetchCOVID19Data(ctx context.Context, country string) <-chan LastValues {
ch := make(chan LastValues)
req, err := http.NewRequestWithContext(ctx, "GET", URL, nil)
url := URL + country
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
panic("internal error - misuse of NewRequestWithContext")
}
go fetch(ctx, req, ch)
return ch
}

func routine(sleep time.Duration) {
func routine(sleep time.Duration, country string) {
cachedVal := LastValues{}
const timeout = time.Second * 2
for {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), TIMEOUT)
select {
case newVal := <-fetchCOVID19Data(ctx):
case newVal := <-fetchCOVID19Data(ctx, country):
if cachedVal != newVal {
err := beeep.Alert("COVID-19 Brazil", newVal.String(), IMG)
err := beeep.Alert("COVID-19 "+country, newVal.String(), IMG)
if err != nil {
log.Printf("rountine: %v", err)
}
Expand All @@ -84,16 +90,35 @@ func routine(sleep time.Duration) {
log.Printf("rountine: %v", ctx.Err())
}
cancel()
log.Printf("sleeping for %s", sleep)
time.Sleep(sleep)
}
}

func getCountryByGeoIP() geoIP {
client := http.Client{Timeout: TIMEOUT}
resp, err := client.Post(
myIP,
"application/json; charset=utf8",
nil,
)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
var ip geoIP
err = json.NewDecoder(resp.Body).Decode(&ip)
if err != nil {
log.Fatalf("Oops, we cannot get your location, please verify your network.")
}
return ip
}

func main() {
log.SetPrefix(os.Args[0] + ": ")
log.SetFlags(0)
var timer time.Duration
flag.DurationVar(&timer, "t", time.Hour, "interval between each api request")
flag.Parse()
routine(timer)
ip := getCountryByGeoIP()
routine(timer, ip.CountryCode)
}
8 changes: 4 additions & 4 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ func TestLastValues_String(t *testing.T) {
{
name: "Test format message to show in the notification",
fields: LastValues{
Confirmed: 100,
Cases: 100,
Deaths: 7,
Recovered: 1,
},
want: "Confirmed: 100, Deaths: 7, Recovered: 1",
want: "Cases: 100, Deaths: 7, Recovered: 1",
},
}
for _, v := range tests {
Expand All @@ -42,8 +42,8 @@ func TestFetch(t *testing.T) {
input io.Reader
want bool
}{
{"ok json", strings.NewReader(`{"data": {"confirmed": 10, "deaths": 10, "recovered": 10}}`), true},
{"bad json", strings.NewReader(`{"data": "confirmed": 10, "deaths": 10, "recovered": 10}}`), false},
{"ok json", strings.NewReader(`{"data": {"cases": 10, "deaths": 10, "recovered": 10}}`), true},
{"bad json", strings.NewReader(`{"data": "cases": 10, "deaths": 10, "recovered": 10}}`), false},
}
for _, v := range tests {
v := v
Expand Down