Mercurial > code > home > repos > gcalendarwatch
annotate 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 |
rev | line source |
---|---|
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
1 package gcalclient |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
2 |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
3 import ( |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
4 "context" |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
5 "log" |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
6 "net/url" |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
7 "strings" |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
8 "time" |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
9 |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
10 "bigasterisk.com/go/gcalendarwatch/mongoclient" |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
11 "google.golang.org/api/calendar/v3" |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
12 ) |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
13 |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
14 type GCalClient struct { |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
15 ctx context.Context |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
16 srv *calendar.Service |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
17 } |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
18 |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
19 // Same as calendar.Event, but includes our urls |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
20 type CalendarEvent struct { |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
21 *calendar.Event |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
22 CalendarUrl string |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
23 EventUrl string |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
24 } |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
25 |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
26 func MakeCalUrl(calId string) string { |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
27 return "http://bigasterisk.com/calendar/" + url.QueryEscape(calId) |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
28 } |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
29 |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
30 func MakeEventUrl(calUrl string, evId string) string { |
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
31 return calUrl + "/" + url.QueryEscape(evId) |
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
32 } |
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
33 |
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
34 func MakeEventUrl3(googleCalId string, evId string) string { |
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
35 return MakeEventUrl("http://bigasterisk.com/calendar/"+ |
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
36 url.QueryEscape(googleCalId), evId) |
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
37 } |
52 | 38 |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
39 func New(ctx context.Context) (*GCalClient, error) { |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
40 err, srv := newService(ctx) |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
41 if err != nil { |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
42 log.Fatalf("Unable to retrieve Calendar client: %v", err) |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
43 } |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
44 return &GCalClient{ctx, srv}, nil |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
45 } |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
46 |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
47 func (gc *GCalClient) Close() { |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
48 // todo: disconnect watches if possible |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
49 } |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
50 |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
51 func (gc *GCalClient) AllCalendars(maxResults int64) ([]*calendar.CalendarListEntry, error) { |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
52 // todo: pagination |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
53 list, err := gc.srv.CalendarList.List().MaxResults(maxResults).Do() |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
54 if err != nil { |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
55 return nil, err |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
56 } |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
57 list.Items = list.Items[:4] |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
58 return list.Items, nil |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
59 } |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
60 |
52 | 61 type FindEventsMessage struct { |
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 | |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
81 cals, err := mc.GetAllCals() |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
82 if err != nil { |
52 | 83 return err |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
84 } |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
85 log.Println("reading", len(cals), "calendars") |
52 | 86 for calNum, cal := range cals { |
87 t := time.Now() | |
88 log.Println(" cal", calNum, cal.Url) | |
89 log.Println(" cal", calNum, "readEventsInRange", "from", initialFillStart, "to", initialFillEnd) | |
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() | |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
103 if err != nil { |
52 | 104 return err |
51
a9b720445bcf
now roughly syncs cals and events to mongodb, one time
drewp@bigasterisk.com
parents:
49
diff
changeset
|
105 } |
52 | 106 time.Sleep(2 * time.Second) |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
107 } |
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
108 } |
52 | 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 } | |
49
2991c1166852
start calsync in go. Calendar list seems to sync
drewp@bigasterisk.com
parents:
diff
changeset
|
162 } |
52 | 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). | |
214 ShowDeleted(false). | |
215 SingleEvents(true). | |
216 TimeMin(initialFillStart.Format(time.RFC3339)). | |
217 TimeMax(initialFillEnd.Format(time.RFC3339)). | |
218 MaxResults(4). | |
219 PageToken(pageToken) | |
220 } | |
221 | |
222 func syncEventsCall(srv *calendar.Service, calGoogleId string) *calendar.EventsListCall { | |
223 return srv.Events.List(calGoogleId). | |
224 ShowDeleted(true). | |
225 SingleEvents(true). | |
226 MaxResults(4) | |
227 } |