12
|
1 package main
|
|
2
|
|
3 import (
|
14
|
4 "bytes"
|
12
|
5 "fmt"
|
|
6 "flag"
|
|
7 "io/ioutil"
|
|
8 "log"
|
|
9 "math"
|
|
10 "net/http"
|
|
11 "net/smtp"
|
|
12 "os"
|
|
13 "strconv"
|
|
14 "strings"
|
|
15 "time"
|
|
16
|
|
17 "golang.org/x/net/html"
|
|
18 )
|
|
19
|
14
|
20 var ver = "0.2.0"
|
12
|
21
|
|
22 func main() {
|
|
23
|
61
|
24 version := flag.Bool("v", false, "print version")
|
|
25 verbose := flag.Bool("V", false, "verbose")
|
|
26 file := flag.String("f", "usd.dat", "data file")
|
12
|
27 flag.Parse()
|
|
28
|
61
|
29 if (*version) {
|
|
30 fmt.Fprintf(os.Stderr, "getexr - Get Exchange Rate [ version = %s ]\n", ver)
|
|
31 os.Exit(0)
|
12
|
32 }
|
|
33
|
14
|
34 t := time.Now()
|
61
|
35 now := t.Format("2006-01-02 15:04:05")
|
14
|
36
|
12
|
37 // Get USD Rate
|
61
|
38 PrintVerbose(*verbose, "> get rate from yahoo...")
|
12
|
39 url := "http://finance.yahoo.co.jp/"
|
61
|
40 resp, err := http.Get(url)
|
12
|
41 if err != nil {
|
61
|
42 log.Fatal(err)
|
12
|
43 }
|
61
|
44 PrintVerbose(*verbose, "success\n")
|
12
|
45
|
61
|
46 z := html.NewTokenizer(resp.Body)
|
|
47 usd, err := ParseHtml(z)
|
12
|
48 if err != nil {
|
61
|
49 log.Fatal(err)
|
12
|
50 }
|
|
51 defer resp.Body.Close()
|
61
|
52 PrintVerbose(*verbose, fmt.Sprintf("> rate = %.2f\n", usd))
|
12
|
53
|
61
|
54 content, err := ioutil.ReadFile(*file)
|
12
|
55 if err != nil {
|
61
|
56 log.Fatal(err)
|
12
|
57 }
|
14
|
58 fc := 0
|
12
|
59
|
61
|
60 buf1 := strings.Split(string(content), "\n")
|
14
|
61
|
|
62 // Compare Alert Rate
|
61
|
63 buf2 := strings.Split(buf1[ 0 ], ",")
|
14
|
64 flg := buf2[0]
|
61
|
65 thr, _ := strconv.ParseFloat(buf2[1], 32)
|
14
|
66
|
61
|
67 if (strings.EqualFold("H", flg) && thr < usd) {
|
14
|
68 fc = -1
|
61
|
69 content = bytes.Replace(content, []byte("H"), []byte("-"), 1)
|
|
70 if err := AlertMail("H", now, usd); err != nil {
|
|
71 log.Fatal(err)
|
14
|
72 }
|
61
|
73 PrintVerbose(*verbose, "> rate higher.\n> sending alert mail.\n")
|
14
|
74
|
61
|
75 } else if (strings.EqualFold("L", flg) && thr > usd) {
|
14
|
76 fc = -1
|
61
|
77 content = bytes.Replace(content, []byte("L"), []byte("-"), 1)
|
|
78 if err := AlertMail("L", now, usd); err != nil {
|
|
79 log.Fatal(err)
|
14
|
80 }
|
61
|
81 PrintVerbose(*verbose, "> rate lower.\n> sending alert mail.\n")
|
14
|
82 }
|
|
83
|
|
84 // Compare Past Rate
|
61
|
85 buf2 = strings.Split(buf1[ len(buf1) - 2 ], ",")
|
14
|
86 ymd0 := buf2[0]
|
61
|
87 usd0, _ := strconv.ParseFloat(buf2[1], 32)
|
12
|
88
|
61
|
89 if (math.Abs(usd0 - usd) > 1.0) {
|
14
|
90 fc = 1
|
|
91 // Post E-mail
|
61
|
92 PrintVerbose(*verbose, "> sending notify mail.\n")
|
|
93 if err := NotifyMail(now, usd, ymd0, usd0); err != nil {
|
|
94 log.Fatal(err)
|
12
|
95 }
|
61
|
96 PrintVerbose(*verbose, "> rate changed.\n")
|
14
|
97 } else {
|
61
|
98 PrintVerbose(*verbose, "> not changed.\n")
|
14
|
99 }
|
12
|
100
|
14
|
101 // Save Rate
|
61
|
102 if (fc != 0) {
|
|
103 if (fc == 1) {
|
|
104 buf := fmt.Sprintf("%s,%.2f\n", now, usd)
|
|
105 content = append(content, buf...)
|
14
|
106 }
|
61
|
107 if err := ioutil.WriteFile(*file, content, 0777); err != nil {
|
|
108 log.Fatal(err)
|
12
|
109 }
|
61
|
110 PrintVerbose(*verbose, "> data file overwrited.\n")
|
12
|
111 }
|
13
|
112
|
61
|
113 PrintVerbose(*verbose, "> finish.\n")
|
12
|
114 }
|
|
115
|
61
|
116 func ParseHtml(z *html.Tokenizer) (float64, error) {
|
12
|
117 for {
|
|
118 tt := z.Next()
|
|
119 switch tt {
|
|
120 case html.ErrorToken:
|
|
121 return 0.0, nil
|
|
122
|
|
123 case html.StartTagToken:
|
|
124 tag, _ := z.TagName()
|
|
125 key, val, _ := z.TagAttr()
|
61
|
126 if string(tag) == "strong" && string(key) == "class" && string(val) == "bkLine" {
|
12
|
127 z.Next()
|
61
|
128 //fmt.Printf("%s %s %s\n", key, val, z.Token())
|
|
129 return strconv.ParseFloat(z.Token().String(), 32)
|
12
|
130 }
|
|
131 }
|
|
132 }
|
|
133 }
|
|
134
|
61
|
135 func NotifyMail(now string, usd float64, old string, usd0 float64) error {
|
13
|
136 address := "muty@willcom.com"
|
14
|
137 msg := "To: " + address + "\r\n" +
|
|
138 "Subject: Exchange-Mail\r\n" +
|
|
139 "\r\n" +
|
|
140 "rate changed\r\n" +
|
|
141 now + "\r\n" +
|
61
|
142 fmt.Sprintf("[ USD/JPY : %.2f ].", usd) + "\r\n\r\n" +
|
14
|
143 old + "\r\n" +
|
61
|
144 fmt.Sprintf("[ USD/JPY : %.2f ].", usd0) + "\r\n" // mail body
|
|
145 if err := SendMail(address, msg); err != nil {
|
14
|
146 return err
|
|
147 }
|
|
148 return nil
|
|
149 }
|
|
150
|
61
|
151 func AlertMail(flg, now string, usd float64) error {
|
14
|
152 address := "muty@willcom.com"
|
|
153 msg := "To: " + address + "\r\n" +
|
|
154 "Subject: Exchange-Mail\r\n" +
|
|
155 "\r\n" +
|
|
156 "rate changed\r\n" +
|
|
157 now + "\r\n" +
|
61
|
158 fmt.Sprintf("[ USD/JPY : %.2f ].", usd) + "\r\n" // mail body
|
|
159 if err := SendMail(address, msg); err != nil {
|
14
|
160 return err
|
|
161 }
|
|
162 return nil
|
|
163 }
|
|
164
|
61
|
165 func SendMail(address, msg string) error {
|
12
|
166 hostname := "sdm.sakura.ne.jp"
|
61
|
167 auth := smtp.PlainAuth("", "bad_user@sdm.sakura.ne.jp", "hogehoge3", hostname)
|
13
|
168 to := []string{ address }
|
61
|
169 err := smtp.SendMail(hostname + ":587", auth, "bad_user@sdm.sakura.ne.jp", to, []byte(msg))
|
12
|
170 if err != nil {
|
|
171 return err
|
|
172 }
|
|
173 return nil
|
|
174 }
|
|
175
|
61
|
176 func PrintVerbose(y bool, msg string) {
|
13
|
177 if y {
|
61
|
178 fmt.Fprintf(os.Stderr, msg)
|
13
|
179 }
|
|
180 }
|
|
181
|