You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wttr.in/internal/view/v1/cmd.go

173 lines
4.2 KiB

// This code represents wttr.in view v1.
// It is based on wego (github.com/schachmat/wego) from which it diverged back in 2016.
//nolint:forbidigo,funlen,gocognit,cyclop
package v1
import (
"encoding/json"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"os/user"
"path"
"regexp"
"strings"
"github.com/mattn/go-colorable"
"github.com/mattn/go-runewidth"
)
type Configuration struct {
APIKey string
City string
Numdays int
Imperial bool
WindUnit bool
Inverse bool
Lang string
Narrow bool
LocationName string
WindMS bool
RightToLeft bool
}
type global struct {
ansiEsc *regexp.Regexp
config Configuration
configpath string
debug bool
}
const (
wuri = "http://127.0.0.1:5001/premium/v1/weather.ashx?"
suri = "http://127.0.0.1:5001/premium/v1/search.ashx?"
slotcount = 4
)
func (g *global) configload() error {
b, err := ioutil.ReadFile(g.configpath)
if err == nil {
return json.Unmarshal(b, &g.config)
}
return err
}
func (g *global) configsave() error {
j, err := json.MarshalIndent(g.config, "", "\t")
if err == nil {
return ioutil.WriteFile(g.configpath, j, 0o600)
}
return err
}
func (g *global) init() {
flag.IntVar(&g.config.Numdays, "days", 3, "Number of days of weather forecast to be displayed")
flag.StringVar(&g.config.Lang, "lang", "en", "Language of the report")
flag.StringVar(&g.config.City, "city", "New York", "City to be queried")
flag.BoolVar(&g.debug, "debug", false, "Print out raw json response for debugging purposes")
flag.BoolVar(&g.config.Imperial, "imperial", false, "Use imperial units")
flag.BoolVar(&g.config.Inverse, "inverse", false, "Use inverted colors")
flag.BoolVar(&g.config.Narrow, "narrow", false, "Narrow output (two columns)")
flag.StringVar(&g.config.LocationName, "location_name", "", "Location name (used in the caption)")
flag.BoolVar(&g.config.WindMS, "wind_in_ms", false, "Show wind speed in m/s")
flag.BoolVar(&g.config.RightToLeft, "right_to_left", false, "Right to left script")
g.configpath = os.Getenv("WEGORC")
if g.configpath == "" {
usr, err := user.Current()
if err != nil {
log.Fatalf("%v\nYou can set the environment variable WEGORC to point to your config file as a workaround.", err)
}
g.configpath = path.Join(usr.HomeDir, ".wegorc")
}
g.config.APIKey = ""
g.config.Imperial = false
g.config.Lang = "en"
err := g.configload()
var pathError *os.PathError
if errors.Is(err, pathError) {
log.Printf("No config file found. Creating %s ...", g.configpath)
if err2 := g.configsave(); err2 != nil {
log.Fatal(err2)
}
} else if err != nil {
log.Fatalf("could not parse %v: %v", g.configpath, err)
}
g.ansiEsc = regexp.MustCompile("\033.*?m")
}
func Cmd() error {
g := global{}
g.init()
flag.Parse()
r, err := g.getDataFromAPI()
if err != nil {
return err
}
if r.Data.Req == nil || len(r.Data.Req) < 1 {
if r.Data.Err != nil && len(r.Data.Err) >= 1 {
log.Fatal(r.Data.Err[0].Msg)
}
log.Fatal("Malformed response.")
}
locationName := r.Data.Req[0].Query
if g.config.LocationName != "" {
locationName = g.config.LocationName
}
if g.config.Lang == "he" || g.config.Lang == "ar" || g.config.Lang == "fa" {
g.config.RightToLeft = true
}
if caption, ok := localizedCaption()[g.config.Lang]; !ok {
fmt.Printf("Weather report: %s\n\n", locationName)
} else {
if g.config.RightToLeft {
caption = locationName + " " + caption
space := strings.Repeat(" ", 125-runewidth.StringWidth(caption))
fmt.Printf("%s%s\n\n", space, caption)
} else {
fmt.Printf("%s %s\n\n", caption, locationName)
}
}
stdout := colorable.NewColorableStdout()
if r.Data.Cur == nil || len(r.Data.Cur) < 1 {
log.Fatal("No weather data available.")
}
out := g.formatCond(make([]string, 5), r.Data.Cur[0], true)
for _, val := range out {
if g.config.RightToLeft {
fmt.Fprint(stdout, strings.Repeat(" ", 94))
} else {
fmt.Fprint(stdout, " ")
}
fmt.Fprintln(stdout, val)
}
if g.config.Numdays == 0 {
return nil
}
if r.Data.Weather == nil {
log.Fatal("No detailed weather forecast available.")
}
for _, d := range r.Data.Weather {
lines, err := g.printDay(d)
if err != nil {
return err
}
for _, val := range lines {
fmt.Fprintln(stdout, val)
}
}
return nil
}