github.com/wtfutil/wtf@v0.43.0/modules/krisinformation/client.go (about) 1 package krisinformation 2 3 import ( 4 "fmt" 5 "math" 6 "net/http" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/wtfutil/wtf/logger" 12 "github.com/wtfutil/wtf/utils" 13 ) 14 15 const ( 16 krisinformationAPI = "https://api.krisinformation.se/v2/feed?format=json" 17 ) 18 19 type Krisinformation []struct { 20 Identifier string `json:"Identifier"` 21 PushMessage string `json:"PushMessage"` 22 Updated time.Time `json:"Updated"` 23 Published time.Time `json:"Published"` 24 Headline string `json:"Headline"` 25 Preamble string `json:"Preamble"` 26 BodyText string `json:"BodyText"` 27 Area []struct { 28 Type string `json:"Type"` 29 Description string `json:"Description"` 30 Coordinate string `json:"Coordinate"` 31 GeometryInformation interface{} `json:"GeometryInformation"` 32 } `json:"Area"` 33 Web string `json:"Web"` 34 Language string `json:"Language"` 35 Event string `json:"Event"` 36 SenderName string `json:"SenderName"` 37 Push bool `json:"Push"` 38 BodyLinks []interface{} `json:"BodyLinks"` 39 SourceID int `json:"SourceID"` 40 IsVma bool `json:"IsVma"` 41 IsTestVma bool `json:"IsTestVma"` 42 } 43 44 // Client holds or configuration 45 type Client struct { 46 latitude float64 47 longitude float64 48 radius int 49 county string 50 country bool 51 } 52 53 // Item holds the interesting parts 54 type Item struct { 55 PushMessage string 56 HeadLine string 57 SenderName string 58 Country bool 59 County bool 60 Distance float64 61 Updated time.Time 62 } 63 64 // NewClient returns a new Client 65 func NewClient(latitude, longitude float64, radius int, county string, country bool) *Client { 66 return &Client{ 67 latitude: latitude, 68 longitude: longitude, 69 radius: radius, 70 county: county, 71 country: country, 72 } 73 74 } 75 76 // getKrisinformation - return items that match either country, county or a radius 77 // Priority: 78 // - Country 79 // - County 80 // - Region 81 func (c *Client) getKrisinformation() (items []Item, err error) { 82 resp, err := http.Get(krisinformationAPI) 83 if err != nil { 84 return nil, err 85 } 86 defer func() { _ = resp.Body.Close() }() 87 88 var data Krisinformation 89 err = utils.ParseJSON(&data, resp.Body) 90 if err != nil { 91 return nil, err 92 } 93 94 for i := range data { 95 for a := range data[i].Area { 96 // Country wide events 97 if c.country && data[i].Area[a].Type == "Country" { 98 item := Item{ 99 PushMessage: data[i].PushMessage, 100 HeadLine: data[i].Headline, 101 SenderName: data[i].SenderName, 102 Country: true, 103 Updated: data[i].Updated, 104 } 105 items = append(items, item) 106 continue 107 } 108 109 // County specific events 110 if c.county != "" && data[i].Area[a].Type == "County" { 111 // We look for county in description 112 if strings.Contains( 113 strings.ToLower(data[i].Area[a].Description), 114 strings.ToLower(c.county), 115 ) { 116 item := Item{ 117 PushMessage: data[i].PushMessage, 118 HeadLine: data[i].Headline, 119 SenderName: data[i].SenderName, 120 County: true, 121 Updated: data[i].Updated, 122 } 123 items = append(items, item) 124 continue 125 } 126 } 127 128 if c.radius != -1 { 129 coords := data[i].Area[a].Coordinate 130 if coords == "" { 131 continue 132 } 133 buf := strings.Split(coords, " ") 134 latlon := strings.Split(buf[0], ",") 135 kris_latitude, err := strconv.ParseFloat(latlon[0], 32) 136 if err != nil { 137 return nil, err 138 } 139 140 kris_longitude, err := strconv.ParseFloat(latlon[1], 32) 141 if err != nil { 142 return nil, err 143 } 144 145 distance := DistanceInMeters(kris_latitude, kris_longitude, c.latitude, c.longitude) 146 logger.Log(fmt.Sprintf("Distance: %f", distance/1000)) // KM 147 if distance < float64(c.radius) { 148 item := Item{ 149 PushMessage: data[i].PushMessage, 150 HeadLine: data[i].Headline, 151 SenderName: data[i].SenderName, 152 Distance: distance, 153 Updated: data[i].Updated, 154 } 155 items = append(items, item) 156 } 157 158 } 159 } 160 } 161 162 return items, nil 163 } 164 165 // haversin(θ) function 166 func hsin(theta float64) float64 { 167 return math.Pow(math.Sin(theta/2), 2) 168 } 169 170 // Distance function returns the distance (in meters) between two points of 171 // 172 // a given longitude and latitude relatively accurately (using a spherical 173 // approximation of the Earth) through the Haversin Distance Formula for 174 // great arc distance on a sphere with accuracy for small distances 175 // 176 // point coordinates are supplied in degrees and converted into rad. in the func 177 // 178 // http://en.wikipedia.org/wiki/Haversine_formula 179 func DistanceInMeters(lat1, lon1, lat2, lon2 float64) float64 { 180 // convert to radians 181 // must cast radius as float to multiply later 182 var la1, lo1, la2, lo2, r float64 183 la1 = lat1 * math.Pi / 180 184 lo1 = lon1 * math.Pi / 180 185 la2 = lat2 * math.Pi / 180 186 lo2 = lon2 * math.Pi / 180 187 188 r = 6378100 // Earth radius in METERS 189 190 // calculate 191 h := hsin(la2-la1) + math.Cos(la1)*math.Cos(la2)*hsin(lo2-lo1) 192 193 return 2 * r * math.Asin(math.Sqrt(h)) 194 }