Skip to content

Commit

Permalink
Refactor code to improve readability and maintainability
Browse files Browse the repository at this point in the history
  • Loading branch information
a3510377 committed Sep 30, 2024
1 parent 36a4d91 commit 593c6cc
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 32 deletions.
36 changes: 25 additions & 11 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ const (
)

var (
noClose = []string{"尚未列入警戒區。", "今天照常上班、照常上課。", "明天照常上班、照常上課。"}
timeMatch = regexp.MustCompile(`\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}`)
noClose = []string{"尚未列入警戒區", "今天照常上班、照常上課", "明天照常上班、照常上課"}
noClassMap = map[string]void{}
timeMatch = regexp.MustCompile(`\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}`)
countyCityPrefixRegex = regexp.MustCompile("^.{2}[縣市]")
)

// const WorkSchoolCloseURL = "https://alerts.ncdr.nat.gov.tw/RssAtomFeed.ashx?AlertType=33"
Expand All @@ -40,8 +42,14 @@ type WorkSchoolCloseMap struct {
Data map[string]WorkSchoolCloseData
}
type WorkSchoolCloseData struct {
County string
State string
County string
Details []string
}

func init() {
for _, v := range noClose {
noClassMap[v] = void{}
}
}

func GetClosedSchool() (*WorkSchoolCloseMap, error) {
Expand All @@ -68,16 +76,22 @@ func GetClosedSchool() (*WorkSchoolCloseMap, error) {

county, state := strings.TrimSpace(values[0]), strings.TrimSpace(values[1])

for _, v := range noClose {
if state == v {
details := []string{}
for _, v := range regexp.MustCompile("。|\n").Split(state, -1) {
v = strings.TrimSpace(v)
if v == "" {
continue
}
if _, ok := noClassMap[v]; ok {
return
}
state = strings.TrimLeft(state, v)

details = append(details, countyCityPrefixRegex.ReplaceAllString(v, ""))
}

result.Data[county] = WorkSchoolCloseData{
County: county,
State: strings.ReplaceAll(strings.TrimSpace(state), " ", "\n"),
County: county,
Details: details,
}
})

Expand All @@ -99,7 +113,7 @@ func NotifyLine(values WorkSchoolClose) {

text := "\n"
for _, v := range values.Data {
text += fmt.Sprintf("%s: %s\n", v.County, strings.ReplaceAll(v.State, "\n", "\n "))
text += fmt.Sprintf("%s: \n %s\n", v.County, strings.Join(v.Details, "\n "))
}
data := url.Values{"message": {text}}.Encode()
req, _ := http.NewRequest("POST", LineMessageAPIUrl, strings.NewReader(data))
Expand Down Expand Up @@ -134,7 +148,7 @@ func NotifyDiscord(values WorkSchoolClose) {
for _, v := range values.Data {
fields = append(fields, map[string]any{
"name": v.County,
"value": v.State,
"value": strings.Join(v.Details, "\n"),
"inline": true,
})
}
Expand Down
14 changes: 8 additions & 6 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ func init() {
}
config := NewConfig()
data, _ := yaml.Marshal(config)
os.MkdirAll(path.Dir(ConfigFilePath), 0o644)
os.WriteFile(ConfigFilePath, data, 0o644)
os.MkdirAll(path.Dir(ConfigFilePath), 0777)
os.WriteFile(ConfigFilePath, data, 0777)
} else {
yaml.Unmarshal(yamlFile, &ConfigData)
}
Expand All @@ -89,12 +89,14 @@ func init() {
err := watchFile(ConfigFilePath)
if err != nil {
log.Println("config watch error", err)
time.Sleep(time.Second * 5)
}

// reload config
yamlFile, err := os.ReadFile(ConfigFilePath)
if err != nil {
log.Println("config watch error", err)
time.Sleep(time.Second * 5)
} else {
yaml.Unmarshal(yamlFile, &ConfigData)
}
Expand Down Expand Up @@ -133,19 +135,19 @@ func watchFile(filePath string) error {
return nil
}

func GetTmpDate() (value map[string]string) {
func GetTmpDate() (value map[string]map[string]bool) {
if data, err := os.ReadFile(TmpFilePath); err == nil {
json.Unmarshal(data, &value)
return
}
return map[string]string{} // if file not exist
return map[string]map[string]bool{} // if file not exist
}

func WriteTmpDate(v any) (err error) {
bytes, err := json.Marshal(v)
if err == nil {
os.MkdirAll(path.Dir(ConfigFilePath), 0o644)
os.WriteFile(TmpFilePath, bytes, 0o644)
os.MkdirAll(path.Dir(ConfigFilePath), 0777)
os.WriteFile(TmpFilePath, bytes, 0777)
}
return
}
59 changes: 44 additions & 15 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,43 @@ package main

import (
"log"
"strings"
"time"

"github.com/robfig/cron/v3"
)

func main() {
main := func() {
const specTime = "*/15 * * * *"
// everyMinute, _ := cron.ParseStandard("* * * * *")

c := cron.New(cron.WithLogger(cron.VerbosePrintfLogger(log.Default())))

loop, _ := c.AddFunc(specTime, func() {
retryCount := 0
for ; retryCount < 3; retryCount++ {
log.Println("Check and notification")
if err := checkAndNotification(); err != nil {
log.Println("checkAndNotification error", err)
time.Sleep(time.Second * 5) // retry after 5 seconds
continue
}

log.Println(strings.Repeat("-", 70))
break
}
if retryCount >= 3 {
log.Println("Retry 3 times, skip check")
}
}
})
entry := c.Entry(loop)

const specTime = "*/15 * * * *"
go entry.Job.Run() // first run

c := cron.New(cron.WithLogger(cron.VerbosePrintfLogger(log.Default())))
// oldSchedule := entry.Schedule
// entry.Schedule = everyMinute
// entry.Next = time.Now().In(c.Location())

c.AddFunc(specTime, main)

main() // first run
c.Run() // loop start
}

Expand All @@ -46,22 +56,41 @@ func checkAndNotification() error {
}

tmpData := GetTmpDate()
for k, v := range data.Data {
log.Println("---------------")
log.Println(k, v)
if !areaNamesMap[k] || tmpData[k] == v.State {
log.Println("skip")
for county, v := range data.Data {
if !areaNamesMap[county] {
continue
}
notifications = append(notifications, v)
tmpData[k] = v.State

countyTmpData, countyExists := tmpData[county]
if !countyExists {
tmpData[county] = map[string]bool{}
}

for _, detail := range v.Details {
absoluteDetail := ConvertRelativeToAbsoluteTime(detail, *data.Date)
if _, ok := countyTmpData[absoluteDetail]; ok {
continue
}

notifications = append(notifications, v)
tmpData[county][absoluteDetail] = true
}
}
log.Println("---------------")

if len(notifications) > 0 {
notification(WorkSchoolClose{Date: data.Date, Data: notifications})
}

// clear timeout data
nowTime := time.Now()
for _, data := range tmpData {
for k := range data {
if HasStatusIsOld(k, nowTime) {
delete(data, k)
}
}
}

WriteTmpDate(tmpData)
return nil
}
Expand Down
41 changes: 41 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import (
"regexp"
"strings"
"time"
)

type void struct{}

var dateRegexp = regexp.MustCompile(`\d{4}-\d{2}-\d{2}`)

func ConvertRelativeToAbsoluteTime(relativeTime string, date time.Time) string {
nowDate := date.Format("2006-01-02")
nextDate := date.AddDate(0, 0, 1).Format("2006-01-02")
dayAfterNextDate := date.AddDate(0, 0, 2).Format("2006-01-02")

replacer := strings.NewReplacer(
"今天", nowDate,
"明天", nextDate,
"後天", dayAfterNextDate,
)

return replacer.Replace(relativeTime)
}

func HasStatusIsOld(status string, referenceDate time.Time) bool {
referenceDate = referenceDate.Truncate(24 * time.Hour)

for _, match := range dateRegexp.FindAllString(status, -1) {
parsedDate, err := time.Parse("2006-01-02", match)
if err != nil {
continue
}
if !parsedDate.Before(referenceDate) {
return false
}
}

return true
}

0 comments on commit 593c6cc

Please sign in to comment.