comparison calsync/gcalclient/gcalclient.go @ 54:3a12a3ac9164

refactor. run 30s forever. doesn't work on 2+ cals
author drewp@bigasterisk.com
date Tue, 20 Aug 2024 12:18:46 -0700
parents f248f018a663
children 627c815f83bb
comparison
equal deleted inserted replaced
53:f248f018a663 54:3a12a3ac9164
9 9
10 "bigasterisk.com/go/gcalendarwatch/mongoclient" 10 "bigasterisk.com/go/gcalendarwatch/mongoclient"
11 "google.golang.org/api/calendar/v3" 11 "google.golang.org/api/calendar/v3"
12 ) 12 )
13 13
14 const urlBase = "http://bigasterisk.com/calendar/"
15
14 type GCalClient struct { 16 type GCalClient struct {
15 ctx context.Context 17 ctx context.Context
16 srv *calendar.Service 18 srv *calendar.Service
17 } 19 }
18 20
22 CalendarUrl string 24 CalendarUrl string
23 EventUrl string 25 EventUrl string
24 } 26 }
25 27
26 func MakeCalUrl(calId string) string { 28 func MakeCalUrl(calId string) string {
27 return "http://bigasterisk.com/calendar/" + url.QueryEscape(calId) 29 return urlBase + url.QueryEscape(calId)
28 } 30 }
29 31
30 func MakeEventUrl(calUrl string, evId string) string { 32 func MakeEventUrl(calUrl string, evId string) string {
31 return calUrl + "/" + url.QueryEscape(evId) 33 return calUrl + "/" + url.QueryEscape(evId)
32 } 34 }
70 // calendar. After that point, all events will be updates (including 72 // calendar. After that point, all events will be updates (including
71 // deletes). 73 // deletes).
72 initialFillStart, initialFillEnd time.Time, 74 initialFillStart, initialFillEnd time.Time,
73 out chan *FindEventsMessage, 75 out chan *FindEventsMessage,
74 ) error { 76 ) error {
75
76 cals, err := mc.GetAllCals() 77 cals, err := mc.GetAllCals()
77 if err != nil { 78 if err != nil {
78 return err 79 return err
79 } 80 }
80 log.Println("reading", len(cals), "calendars") 81 log.Println("reading", len(cals), "calendars")
81 for calNum, cal := range cals { 82 for calNum, cal := range cals {
82 t := time.Now() 83 go calRoutine(calNum, cal, initialFillStart, initialFillEnd, gc, out)
83 log.Println(" cal", calNum, cal.Url) 84 }
84 log.Println(" cal", calNum, "readEventsInRange", "from", initialFillStart, "to", initialFillEnd) 85
85 syncToken, err := gc.readEventsInRange(&cal, initialFillStart, initialFillEnd, out) 86 return nil
87 }
88
89 func calRoutine(calNum int, cal mongoclient.MongoCal, initialFillStart time.Time, initialFillEnd time.Time, gc *GCalClient, out chan *FindEventsMessage) bool {
90 t := time.Now()
91 log.Println(" cal", calNum, cal.Url)
92 log.Println(" cal", calNum, "readEventsInRange", "from", initialFillStart, "to", initialFillEnd)
93 syncToken, err := gc.readEventsInRange(&cal, initialFillStart, initialFillEnd, out)
94 if err != nil {
95 log.Panicln(err)
96 return true
97 }
98
99 out <- &FindEventsMessage{nil, cal.GoogleId, t}
100
101 ew := gc.NewEventWatch(&cal, t, syncToken, out)
102
103 for loop := 0; ; loop++ {
104 log.Println("")
105 log.Println("tail loop", loop, "for", cal.Url)
106 err := ew.GetMoreEvents()
86 if err != nil { 107 if err != nil {
87 return err 108 log.Panicln(err)
88 } 109 return true
89 110 }
90 out <- &FindEventsMessage{nil, cal.GoogleId, t} 111 time.Sleep(10 * time.Minute)
91 112 }
92 ew := gc.NewEventWatch(&cal, t, syncToken, out) 113
93
94 for loop := 0; loop < 30; loop++ {
95 log.Println("")
96 log.Println("tail loop", loop, "for", cal.Url)
97 err := ew.GetMoreEvents()
98 if err != nil {
99 return err
100 }
101 time.Sleep(2 * time.Second)
102 }
103 }
104
105 return nil
106 } 114 }
107 115
108 // Synchronous. 116 // Synchronous.
109 func (gc *GCalClient) readEventsInRange( 117 func (gc *GCalClient) readEventsInRange(cal *mongoclient.MongoCal, t1, t2 time.Time, out chan *FindEventsMessage) (string, error) {
110 cal *mongoclient.MongoCal, 118 log.Println(" get initial events for", cal.Url, "between", t1, "and", t2)
111 initialFillStart, initialFillEnd time.Time,
112 out chan *FindEventsMessage,
113 ) (string, error) {
114 log.Println(
115 " get initial events for", cal.Url, "between",
116 initialFillStart, "and", initialFillEnd)
117 119
118 pageToken := "" 120 pageToken := ""
119 syncToken := "" 121 syncToken := ""
120 122 var err error
123 var done bool
121 for { 124 for {
122 log.Println(" getting another page", pageToken) 125 done, syncToken, pageToken, err = readEventsPage(gc, cal, t1, t2, pageToken, out)
123 events, err := rangedEventsCall(gc.srv, cal.GoogleId, initialFillStart, initialFillEnd, pageToken).Do()
124 if err != nil { 126 if err != nil {
125 return "", err 127 return "", err
126 } 128 }
127 129 if done {
128 log.Println(" got", len(events.Items), "events, sync=", events.NextSyncToken)
129 if len(events.Items) == 0 {
130 break 130 break
131 } 131 }
132
133 sendEvents(events, cal, out)
134
135 syncToken = events.NextSyncToken
136 if events.NextPageToken == "" {
137 break
138 }
139 pageToken = events.NextPageToken
140 } 132 }
141 return syncToken, nil 133 return syncToken, nil
134 }
135
136 func readEventsPage(gc *GCalClient, cal *mongoclient.MongoCal, t1, t2 time.Time, pageToken string, out chan *FindEventsMessage) (done bool, syncToken, nextPageToken string, err error) {
137 log.Println(" getting another page", pageToken)
138 events, err := rangedEventsCall(gc.srv, cal.GoogleId, t1, t2, pageToken).Do()
139 if err != nil {
140 return
141 }
142
143 log.Println(" got", len(events.Items), "events, sync=", events.NextSyncToken)
144 if len(events.Items) == 0 {
145 done = true
146 return
147 }
148
149 sendEvents(events, cal, out)
150
151 syncToken = events.NextSyncToken
152 if events.NextPageToken == "" {
153 done = true
154 return
155 }
156 nextPageToken = events.NextPageToken
157 syncToken = events.NextSyncToken
158 return
142 } 159 }
143 160
144 // Send a page of calendar.Events over a channel, as CalendarEvent structs. 161 // Send a page of calendar.Events over a channel, as CalendarEvent structs.
145 func sendEvents(events *calendar.Events, cal *mongoclient.MongoCal, out chan *FindEventsMessage) { 162 func sendEvents(events *calendar.Events, cal *mongoclient.MongoCal, out chan *FindEventsMessage) {
146 for _, event := range events.Items { 163 for _, event := range events.Items {
176 } 193 }
177 194
178 // Call this when there are likely new changes to sync. 195 // Call this when there are likely new changes to sync.
179 func (w *eventWatch) GetMoreEvents() error { 196 func (w *eventWatch) GetMoreEvents() error {
180 call := syncEventsCall(w.gc.srv, w.cal.GoogleId) 197 call := syncEventsCall(w.gc.srv, w.cal.GoogleId)
198
181 log.Println("listing events on", w.cal.GoogleId, "with") 199 log.Println("listing events on", w.cal.GoogleId, "with")
182
183 if w.nextPageToken != "" { 200 if w.nextPageToken != "" {
184 call = call.PageToken(w.nextPageToken) 201 call = call.PageToken(w.nextPageToken)
185 log.Println(" pageToken", w.nextPageToken) 202 log.Println(" pageToken", w.nextPageToken)
186 } else if w.nextSyncToken != "" { 203 } else if w.nextSyncToken != "" {
187 call = call.SyncToken(w.nextSyncToken) 204 call = call.SyncToken(w.nextSyncToken)
188 log.Println(" syncToken", w.nextSyncToken) 205 log.Println(" syncToken", w.nextSyncToken)
189 } else { 206 } else {
190 call = call.UpdatedMin((w.modSince.Format(time.RFC3339))) 207 call = call.UpdatedMin((w.modSince.Format(time.RFC3339)))
191 log.Println(" updatedMin", w.modSince.Format(time.RFC3339)) 208 log.Println(" updatedMin", w.modSince.Format(time.RFC3339))
192 } 209 }
193 ret, err := call.Do() 210 events, err := call.Do()
194 if err != nil { 211 if err != nil {
195 return err 212 return err
196 } 213 }
197 w.nextSyncToken = ret.NextSyncToken 214 w.nextSyncToken = events.NextSyncToken
198 w.nextPageToken = ret.NextPageToken 215 w.nextPageToken = events.NextPageToken
199 log.Println(len(ret.Items), "more events received") 216 log.Println(len(events.Items), "more events received")
200 sendEvents(ret, w.cal, w.out) 217 sendEvents(events, w.cal, w.out)
201 log.Println("got nextSyncToken=", w.nextSyncToken) 218 log.Println("got nextSyncToken=", w.nextSyncToken, " nextPageToken=", w.nextPageToken)
202 log.Println("got nextPageToken=", w.nextPageToken)
203 return err 219 return err
204 } 220 }