hayai/wolfx/wolfx.go

177 lines
4.6 KiB
Go

package wolfx
import (
"encoding/json"
"fmt"
"hayai/config"
"hayai/constants"
"hayai/seismo"
"hayai/utils"
"log"
"net/url"
"os"
"time"
"embed"
"github.com/faiface/beep"
"github.com/faiface/beep/flac"
"github.com/faiface/beep/speaker"
"github.com/gen2brain/beeep"
"github.com/gorilla/websocket"
"github.com/sqweek/dialog"
)
//go:embed assets/alertv3-sat.flac
var alertSoundFile embed.FS
type TypeMessage struct {
Type string
}
type Issue struct {
Source string
Status string
}
type Accuracy struct {
Epicenter string
Depth string
Magnitude string
}
type MaxIntChange struct {
String string
Reason string
}
type WarnArea struct {
Chiiki string
Shindo1 string
Shindo2 string
Time string
Type string
Arrive bool
}
type JMAEEW struct {
Type string
Title string
CodeType string
Issue Issue
EventID string
Serial int
AnnouncedTime string
OriginTime string
Hypocenter string
Latitude float64
Longitude float64
Magunitude float64
Depth int
MaxIntensity string
Accuracy Accuracy
MaxIntChange MaxIntChange
WarnArea []WarnArea
IsSea bool
IsTraining bool
IsAssumption bool
IsWarn bool
IsFinal bool
IsCancel bool
OriginalText string
Pond string
}
var LastRetry time.Time
func Listen() {
// Init sound
alertSound, err := alertSoundFile.Open("assets/alertv3-sat.flac")
utils.CheckError(err)
defer alertSound.Close()
streamer, format, err := flac.Decode(alertSound)
utils.CheckError(err)
defer streamer.Close()
// Listen
u := url.URL{Scheme: "wss", Host: constants.WSHost, Path: "/all_eew"}
for {
log.Printf("connecting to %s", u.String())
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Print("dial:", err)
time.Sleep(time.Duration(config.Config.RetryConnectionEveryXS) * time.Second)
continue
}
defer c.Close()
done := make(chan struct{})
defer close(done)
log.Printf("connected.")
for {
_, message, err := c.ReadMessage()
utils.CheckError(err)
if message == nil {
log.Printf("connection lost.")
if time.Since(LastRetry) < time.Duration(config.Config.RetryConnectionEveryXS)*time.Second {
time.Sleep(time.Duration(config.Config.RetryConnectionEveryXS) * time.Second)
LastRetry = time.Now()
}
break
}
var typeMessage TypeMessage
if config.Config.TestWarning {
message = constants.TestMessage
}
json.Unmarshal(message, &typeMessage)
if typeMessage.Type == "jma_eew" {
log.Printf("recv: %s", message)
var jmaeew JMAEEW
json.Unmarshal(message, &jmaeew)
if !jmaeew.IsWarn && config.Config.OnlyWarnings {
continue
}
equivalentMagnitude := seismo.CalculateEquivalentMagnitude(jmaeew.Magunitude, jmaeew.Latitude, jmaeew.Longitude, config.Config.Latitude, config.Config.Longitude)
if config.Config.IssueWarningAtAnyMagnitude || config.Config.IssueWarningAtEquivalentMagnitude < equivalentMagnitude {
warnareas := ""
if len(jmaeew.WarnArea) != 0 {
warnareas += "\nWarnings issued for:"
}
for _, warnarea := range jmaeew.WarnArea {
warnareas += fmt.Sprintf("\n - %s (at %s JST) [Shindo %s / %s] [%s]", warnarea.Chiiki, warnarea.Time, warnarea.Shindo1, warnarea.Shindo2, warnarea.Type)
}
alert_body := fmt.Sprintf("Epicenter: %s\nMagnitude %0.1f\nApproximately magnitude %0.1f at your location%s\n\nStrong shaking is expected soon.\nStay calm and seek shelter nearby.\n\nOrigin time: %s JST\nAnnouncement time: %s JST\nDepth: %dkm\nCoordinates: %0.1f, %0.1f\n\nSource: %s\nStatus: %s\n\n%s", jmaeew.Hypocenter, jmaeew.Magunitude, equivalentMagnitude, warnareas, jmaeew.OriginTime, jmaeew.AnnouncedTime, jmaeew.Depth, jmaeew.Latitude, jmaeew.Longitude, jmaeew.Issue.Source, jmaeew.Issue.Status, jmaeew.OriginalText)
if config.Config.IssuePopup {
go dialog.Message("%s", alert_body).Title("Early Earthquake Warning!").Info()
}
if config.Config.IssueNotification {
homedir, err := os.UserHomeDir()
utils.CheckError(err)
err = beeep.Notify("Early Earthquake Warning!", alert_body, homedir+"/.icons/actions/scalable/dialog-warning.svg")
utils.CheckError(err)
}
if config.Config.OpenWebPages {
utils.OpenURL(constants.OpenURLA)
utils.OpenURL(constants.OpenURLB)
}
if config.Config.IssueWarningSound {
speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
streamer.Seek(0)
donep := make(chan bool)
speaker.Play(beep.Seq(streamer, beep.Callback(func() {
donep <- true
})))
<-donep
speaker.Close()
}
}
}
}
}
}