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/ipaddresses/ipinfo"
|
||||||
"github.com/wtfutil/wtf/modules/jenkins"
|
"github.com/wtfutil/wtf/modules/jenkins"
|
||||||
"github.com/wtfutil/wtf/modules/jira"
|
"github.com/wtfutil/wtf/modules/jira"
|
||||||
|
"github.com/wtfutil/wtf/modules/krisinformation"
|
||||||
"github.com/wtfutil/wtf/modules/kubernetes"
|
"github.com/wtfutil/wtf/modules/kubernetes"
|
||||||
"github.com/wtfutil/wtf/modules/logger"
|
"github.com/wtfutil/wtf/modules/logger"
|
||||||
"github.com/wtfutil/wtf/modules/mercurial"
|
"github.com/wtfutil/wtf/modules/mercurial"
|
||||||
@ -214,6 +215,9 @@ func MakeWidget(
|
|||||||
case "kubernetes":
|
case "kubernetes":
|
||||||
settings := kubernetes.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
settings := kubernetes.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||||
widget = kubernetes.NewWidget(app, settings)
|
widget = kubernetes.NewWidget(app, settings)
|
||||||
|
case "krisinformation":
|
||||||
|
settings := krisinformation.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||||
|
widget = krisinformation.NewWidget(app, settings)
|
||||||
case "logger":
|
case "logger":
|
||||||
settings := logger.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
settings := logger.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||||
widget = logger.NewWidget(app, settings)
|
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