170 lines
3.7 KiB
Go
170 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/http"
|
|
"net/smtp"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"time"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
homedir "github.com/mitchellh/go-homedir"
|
|
"github.com/domodwyer/mailyak"
|
|
)
|
|
|
|
type Config struct {
|
|
MailHost, Username, Password, From string
|
|
Recipients []string
|
|
MailPort int
|
|
Len int64
|
|
}
|
|
|
|
var conf Config
|
|
var confFile string
|
|
|
|
func getConf() Config {
|
|
confDir := path.Dir(confFile)
|
|
|
|
if _, err := os.Stat(confDir); os.IsNotExist(err) {
|
|
log.Printf("Creating config directory")
|
|
err = os.MkdirAll(confDir, 0777)
|
|
if err != nil {
|
|
log.Fatal("Cannot create config directory: ", err)
|
|
}
|
|
}
|
|
if _, err := os.Stat(confFile); os.IsNotExist(err) {
|
|
log.Printf("Creating config file")
|
|
f, err := os.Create(confFile)
|
|
if err != nil {
|
|
log.Fatal("Cannot create config file: ", err)
|
|
}
|
|
err = f.Close()
|
|
if err != nil {
|
|
log.Fatal("Error closing config file: ", err)
|
|
}
|
|
}
|
|
if _, err := toml.DecodeFile(confFile, &conf); err != nil {
|
|
log.Fatal("Error reading config file: ", err)
|
|
}
|
|
if conf.From == "" {
|
|
conf.From = conf.Username + "@" + conf.MailHost
|
|
}
|
|
of, err := os.Create(path.Join(confDir, "c.R"))
|
|
if err != nil {
|
|
log.Fatal("Error creating R source file: ", err)
|
|
}
|
|
_, err = of.WriteString(rCode())
|
|
if err != nil {
|
|
log.Fatal("Error writing R source code: ", err)
|
|
}
|
|
return conf
|
|
}
|
|
|
|
func save() {
|
|
of, err := os.Create(confFile)
|
|
if err != nil {
|
|
log.Fatal("Cannot open config file: ", err)
|
|
}
|
|
var buf bytes.Buffer
|
|
w := bufio.NewWriter(&buf)
|
|
enc := toml.NewEncoder(w)
|
|
enc.Encode(conf)
|
|
io.Copy(of, &buf)
|
|
err = of.Close()
|
|
if err != nil {
|
|
log.Fatal("Error closing config file: ", err)
|
|
}
|
|
}
|
|
|
|
func fetch() {
|
|
url := "https://health.data.ny.gov/api/views/xdss-u53e/rows.csv?accessType=DOWNLOAD"
|
|
|
|
resp, err := http.Get(url)
|
|
if err != nil {
|
|
log.Printf("HTTP error: ", err)
|
|
return
|
|
}
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
log.Printf("Read error: ", err)
|
|
return
|
|
}
|
|
if int64(len(body)) == conf.Len {
|
|
log.Printf("Equal length, returning")
|
|
return
|
|
}
|
|
log.Printf("Length differs: body = %d", len(body))
|
|
conf.Len = int64(len(body))
|
|
save()
|
|
|
|
of, err := os.Create(path.Join(path.Dir(confFile), "rows.csv"))
|
|
if err != nil {
|
|
log.Fatal("Cannot create rows.csv: ", err)
|
|
}
|
|
_, err = of.Write(body)
|
|
if err != nil {
|
|
log.Fatal("Error writing rows.csv: ", err)
|
|
}
|
|
|
|
confDir := path.Dir(confFile)
|
|
cmd := exec.Command("R", "--no-save", "-f", path.Join(confDir, "c.R"))
|
|
log.Printf("Running R")
|
|
err = cmd.Run()
|
|
if err != nil {
|
|
log.Print("Error running R: ", err)
|
|
return
|
|
}
|
|
log.Printf("R completed")
|
|
if conf.MailHost == "" {
|
|
log.Print("No mail host set, returning")
|
|
return
|
|
}
|
|
f, err := os.Open("Rplot001.svg")
|
|
if err != nil {
|
|
log.Fatal("Error opening Rplot001.svg: ", err)
|
|
}
|
|
defer f.Close()
|
|
for _, r := range conf.Recipients {
|
|
email := mailyak.New(fmt.Sprintf("%s:%d", conf.MailHost, conf.MailPort),
|
|
smtp.PlainAuth("", conf.Username, conf.Password, conf.MailHost))
|
|
email.To(r)
|
|
email.From(conf.From)
|
|
msg := "Covid dashboard update for " + time.Now().Format("Monday, January 2 2006")
|
|
email.Subject(msg)
|
|
email.Plain().Set(msg)
|
|
email.HTML().Set(`<html><body><img src="dashboard.svg"/></body></html>`)
|
|
email.AttachInlineWithMimeType("dashboard.svg", f, "image/svg+xml")
|
|
err = email.Send()
|
|
if err != nil {
|
|
log.Print("Error sending email: ", err)
|
|
} else {
|
|
log.Print("Sent email to ", r)
|
|
}
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
log.Printf("starting")
|
|
homeDir, err := homedir.Dir()
|
|
if err != nil {
|
|
log.Fatal("Cannot locate user's home directory")
|
|
}
|
|
confFile = path.Join(homeDir, ".config", "cget", "cget.conf")
|
|
os.Chdir(path.Dir(confFile))
|
|
getConf()
|
|
|
|
for {
|
|
fetch()
|
|
time.Sleep(time.Minute * 30)
|
|
}
|
|
log.Printf("done")
|
|
}
|
|
|