init: init commit

This commit is contained in:
Louis Dalibard 2024-08-25 12:20:20 +02:00
parent b75af127f7
commit 4052c039f1
12 changed files with 410 additions and 0 deletions

3
.gitignore vendored
View File

@ -23,3 +23,6 @@ go.work.sum
# env file
.env
# binary
hayai

71
config/config.go Normal file
View File

@ -0,0 +1,71 @@
package config
import (
"os"
"path/filepath"
"github.com/kirsle/configdir"
"gopkg.in/yaml.v3"
)
type ConfigS struct {
OnlyWarnings bool
Latitude float64
Longitude float64
IssueWarningAtEquivalentMagnitude float64 // 5.5 is a good default
IssueWarningAtAnyMagnitude bool
IssueWarningSound bool
IssuePopup bool
IssueNotification bool
OpenWebPages bool
TestWarning bool
}
var Config ConfigS
var DefaultConfig = ConfigS{
OnlyWarnings: false,
Latitude: 35.6799833,
Longitude: 139.7655883,
IssueWarningAtEquivalentMagnitude: 5.5,
IssueWarningAtAnyMagnitude: false,
IssueWarningSound: false,
IssuePopup: true,
IssueNotification: true,
OpenWebPages: false,
TestWarning: false,
}
func Init() {
configPath := configdir.LocalConfig("ontake", "hayai")
err := configdir.MakePath(configPath) // Ensure it exists.
if err != nil {
panic(err)
}
configFile := filepath.Join(configPath, "config.yml")
// Does the file not exist?
if _, err = os.Stat(configFile); os.IsNotExist(err) {
// Create the new config file.
fh, err := os.Create(configFile)
if err != nil {
panic(err)
}
defer fh.Close()
encoder := yaml.NewEncoder(fh)
encoder.Encode(&DefaultConfig)
Config = DefaultConfig
} else {
// Load the existing file.
fh, err := os.Open(configFile)
if err != nil {
panic(err)
}
defer fh.Close()
decoder := yaml.NewDecoder(fh)
decoder.Decode(&Config)
}
}

11
constants/constants.go Normal file
View File

@ -0,0 +1,11 @@
package constants
// https://earthquake.usgs.gov/earthquakes/eventpage/us6000d3zh/dyfi/intensity-vs-distance ignored since too tame
// https://earthquake.usgs.gov/earthquakes/eventpage/us6000nith/dyfi/intensity-vs-distance used
const MagnitudeDecreasePerKM = 0.00814867762 // 0.01159528707
var TestMessage = []byte(`{"type":"jma_eew","Title": "緊急地震速報(予報)", "CodeType": "M、最大予測震度及び主要動到達予測時刻の緊急地震速報", "Issue": {"Source": "東京", "Status": "通常"}, "EventID": "20240824093249", "Serial": 5, "AnnouncedTime": "2024/08/24 09:33:35", "OriginTime": "2024/08/24 09:32:40", "Hypocenter": "四国沖", "Latitude": 32.9, "Longitude": 134.3, "Magunitude": 4.0, "Depth": 10, "MaxIntensity": "2", "Accuracy": {"Epicenter": "IPF 法5 点以上)", "Depth": "IPF 法5 点以上)", "Magnitude": "防災科研システム"}, "MaxIntChange": {"String": "ほとんど変化なし", "Reason": "不明、未設定時、キャンセル時"}, "WarnArea": [], "isSea": true, "isTraining": false, "isAssumption": false, "isWarn": false, "isFinal": true, "isCancel": false, "OriginalText": "37 03 00 240824093335 C11 240824093240 ND20240824093249 NCN905 JD////////////// JN/// 902 N329 E1343 010 40 02 RK44209 RT10/// RC0//// 9999=", "Pond": "41"}`)
const WSHost = "ws-api.wolfx.jp"
const OpenURLA = "https://bs.wolfx.jp/newJMAEQList/"
const OpenURLB = "https://smi.lmoniexp.bosai.go.jp/"

27
go.mod Normal file
View File

@ -0,0 +1,27 @@
module hayai
go 1.23.0
require (
github.com/faiface/beep v1.1.0
github.com/gen2brain/beeep v0.0.0-20240516210008-9c006672e7f4
github.com/gorilla/websocket v1.5.3
github.com/jftuga/geodist v1.0.0
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f
github.com/sqweek/dialog v0.0.0-20240226140203-065105509627
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf // indirect
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/hajimehoshi/oto v0.7.1 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 // indirect
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 // indirect
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6 // indirect
golang.org/x/sys v0.6.0 // indirect
)

62
go.sum Normal file
View File

@ -0,0 +1,62 @@
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf h1:FPsprx82rdrX2jiKyS17BH6IrTmUBYqZa/CXT4uvb+I=
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf/go.mod h1:peYoMncQljjNS6tZwI9WVyQB3qZS6u79/N3mBOcnd3I=
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c=
github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
github.com/gen2brain/beeep v0.0.0-20240516210008-9c006672e7f4 h1:ygs9POGDQpQGLJPlq4+0LBUmMBNox1N4JSpw+OETcvI=
github.com/gen2brain/beeep v0.0.0-20240516210008-9c006672e7f4/go.mod h1:0W7dI87PvXJ1Sjs0QPvWXKcQmNERY77e8l7GFhZB/s4=
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498=
github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4/go.mod h1:kW3HQ4UdaAyrUCSSDR4xUzBKW6O2iA4uHhk7AtyYp10=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk=
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos=
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA=
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk=
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
github.com/jftuga/geodist v1.0.0 h1:PFPQlZtj10u8ETAYTyxE0DWMl1bwA+Xzrqb4+oLkkC0=
github.com/jftuga/geodist v1.0.0/go.mod h1:BohEDxpZ8S5ADAxW/9EKPSKWOVl0+3wHENIT40m4UO4=
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f h1:dKccXx7xA56UNqOcFIbuqFjAWPVtP688j5QMgmo6OHU=
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDSfUAlBSyUjPG0JnaNGjf13JySHFeRdD/3dLP0=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mewkiz/flac v1.0.7/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd1pU=
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/sqweek/dialog v0.0.0-20240226140203-065105509627 h1:2JL2wmHXWIAxDofCK+AdkFi1KEg3dgkefCsm7isADzQ=
github.com/sqweek/dialog v0.0.0-20240226140203-065105509627/go.mod h1:/qNPSY91qTz/8TgHEMioAUc6q7+3SOybeKczHMXFcXw=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 h1:idBdZTd9UioThJp8KpM/rTSinK/ChZFBE43/WtIy8zg=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 h1:KYGJGHOQy8oSi1fDlSpcZF0+juKwk/hEMv5SiwHogR0=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6 h1:vyLBGJPIl9ZYbcQFM2USFmJBK6KI+t+z6jL0lbwjrnc=
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

11
main.go Normal file
View File

@ -0,0 +1,11 @@
package main
import (
"hayai/config"
"hayai/wolfx"
)
func main() {
config.Init()
wolfx.Listen()
}

14
seismo/seismo.go Normal file
View File

@ -0,0 +1,14 @@
package seismo
import (
"hayai/constants"
"github.com/jftuga/geodist"
)
func CalculateEquivalentMagnitude(earthquakeMagnitude float64, earthquakeLat, earthquakeLon, userLat, userLon float64) float64 {
var earthquake = geodist.Coord{Lat: earthquakeLat, Lon: earthquakeLon}
var user = geodist.Coord{Lat: userLat, Lon: userLon}
_, km, _ := geodist.VincentyDistance(earthquake, user)
return earthquakeMagnitude - km*constants.MagnitudeDecreasePerKM
}

55
utils/utils.go Normal file
View File

@ -0,0 +1,55 @@
package utils
import (
"log"
"os/exec"
"runtime"
"strings"
)
func CheckError(err error) {
if err != nil {
log.Fatal(err)
}
}
// https://stackoverflow.com/questions/39320371/how-start-web-server-to-open-page-in-browser-in-golang
// openURL opens the specified URL in the default browser of the user.
func OpenURL(url string) error {
var cmd string
var args []string
switch runtime.GOOS {
case "windows":
cmd = "cmd"
args = []string{"/c", "start"}
case "darwin":
cmd = "open"
args = []string{url}
default: // "linux", "freebsd", "openbsd", "netbsd"
// Check if running under WSL
if isWSL() {
// Use 'cmd.exe /c start' to open the URL in the default Windows browser
cmd = "cmd.exe"
args = []string{"/c", "start", url}
} else {
// Use xdg-open on native Linux environments
cmd = "xdg-open"
args = []string{url}
}
}
if len(args) > 1 {
// args[0] is used for 'start' command argument, to prevent issues with URLs starting with a quote
args = append(args[:1], append([]string{""}, args[1:]...)...)
}
return exec.Command(cmd, args...).Start()
}
// isWSL checks if the Go program is running inside Windows Subsystem for Linux
func isWSL() bool {
releaseData, err := exec.Command("uname", "-r").Output()
if err != nil {
return false
}
return strings.Contains(strings.ToLower(string(releaseData)), "microsoft")
}

BIN
wolfx/assets/alert-sat.wav Normal file

Binary file not shown.

1
wolfx/assets/alert.ceol Normal file
View File

@ -0,0 +1 @@
3,1,0,0,140,16,4,1,11,0,5,128,0,256,2,0,0,0,0,6,55,1,1,0,65,1,1,0,65,1,3,0,65,1,5,0,65,1,8,0,65,1,10,0,0,0,0,0,0,0,0,3,0,3,0,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,

BIN
wolfx/assets/alert.wav Normal file

Binary file not shown.

155
wolfx/wolfx.go Normal file
View File

@ -0,0 +1,155 @@
package wolfx
import (
"encoding/json"
"fmt"
"hayai/config"
"hayai/constants"
"hayai/seismo"
"hayai/utils"
"log"
"net/url"
"os"
"time"
"embed"
"github.com/faiface/beep/speaker"
"github.com/faiface/beep/wav"
"github.com/gen2brain/beeep"
"github.com/gorilla/websocket"
"github.com/sqweek/dialog"
)
//go:embed assets/alert-sat.wav
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 string
}
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
}
func Listen() {
// Init sound
alertSound, err := alertSoundFile.Open("assets/alert-sat.wav")
utils.CheckError(err)
defer alertSound.Close()
streamer, format, err := wav.Decode(alertSound)
utils.CheckError(err)
defer streamer.Close()
// Listen
u := url.URL{Scheme: "wss", Host: constants.WSHost, Path: "/all_eew"}
log.Printf("connecting to %s", u.String())
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
done := make(chan struct{})
defer close(done)
log.Printf("connected.")
for {
_, message, err := c.ReadMessage()
utils.CheckError(err)
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 {
alert_body := fmt.Sprintf("Epicenter: %s\nMagnitude %0.1f\nApproximately magnitude %0.1f at your location\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, 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)
speaker.Play(streamer)
for i := 0; i < 10; i++ {
time.Sleep(2 * time.Second)
streamer.Seek(0)
}
speaker.Close()
}
}
}
}
}