Mercurial > code > home > repos > gcalendarwatch
comparison calsync/gcalclient/gcalclient.go @ 52:5f7c393577e9
now gets sync updates (for 30 sec)
author | drewp@bigasterisk.com |
---|---|
date | Mon, 19 Aug 2024 19:19:13 -0700 |
parents | a9b720445bcf |
children | f248f018a663 |
comparison
equal
deleted
inserted
replaced
51:a9b720445bcf | 52:5f7c393577e9 |
---|---|
33 | 33 |
34 func MakeEventUrl3(googleCalId string, evId string) string { | 34 func MakeEventUrl3(googleCalId string, evId string) string { |
35 return MakeEventUrl("http://bigasterisk.com/calendar/"+ | 35 return MakeEventUrl("http://bigasterisk.com/calendar/"+ |
36 url.QueryEscape(googleCalId), evId) | 36 url.QueryEscape(googleCalId), evId) |
37 } | 37 } |
38 | |
38 func New(ctx context.Context) (*GCalClient, error) { | 39 func New(ctx context.Context) (*GCalClient, error) { |
39 // If modifying these scopes, delete your previously saved token.json. | |
40 err, srv := newService(ctx) | 40 err, srv := newService(ctx) |
41 if err != nil { | 41 if err != nil { |
42 log.Fatalf("Unable to retrieve Calendar client: %v", err) | 42 log.Fatalf("Unable to retrieve Calendar client: %v", err) |
43 } | 43 } |
44 return &GCalClient{ctx, srv}, nil | 44 return &GCalClient{ctx, srv}, nil |
56 } | 56 } |
57 list.Items = list.Items[:4] | 57 list.Items = list.Items[:4] |
58 return list.Items, nil | 58 return list.Items, nil |
59 } | 59 } |
60 | 60 |
61 // FindEvents considers all calendars | 61 type FindEventsMessage struct { |
62 func (gc *GCalClient) FindEvents(mc *mongoclient.MongoClient, s time.Time, maxEventsPerCalendar int64) ([]*CalendarEvent, error) { | 62 // either non-nil this: |
63 Event *CalendarEvent | |
64 // or these: | |
65 CalId string | |
66 OlderThanThisIsDeletable time.Time | |
67 } | |
68 | |
69 // FindEvents considers all calendars. It runs forever. | |
70 func (gc *GCalClient) FindEvents( | |
71 mc *mongoclient.MongoClient, | |
72 // For each calendar, after events in this time range have been sent to | |
73 // `out`, the chan will get the other kind of FindEventsMessage (CalId, | |
74 // ...). That message signals that the caller may cull old events on the given | |
75 // calendar. After that point, all events will be updates (including | |
76 // deletes). | |
77 initialFillStart, initialFillEnd time.Time, | |
78 out chan *FindEventsMessage, | |
79 ) error { | |
80 | |
63 cals, err := mc.GetAllCals() | 81 cals, err := mc.GetAllCals() |
64 if err != nil { | 82 if err != nil { |
65 return nil, err | 83 return err |
66 } | 84 } |
67 log.Println("reading", len(cals), "calendars") | 85 log.Println("reading", len(cals), "calendars") |
68 ret := make([]*CalendarEvent, 0) | 86 for calNum, cal := range cals { |
69 for _, cal := range cals { | 87 t := time.Now() |
70 calUrl := cal.Url | 88 log.Println(" cal", calNum, cal.Url) |
71 events, err := gc.srv. | 89 log.Println(" cal", calNum, "readEventsInRange", "from", initialFillStart, "to", initialFillEnd) |
72 Events.List(cal.GoogleId). | 90 syncToken, err := gc.readEventsInRange(&cal, initialFillStart, initialFillEnd, out) |
91 if err != nil { | |
92 return err | |
93 } | |
94 | |
95 out <- &FindEventsMessage{nil, cal.GoogleId, t} | |
96 | |
97 ew := gc.NewEventWatch(&cal, t, syncToken, out) | |
98 | |
99 for loop := 0; loop < 30; loop++ { | |
100 log.Println("") | |
101 log.Println("tail loop", loop, "for", cal.Url) | |
102 err := ew.GetMoreEvents() | |
103 if err != nil { | |
104 return err | |
105 } | |
106 time.Sleep(2 * time.Second) | |
107 } | |
108 } | |
109 | |
110 return nil | |
111 } | |
112 | |
113 // Synchronous. | |
114 func (gc *GCalClient) readEventsInRange( | |
115 cal *mongoclient.MongoCal, | |
116 initialFillStart, initialFillEnd time.Time, | |
117 out chan *FindEventsMessage, | |
118 ) (string, error) { | |
119 log.Println( | |
120 " get initial events for", cal.Url, "between", | |
121 initialFillStart, "and", initialFillEnd) | |
122 | |
123 pageToken := "" | |
124 syncToken := "" | |
125 | |
126 for { | |
127 log.Println(" getting another page", pageToken) | |
128 events, err := rangedEventsCall(gc.srv, cal.GoogleId, initialFillStart, initialFillEnd, pageToken).Do() | |
129 if err != nil { | |
130 return "", err | |
131 } | |
132 | |
133 log.Println(" got", len(events.Items), "events, sync=", events.NextSyncToken) | |
134 if len(events.Items) == 0 { | |
135 break | |
136 } | |
137 | |
138 sendEvents(events, cal, out) | |
139 | |
140 syncToken = events.NextSyncToken | |
141 if events.NextPageToken == "" { | |
142 break | |
143 } | |
144 pageToken = events.NextPageToken | |
145 } | |
146 return syncToken, nil | |
147 } | |
148 | |
149 // Send a page of calendar.Events over a channel, as CalendarEvent structs. | |
150 func sendEvents(events *calendar.Events, cal *mongoclient.MongoCal, out chan *FindEventsMessage) { | |
151 for _, event := range events.Items { | |
152 if event.Status == "cancelled" { | |
153 log.Fatal("todo") | |
154 } | |
155 out <- &FindEventsMessage{ | |
156 Event: &CalendarEvent{ | |
157 Event: event, | |
158 CalendarUrl: cal.Url, | |
159 EventUrl: MakeEventUrl(cal.Url, event.Id), | |
160 }} | |
161 } | |
162 } | |
163 | |
164 type eventWatch struct { | |
165 gc *GCalClient | |
166 cal *mongoclient.MongoCal | |
167 nextSyncToken string | |
168 nextPageToken string | |
169 modSince time.Time | |
170 out chan *FindEventsMessage | |
171 } | |
172 | |
173 func (gc *GCalClient) NewEventWatch( | |
174 cal *mongoclient.MongoCal, | |
175 modSince time.Time, | |
176 syncToken string, | |
177 out chan *FindEventsMessage, | |
178 ) *eventWatch { | |
179 ew := &eventWatch{gc, cal, syncToken, "", modSince, out} | |
180 return ew | |
181 } | |
182 | |
183 // Call this when there are likely new changes to sync. | |
184 func (w *eventWatch) GetMoreEvents() error { | |
185 call := syncEventsCall(w.gc.srv, w.cal.GoogleId) | |
186 log.Println("listing events on", w.cal.GoogleId, "with") | |
187 | |
188 if w.nextPageToken != "" { | |
189 call = call.PageToken(w.nextPageToken) | |
190 log.Println(" pageToken", w.nextPageToken) | |
191 } else if w.nextSyncToken != "" { | |
192 call = call.SyncToken(w.nextSyncToken) | |
193 log.Println(" syncToken", w.nextSyncToken) | |
194 } else { | |
195 call = call.UpdatedMin((w.modSince.Format(time.RFC3339))) | |
196 log.Println(" updatedMin", w.modSince.Format(time.RFC3339)) | |
197 } | |
198 ret, err := call.Do() | |
199 if err != nil { | |
200 return err | |
201 } | |
202 w.nextSyncToken = ret.NextSyncToken | |
203 w.nextPageToken = ret.NextPageToken | |
204 log.Println(len(ret.Items), "more events received") | |
205 sendEvents(ret, w.cal, w.out) | |
206 log.Println("got nextSyncToken=", w.nextSyncToken) | |
207 log.Println("got nextPageToken=", w.nextPageToken) | |
208 return err | |
209 } | |
210 | |
211 func rangedEventsCall(srv *calendar.Service, calGoogleId string, | |
212 initialFillStart, initialFillEnd time.Time, pageToken string) *calendar.EventsListCall { | |
213 return srv.Events.List(calGoogleId). | |
73 ShowDeleted(false). | 214 ShowDeleted(false). |
74 SingleEvents(true). | 215 SingleEvents(true). |
75 TimeMin(s.Format(time.RFC3339)). | 216 TimeMin(initialFillStart.Format(time.RFC3339)). |
76 MaxResults(maxEventsPerCalendar). | 217 TimeMax(initialFillEnd.Format(time.RFC3339)). |
77 OrderBy("startTime"). | 218 MaxResults(4). |
78 Do() | 219 PageToken(pageToken) |
79 if err != nil { | 220 } |
80 return nil, err | 221 |
81 } | 222 func syncEventsCall(srv *calendar.Service, calGoogleId string) *calendar.EventsListCall { |
82 log.Println(len(events.Items), "events from", calUrl) | 223 return srv.Events.List(calGoogleId). |
83 for _, event := range events.Items { | 224 ShowDeleted(true). |
84 ev := &CalendarEvent{ | 225 SingleEvents(true). |
85 Event: event, | 226 MaxResults(4) |
86 CalendarUrl: calUrl, | 227 } |
87 EventUrl: MakeEventUrl(calUrl, event.Id), | |
88 } | |
89 ret = append(ret, ev) | |
90 } | |
91 } | |
92 return ret, nil | |
93 } |