77 "os"
88 "regexp"
99 "strconv"
10- "strings"
1110 "time"
1211
1312 "github.com/xiahongze/pricetracker/email"
@@ -28,58 +27,71 @@ func init() {
2827 }
2928}
3029
30+ func processEntity (ent * models.Entity ) {
31+ if ent .K == nil {
32+ return
33+ }
34+ // save the entity before returning
35+ ctx , cancel := context .WithTimeout (context .Background (), time .Duration (CancelWaitTime ))
36+ defer func () {
37+ if err := ent .Save (ctx , EntityType , DsClient ); err != nil {
38+ log .Println ("ERROR: failed to save entity:" , err , ". Entity: " , ent )
39+ }
40+ cancel ()
41+ }()
42+
43+ var tracker trackers.Tracker
44+ switch ent .Options .UseChrome {
45+ case true :
46+ tracker = trackers .ChromeTracker
47+ default :
48+ tracker = trackers .SimpleTracker
49+ }
50+
51+ content , ok := tracker (& ent .URL , & ent .XPATH )
52+ if ! ok {
53+ log .Println ("ERROR: failed to fetch price." , content )
54+ key , _ := ent .K .MarshalJSON ()
55+ log .Printf ("URL: %s\n XPATH: %s\n Key: %s" , ent .URL , ent .XPATH , key )
56+ subject := fmt .Sprintf ("[%s] <%s> Alert: failed to fetch price for reason `%s`!" , email .Identity , ent .Name , content )
57+ ent .SendEmail (& subject )
58+ return
59+ }
60+ if ent .History == nil {
61+ log .Println ("WARN: zero price history." , ent )
62+ ent .History = []models.DataPoint {models.DataPoint {Price : content , Timestamp : time .Now ()}}
63+ return
64+ }
65+
66+ last := ent .History [len (ent .History )- 1 ]
67+ thisP , err := strconv .ParseFloat (priceRegex .FindString (content ), 32 )
68+ if err != nil {
69+ log .Println ("ERROR: failed to convert price" , err , "this price:" , content )
70+ return
71+ }
72+
73+ // update history & save entity
74+ ent .History = append (ent .History , models.DataPoint {Price : content , Timestamp : time .Now ()})
75+ ent .NextCheck = time .Now ().Add (time .Minute * time .Duration (ent .Options .CheckFreq ))
76+ if len (ent .History ) > int (ent .Options .MaxRecords ) {
77+ ent .History = ent .History [:ent .Options .MaxRecords ]
78+ }
79+ // send alert
80+ if ent .Options .AlertType == "onChange" && content != last .Price {
81+ subject := fmt .Sprintf ("[%s] <%s> Alert: price changes to %s!" , email .Identity , ent .Name , content )
82+ ent .SendEmail (& subject )
83+ } else if ent .Options .AlertType == "threshold" && ent .Options .Threshold >= float32 (thisP ) {
84+ subject := fmt .Sprintf ("[%s] <%s> Alert: price drops to %s!" , email .Identity , ent .Name , content )
85+ ent .SendEmail (& subject )
86+ }
87+ }
88+
3189// Refresh refreshes prices from datastore
3290func Refresh () {
3391 log .Println ("INFO: Refresh started" )
3492 entities := FetchData (fetchLimit )
35- var tracker trackers.Tracker
3693 for _ , ent := range entities {
37- if ent .K != nil {
38- if ent .Options .UseChrome {
39- tracker = trackers .ChromeTracker
40- } else {
41- tracker = trackers .SimpleTracker
42- }
43- if content , ok := tracker (& ent .URL , & ent .XPATH ); ok {
44- content = strings .TrimSpace (content )
45- if ent .History != nil {
46- last := ent .History [len (ent .History )- 1 ]
47- thisP , err := strconv .ParseFloat (priceRegex .FindString (content ), 32 )
48- if err != nil {
49- log .Println ("ERROR: failed to convert price" , err , "this price:" , content )
50- }
51- if ent .Options .AlertType == "onChange" && content != last .Price {
52- subject := fmt .Sprintf ("[%s] <%s> Alert: price changes to %s!" , email .Identity , ent .Name , content )
53- ent .SendEmail (& subject )
54- } else if ent .Options .AlertType == "threshold" && ent .Options .Threshold >= float32 (thisP ) {
55- subject := fmt .Sprintf ("[%s] <%s> Alert: price drops to %s!" , email .Identity , ent .Name , content )
56- ent .SendEmail (& subject )
57- }
58-
59- // update history & save entity
60- ent .History = append (ent .History , models.DataPoint {Price : content , Timestamp : time .Now ()})
61- ent .NextCheck = time .Now ().Add (time .Minute * time .Duration (ent .Options .CheckFreq ))
62- if len (ent .History ) > int (ent .Options .MaxRecords ) {
63- ent .History = ent .History [:ent .Options .MaxRecords ]
64- }
65- } else {
66- log .Println ("WARN: zero price history." , ent )
67- ent .History = []models.DataPoint {models.DataPoint {Price : content , Timestamp : time .Now ()}}
68- }
69-
70- ctx , cancel := context .WithTimeout (context .Background (), time .Duration (CancelWaitTime ))
71- defer cancel ()
72- if err := ent .Save (ctx , EntityType , DsClient ); err != nil {
73- log .Println ("ERROR: failed to save entity:" , err , ". Entity: " , ent )
74- }
75- } else {
76- log .Println ("ERROR: failed to fetch price." , content )
77- key , _ := ent .K .MarshalJSON ()
78- log .Printf ("URL: %s\n XPATH: %s\n Key: %s" , ent .URL , ent .XPATH , key )
79- subject := fmt .Sprintf ("[%s] <%s> Alert: failed to fetch price for reason `%s`!" , email .Identity , ent .Name , content )
80- ent .SendEmail (& subject )
81- }
82- }
94+ processEntity (& ent )
8395 }
8496 log .Println ("INFO: Refresh ended" )
8597}
0 commit comments