mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
Merge branch 'kris' of github.com:stone/wtf into stone-kris
This commit is contained in:
commit
190b06182f
@ -41,6 +41,7 @@ import (
|
||||
"github.com/wtfutil/wtf/modules/ipaddresses/ipinfo"
|
||||
"github.com/wtfutil/wtf/modules/jenkins"
|
||||
"github.com/wtfutil/wtf/modules/jira"
|
||||
"github.com/wtfutil/wtf/modules/krisinformation"
|
||||
"github.com/wtfutil/wtf/modules/kubernetes"
|
||||
"github.com/wtfutil/wtf/modules/logger"
|
||||
"github.com/wtfutil/wtf/modules/mercurial"
|
||||
@ -214,6 +215,9 @@ func MakeWidget(
|
||||
case "kubernetes":
|
||||
settings := kubernetes.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||
widget = kubernetes.NewWidget(app, settings)
|
||||
case "krisinformation":
|
||||
settings := krisinformation.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||
widget = krisinformation.NewWidget(app, settings)
|
||||
case "logger":
|
||||
settings := logger.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||
widget = logger.NewWidget(app, settings)
|
||||
|
193
modules/krisinformation/client.go
Normal file
193
modules/krisinformation/client.go
Normal file
@ -0,0 +1,193 @@
|
||||
package krisinformation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/wtfutil/wtf/logger"
|
||||
"github.com/wtfutil/wtf/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
krisinformationAPI = "https://api.krisinformation.se/v2/feed?format=json"
|
||||
)
|
||||
|
||||
type Krisinformation []struct {
|
||||
Identifier string `json:"Identifier"`
|
||||
PushMessage string `json:"PushMessage"`
|
||||
Updated time.Time `json:"Updated"`
|
||||
Published time.Time `json:"Published"`
|
||||
Headline string `json:"Headline"`
|
||||
Preamble string `json:"Preamble"`
|
||||
BodyText string `json:"BodyText"`
|
||||
Area []struct {
|
||||
Type string `json:"Type"`
|
||||
Description string `json:"Description"`
|
||||
Coordinate string `json:"Coordinate"`
|
||||
GeometryInformation interface{} `json:"GeometryInformation"`
|
||||
} `json:"Area"`
|
||||
Web string `json:"Web"`
|
||||
Language string `json:"Language"`
|
||||
Event string `json:"Event"`
|
||||
SenderName string `json:"SenderName"`
|
||||
Push bool `json:"Push"`
|
||||
BodyLinks []interface{} `json:"BodyLinks"`
|
||||
SourceID int `json:"SourceID"`
|
||||
IsVma bool `json:"IsVma"`
|
||||
IsTestVma bool `json:"IsTestVma"`
|
||||
}
|
||||
|
||||
// Client holds or configuration
|
||||
type Client struct {
|
||||
latitude float64
|
||||
longitude float64
|
||||
radius int
|
||||
county string
|
||||
country bool
|
||||
}
|
||||
|
||||
// Item holds the interesting parts
|
||||
type Item struct {
|
||||
PushMessage string
|
||||
HeadLine string
|
||||
SenderName string
|
||||
Country bool
|
||||
County bool
|
||||
Distance float64
|
||||
Updated time.Time
|
||||
}
|
||||
|
||||
//NewClient returns a new Client
|
||||
func NewClient(latitude, longitude float64, radius int, county string, country bool) *Client {
|
||||
return &Client{
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
radius: radius,
|
||||
county: county,
|
||||
country: country,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// getKrisinformation - return items that match either country, county or a radius
|
||||
// Priority:
|
||||
// - Country
|
||||
// - County
|
||||
// - Region
|
||||
func (c *Client) getKrisinformation() (items []Item, err error) {
|
||||
resp, err := http.Get(krisinformationAPI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
var data Krisinformation
|
||||
err = utils.ParseJSON(&data, resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range data {
|
||||
for a := range data[i].Area {
|
||||
// Country wide events
|
||||
if c.country && data[i].Area[a].Type == "Country" {
|
||||
item := Item{
|
||||
PushMessage: data[i].PushMessage,
|
||||
HeadLine: data[i].Headline,
|
||||
SenderName: data[i].SenderName,
|
||||
Country: true,
|
||||
Updated: data[i].Updated,
|
||||
}
|
||||
items = append(items, item)
|
||||
continue
|
||||
}
|
||||
|
||||
// County specific events
|
||||
if c.county != "" && data[i].Area[a].Type == "County" {
|
||||
// We look for county in description
|
||||
if strings.Contains(
|
||||
strings.ToLower(data[i].Area[a].Description),
|
||||
strings.ToLower(c.county),
|
||||
) {
|
||||
item := Item{
|
||||
PushMessage: data[i].PushMessage,
|
||||
HeadLine: data[i].Headline,
|
||||
SenderName: data[i].SenderName,
|
||||
County: true,
|
||||
Updated: data[i].Updated,
|
||||
}
|
||||
items = append(items, item)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if c.radius != -1 {
|
||||
coords := data[i].Area[a].Coordinate
|
||||
if coords == "" {
|
||||
continue
|
||||
}
|
||||
buf := strings.Split(coords, " ")
|
||||
latlon := strings.Split(buf[0], ",")
|
||||
kris_latitude, err := strconv.ParseFloat(latlon[0], 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kris_longitude, err := strconv.ParseFloat(latlon[1], 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
distance := DistanceInMeters(kris_latitude, kris_longitude, c.latitude, c.longitude)
|
||||
logger.Log(fmt.Sprintf("Distance: %f", distance/1000)) // KM
|
||||
if distance < float64(c.radius) {
|
||||
item := Item{
|
||||
PushMessage: data[i].PushMessage,
|
||||
HeadLine: data[i].Headline,
|
||||
SenderName: data[i].SenderName,
|
||||
Distance: distance,
|
||||
Updated: data[i].Updated,
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// haversin(θ) function
|
||||
func hsin(theta float64) float64 {
|
||||
return math.Pow(math.Sin(theta/2), 2)
|
||||
}
|
||||
|
||||
// Distance function returns the distance (in meters) between two points of
|
||||
// a given longitude and latitude relatively accurately (using a spherical
|
||||
// approximation of the Earth) through the Haversin Distance Formula for
|
||||
// great arc distance on a sphere with accuracy for small distances
|
||||
//
|
||||
// point coordinates are supplied in degrees and converted into rad. in the func
|
||||
//
|
||||
// http://en.wikipedia.org/wiki/Haversine_formula
|
||||
func DistanceInMeters(lat1, lon1, lat2, lon2 float64) float64 {
|
||||
// convert to radians
|
||||
// must cast radius as float to multiply later
|
||||
var la1, lo1, la2, lo2, r float64
|
||||
la1 = lat1 * math.Pi / 180
|
||||
lo1 = lon1 * math.Pi / 180
|
||||
la2 = lat2 * math.Pi / 180
|
||||
lo2 = lon2 * math.Pi / 180
|
||||
|
||||
r = 6378100 // Earth radius in METERS
|
||||
|
||||
// calculate
|
||||
h := hsin(la2-la1) + math.Cos(la1)*math.Cos(la2)*hsin(lo2-lo1)
|
||||
|
||||
return 2 * r * math.Asin(math.Sqrt(h))
|
||||
}
|
44
modules/krisinformation/settings.go
Normal file
44
modules/krisinformation/settings.go
Normal file
@ -0,0 +1,44 @@
|
||||
package krisinformation
|
||||
|
||||
import (
|
||||
"github.com/olebedev/config"
|
||||
"github.com/wtfutil/wtf/cfg"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultFocusable = false
|
||||
defaultTitle = "Krisinformation"
|
||||
defaultRadius = -1
|
||||
defaultCountry = true
|
||||
defaultCounty = ""
|
||||
defaultMaxItems = -1
|
||||
defaultMaxAge = 720
|
||||
)
|
||||
|
||||
// Settings defines the configuration properties for this module
|
||||
type Settings struct {
|
||||
common *cfg.Common
|
||||
latitude float64 `help:"The latitude of the position from which the widget should look for messages." optional:"true"`
|
||||
longitude float64 `help:"The longitude of the position from which the widget should look for messages." optional:"true"`
|
||||
radius int `help:"The radius in km from your position that the widget should look for messages. need latitude/longitude setting,Default 10" optional:"true"`
|
||||
county string `help:"The county from where to display messages" optional:"true"`
|
||||
country bool `help:"Only display country wide messages" optional:"true"`
|
||||
maxitems int `help:"Only display X number of latest messages" optional:"true"`
|
||||
maxage int `help:"Only show messages younger than maxage" optional:"true"`
|
||||
}
|
||||
|
||||
// NewSettingsFromYAML creates a new settings instance from a YAML config block
|
||||
func NewSettingsFromYAML(name string, ymlConfig *config.Config, globalConfig *config.Config) *Settings {
|
||||
settings := Settings{
|
||||
common: cfg.NewCommonSettingsFromModule(name, defaultTitle, defaultFocusable, ymlConfig, globalConfig),
|
||||
latitude: ymlConfig.UFloat64("latitude", -1),
|
||||
longitude: ymlConfig.UFloat64("longitude", -1),
|
||||
radius: ymlConfig.UInt("radius", defaultRadius),
|
||||
country: ymlConfig.UBool("country", defaultCountry),
|
||||
county: ymlConfig.UString("county", defaultCounty),
|
||||
maxitems: ymlConfig.UInt("maxitems", defaultMaxItems),
|
||||
maxage: ymlConfig.UInt("maxages", defaultMaxAge),
|
||||
}
|
||||
|
||||
return &settings
|
||||
}
|
90
modules/krisinformation/widget.go
Normal file
90
modules/krisinformation/widget.go
Normal file
@ -0,0 +1,90 @@
|
||||
package krisinformation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/rivo/tview"
|
||||
"github.com/wtfutil/wtf/view"
|
||||
)
|
||||
|
||||
// Widget is the container for your module's data
|
||||
type Widget struct {
|
||||
view.TextWidget
|
||||
|
||||
app *tview.Application
|
||||
settings *Settings
|
||||
err error
|
||||
client *Client
|
||||
}
|
||||
|
||||
// NewWidget creates and returns an instance of Widget
|
||||
func NewWidget(app *tview.Application, settings *Settings) *Widget {
|
||||
widget := Widget{
|
||||
TextWidget: view.NewTextWidget(app, nil, settings.common),
|
||||
app: app,
|
||||
settings: settings,
|
||||
client: NewClient(
|
||||
settings.latitude,
|
||||
settings.longitude,
|
||||
settings.radius,
|
||||
settings.county,
|
||||
settings.country),
|
||||
}
|
||||
|
||||
return &widget
|
||||
}
|
||||
|
||||
/* -------------------- Exported Functions -------------------- */
|
||||
|
||||
// Refresh updates the onscreen contents of the widget
|
||||
func (widget *Widget) Refresh() {
|
||||
if widget.Disabled() {
|
||||
return
|
||||
}
|
||||
// The last call should always be to the display function
|
||||
widget.display()
|
||||
}
|
||||
|
||||
/* -------------------- Unexported Functions -------------------- */
|
||||
|
||||
func (widget *Widget) content() (string, string, bool) {
|
||||
var title = defaultTitle
|
||||
if widget.CommonSettings().Title != "" {
|
||||
title = widget.CommonSettings().Title
|
||||
}
|
||||
now := time.Now()
|
||||
kriser, err := widget.client.getKrisinformation()
|
||||
if err != nil {
|
||||
handleError(widget, err)
|
||||
}
|
||||
|
||||
var str string
|
||||
i := 0
|
||||
for k := range kriser {
|
||||
diff := now.Sub(kriser[k].Updated)
|
||||
if widget.settings.maxage != -1 {
|
||||
// Skip if message is too old
|
||||
if int(diff.Hours()) > widget.settings.maxage {
|
||||
//logger.Log(fmt.Sprintf("Article to old: (%s) Days: %d", kriser[k].HeadLine, int(diff.Hours())))
|
||||
continue
|
||||
}
|
||||
}
|
||||
i++
|
||||
if i > widget.settings.maxitems && widget.settings.maxitems != -1 {
|
||||
break
|
||||
}
|
||||
str += fmt.Sprintf("- %s\n", kriser[k].HeadLine)
|
||||
}
|
||||
return title, str, true
|
||||
}
|
||||
|
||||
func (widget *Widget) display() {
|
||||
widget.Redraw(func() (string, string, bool) {
|
||||
return widget.content()
|
||||
})
|
||||
}
|
||||
|
||||
func handleError(widget *Widget, err error) {
|
||||
widget.err = err
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user