Merge lp:~mardy/account-polld/no-account-watching into lp:~ubuntu-push-hackers/account-polld/trunk
- no-account-watching
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Jonas G. Drange |
Approved revision: | 177 |
Merged at revision: | 174 |
Proposed branch: | lp:~mardy/account-polld/no-account-watching |
Merge into: | lp:~ubuntu-push-hackers/account-polld/trunk |
Diff against target: |
513 lines (+94/-150) 7 files modified
accounts/account-watcher.c (+53/-93) accounts/account-watcher.h (+5/-3) accounts/accounts.c (+2/-2) accounts/accounts.go (+12/-8) cmd/account-polld/account_service.go (+11/-13) cmd/account-polld/main.go (+10/-28) cmd/account-watcher-test/main.go (+1/-3) |
To merge this branch: | bzr merge lp:~mardy/account-polld/no-account-watching |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jonas G. Drange (community) | Approve | ||
system-apps-ci-bot | continuous-integration | Approve | |
Review via email: mp+300847@code.launchpad.net |
Commit message
Don't watch accounts for changes: retrieve a new list at every poll
Watching for account changes makes the code more complicated than needed: we can simply query the list of enabled accounts at every Poll cycle, and check the differences with the previous list. This avoids the need to setup account watches and, more importantly, requires only once instance of AgAccountManager (compared to one instance for each service type).
Also, simplify the configuration of supported services: drop the usage of the "service type" concept, and rely on the service IDs only; this makes account-polld much easier to extend.
Description of the change
Don't watch accounts for changes: retrieve a new list at every poll
Watching for account changes makes the code more complicated than needed: we can simply query the list of enabled accounts at every Poll cycle, and check the differences with the previous list. This avoids the need to setup account watches and, more importantly, requires only once instance of AgAccountManager (compared to one instance for each service type).
Also, simplify the configuration of supported services: drop the usage of the "service type" concept, and rely on the service IDs only; this makes account-polld much easier to extend.
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
Jonas G. Drange (jonas-drange) wrote : | # |
Wonderful, thanks. Will you let me know when there's a silo for this, I'd like to see how it works.
Preview Diff
1 | === modified file 'accounts/account-watcher.c' | |||
2 | --- accounts/account-watcher.c 2016-04-19 19:58:25 +0000 | |||
3 | +++ accounts/account-watcher.c 2016-07-22 08:01:34 +0000 | |||
4 | @@ -31,13 +31,10 @@ | |||
5 | 31 | struct _AccountWatcher { | 31 | struct _AccountWatcher { |
6 | 32 | AgManager *manager; | 32 | AgManager *manager; |
7 | 33 | /* A hash table of the enabled accounts we know of. | 33 | /* A hash table of the enabled accounts we know of. |
9 | 34 | * Keys are account ID integers, and AccountInfo structs as values. | 34 | * Keys are "<accountId>/<serviceName>", and AccountInfo structs as values. |
10 | 35 | */ | 35 | */ |
11 | 36 | GHashTable *services; | 36 | GHashTable *services; |
12 | 37 | 37 | ||
13 | 38 | gulong enabled_event_signal_id; | ||
14 | 39 | gulong account_deleted_signal_id; | ||
15 | 40 | |||
16 | 41 | AccountEnabledCallback callback; | 38 | AccountEnabledCallback callback; |
17 | 42 | void *user_data; | 39 | void *user_data; |
18 | 43 | }; | 40 | }; |
19 | @@ -51,9 +48,7 @@ | |||
20 | 51 | GVariant *auth_params; | 48 | GVariant *auth_params; |
21 | 52 | GVariant *session_data; | 49 | GVariant *session_data; |
22 | 53 | 50 | ||
23 | 54 | gulong enabled_signal_id; | ||
24 | 55 | AgAccountId account_id; | 51 | AgAccountId account_id; |
25 | 56 | gboolean enabled; /* the last known state of the account */ | ||
26 | 57 | }; | 52 | }; |
27 | 58 | 53 | ||
28 | 59 | static void account_info_clear_login(AccountInfo *info) { | 54 | static void account_info_clear_login(AccountInfo *info) { |
29 | @@ -74,11 +69,6 @@ | |||
30 | 74 | 69 | ||
31 | 75 | static void account_info_free(AccountInfo *info) { | 70 | static void account_info_free(AccountInfo *info) { |
32 | 76 | account_info_clear_login(info); | 71 | account_info_clear_login(info); |
33 | 77 | if (info->enabled_signal_id != 0) { | ||
34 | 78 | g_signal_handler_disconnect( | ||
35 | 79 | info->account_service, info->enabled_signal_id); | ||
36 | 80 | } | ||
37 | 81 | info->enabled_signal_id = 0; | ||
38 | 82 | if (info->account_service) { | 72 | if (info->account_service) { |
39 | 83 | g_object_unref(info->account_service); | 73 | g_object_unref(info->account_service); |
40 | 84 | info->account_service = NULL; | 74 | info->account_service = NULL; |
41 | @@ -116,7 +106,7 @@ | |||
42 | 116 | service_type, | 106 | service_type, |
43 | 117 | service_name, | 107 | service_name, |
44 | 118 | error, | 108 | error, |
46 | 119 | info->enabled, | 109 | TRUE, |
47 | 120 | client_id, | 110 | client_id, |
48 | 121 | client_secret, | 111 | client_secret, |
49 | 122 | access_token, | 112 | access_token, |
50 | @@ -178,24 +168,6 @@ | |||
51 | 178 | ag_auth_data_unref(auth_data); | 168 | ag_auth_data_unref(auth_data); |
52 | 179 | } | 169 | } |
53 | 180 | 170 | ||
54 | 181 | static void account_info_enabled_cb( | ||
55 | 182 | AgAccountService *account_service, gboolean enabled, AccountInfo *info) { | ||
56 | 183 | trace("account_info_enabled_cb for %u, enabled=%d\n", info->account_id, enabled); | ||
57 | 184 | if (info->enabled == enabled) { | ||
58 | 185 | /* no change */ | ||
59 | 186 | return; | ||
60 | 187 | } | ||
61 | 188 | info->enabled = enabled; | ||
62 | 189 | |||
63 | 190 | if (enabled) { | ||
64 | 191 | account_info_login(info); | ||
65 | 192 | } else { | ||
66 | 193 | account_info_clear_login(info); | ||
67 | 194 | // Send notification that account has been disabled */ | ||
68 | 195 | account_info_notify(info, NULL); | ||
69 | 196 | } | ||
70 | 197 | } | ||
71 | 198 | |||
72 | 199 | static AccountInfo *account_info_new(AccountWatcher *watcher, AgAccountService *account_service) { | 171 | static AccountInfo *account_info_new(AccountWatcher *watcher, AgAccountService *account_service) { |
73 | 200 | AccountInfo *info = g_new0(AccountInfo, 1); | 172 | AccountInfo *info = g_new0(AccountInfo, 1); |
74 | 201 | info->watcher = watcher; | 173 | info->watcher = watcher; |
75 | @@ -204,99 +176,85 @@ | |||
76 | 204 | AgAccount *account = ag_account_service_get_account(account_service); | 176 | AgAccount *account = ag_account_service_get_account(account_service); |
77 | 205 | g_object_get(account, "id", &info->account_id, NULL); | 177 | g_object_get(account, "id", &info->account_id, NULL); |
78 | 206 | 178 | ||
79 | 207 | info->enabled_signal_id = g_signal_connect( | ||
80 | 208 | account_service, "enabled", | ||
81 | 209 | G_CALLBACK(account_info_enabled_cb), info); | ||
82 | 210 | // Set initial state | ||
83 | 211 | account_info_enabled_cb(account_service, ag_account_service_get_enabled(account_service), info); | ||
84 | 212 | |||
85 | 213 | return info; | 179 | return info; |
86 | 214 | } | 180 | } |
87 | 215 | 181 | ||
88 | 216 | static void account_watcher_enabled_event_cb( | ||
89 | 217 | AgManager *manager, AgAccountId account_id, AccountWatcher *watcher) { | ||
90 | 218 | trace("enabled-event for %u\n", account_id); | ||
91 | 219 | if (g_hash_table_contains(watcher->services, GUINT_TO_POINTER(account_id))) { | ||
92 | 220 | /* We are already tracking this account */ | ||
93 | 221 | return; | ||
94 | 222 | } | ||
95 | 223 | AgAccount *account = ag_manager_get_account(manager, account_id); | ||
96 | 224 | if (account == NULL) { | ||
97 | 225 | /* There was a problem looking up the account */ | ||
98 | 226 | return; | ||
99 | 227 | } | ||
100 | 228 | /* Since our AgManager is restricted to a particular service type, | ||
101 | 229 | * pick the first service for the account. */ | ||
102 | 230 | GList *services = ag_account_list_services(account); | ||
103 | 231 | if (services != NULL) { | ||
104 | 232 | AgService *service = services->data; | ||
105 | 233 | AgAccountService *account_service = ag_account_service_new( | ||
106 | 234 | account, service); | ||
107 | 235 | AccountInfo *info = account_info_new(watcher, account_service); | ||
108 | 236 | g_object_unref(account_service); | ||
109 | 237 | g_hash_table_insert(watcher->services, GUINT_TO_POINTER(account_id), info); | ||
110 | 238 | } | ||
111 | 239 | ag_service_list_free(services); | ||
112 | 240 | g_object_unref(account); | ||
113 | 241 | } | ||
114 | 242 | |||
115 | 243 | static void account_watcher_account_deleted_cb( | ||
116 | 244 | AgManager *manager, AgAccountId account_id, AccountWatcher *watcher) { | ||
117 | 245 | trace("account-deleted for %u\n", account_id); | ||
118 | 246 | /* A disabled event should have been sent prior to this, so no | ||
119 | 247 | * need to send any notification. */ | ||
120 | 248 | g_hash_table_remove(watcher->services, GUINT_TO_POINTER(account_id)); | ||
121 | 249 | } | ||
122 | 250 | |||
123 | 251 | static gboolean account_watcher_setup(void *user_data) { | 182 | static gboolean account_watcher_setup(void *user_data) { |
124 | 252 | AccountWatcher *watcher = (AccountWatcher *)user_data; | 183 | AccountWatcher *watcher = (AccountWatcher *)user_data; |
125 | 253 | 184 | ||
126 | 254 | /* Track changes to accounts */ | ||
127 | 255 | watcher->enabled_event_signal_id = g_signal_connect( | ||
128 | 256 | watcher->manager, "enabled-event", | ||
129 | 257 | G_CALLBACK(account_watcher_enabled_event_cb), watcher); | ||
130 | 258 | watcher->account_deleted_signal_id = g_signal_connect( | ||
131 | 259 | watcher->manager, "account-deleted", | ||
132 | 260 | G_CALLBACK(account_watcher_account_deleted_cb), watcher); | ||
133 | 261 | |||
134 | 262 | /* Now check initial state */ | 185 | /* Now check initial state */ |
136 | 263 | GList *enabled_accounts = ag_manager_list(watcher->manager); | 186 | GList *enabled_accounts = |
137 | 187 | ag_manager_get_enabled_account_services(watcher->manager); | ||
138 | 188 | GList *old_services = g_hash_table_get_keys(watcher->services); | ||
139 | 189 | |||
140 | 190 | /* Update the services table */ | ||
141 | 264 | GList *l; | 191 | GList *l; |
142 | 265 | for (l = enabled_accounts; l != NULL; l = l->next) { | 192 | for (l = enabled_accounts; l != NULL; l = l->next) { |
147 | 266 | AgAccountId account_id = GPOINTER_TO_UINT(l->data); | 193 | AgAccountService *account_service = l->data; |
148 | 267 | account_watcher_enabled_event_cb(watcher->manager, account_id, watcher); | 194 | AgAccountId id = ag_account_service_get_account(account_service)->id; |
149 | 268 | } | 195 | AgService *service = ag_account_service_get_service(account_service); |
150 | 269 | ag_manager_list_free(enabled_accounts); | 196 | char *key = g_strdup_printf("%d/%s", id, ag_service_get_name(service)); |
151 | 197 | |||
152 | 198 | AccountInfo *info = g_hash_table_lookup(watcher->services, key); | ||
153 | 199 | if (info) { | ||
154 | 200 | GList *node = g_list_find_custom(old_services, key, | ||
155 | 201 | (GCompareFunc)g_strcmp0); | ||
156 | 202 | old_services = g_list_remove_link(old_services, node); | ||
157 | 203 | g_free(key); | ||
158 | 204 | } else { | ||
159 | 205 | trace("adding account %s\n", key); | ||
160 | 206 | info = account_info_new(watcher, account_service); | ||
161 | 207 | g_hash_table_insert(watcher->services, key, info); | ||
162 | 208 | } | ||
163 | 209 | account_info_login(info); | ||
164 | 210 | } | ||
165 | 211 | g_list_free_full(enabled_accounts, g_object_unref); | ||
166 | 212 | |||
167 | 213 | /* Remove from the table the accounts which are no longer enabled */ | ||
168 | 214 | for (l = old_services; l != NULL; l = l->next) { | ||
169 | 215 | char *key = l->data; | ||
170 | 216 | trace("removing account %s\n", key); | ||
171 | 217 | g_hash_table_remove(watcher->services, key); | ||
172 | 218 | } | ||
173 | 219 | g_list_free(old_services); | ||
174 | 270 | 220 | ||
175 | 271 | return G_SOURCE_REMOVE; | 221 | return G_SOURCE_REMOVE; |
176 | 272 | } | 222 | } |
177 | 273 | 223 | ||
180 | 274 | AccountWatcher *account_watcher_new(const char *service_type, | 224 | AccountWatcher *account_watcher_new(AccountEnabledCallback callback, |
179 | 275 | AccountEnabledCallback callback, | ||
181 | 276 | void *user_data) { | 225 | void *user_data) { |
182 | 277 | AccountWatcher *watcher = g_new0(AccountWatcher, 1); | 226 | AccountWatcher *watcher = g_new0(AccountWatcher, 1); |
183 | 278 | 227 | ||
185 | 279 | watcher->manager = ag_manager_new_for_service_type(service_type); | 228 | watcher->manager = ag_manager_new(); |
186 | 280 | watcher->services = g_hash_table_new_full( | 229 | watcher->services = g_hash_table_new_full( |
188 | 281 | g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)account_info_free); | 230 | g_str_hash, g_str_equal, g_free, (GDestroyNotify)account_info_free); |
189 | 282 | watcher->callback = callback; | 231 | watcher->callback = callback; |
190 | 283 | watcher->user_data = user_data; | 232 | watcher->user_data = user_data; |
191 | 284 | 233 | ||
192 | 234 | return watcher; | ||
193 | 235 | } | ||
194 | 236 | |||
195 | 237 | void account_watcher_run(AccountWatcher *watcher) { | ||
196 | 285 | /* Make sure main setup occurs within the mainloop thread */ | 238 | /* Make sure main setup occurs within the mainloop thread */ |
197 | 286 | g_idle_add(account_watcher_setup, watcher); | 239 | g_idle_add(account_watcher_setup, watcher); |
198 | 287 | return watcher; | ||
199 | 288 | } | 240 | } |
200 | 289 | 241 | ||
201 | 290 | struct refresh_info { | 242 | struct refresh_info { |
202 | 291 | AccountWatcher *watcher; | 243 | AccountWatcher *watcher; |
203 | 292 | AgAccountId account_id; | 244 | AgAccountId account_id; |
204 | 245 | char *service_name; | ||
205 | 293 | }; | 246 | }; |
206 | 294 | 247 | ||
207 | 248 | static void refresh_info_free(struct refresh_info *data) { | ||
208 | 249 | g_free(data->service_name); | ||
209 | 250 | g_free(data); | ||
210 | 251 | } | ||
211 | 252 | |||
212 | 295 | static gboolean account_watcher_refresh_cb(void *user_data) { | 253 | static gboolean account_watcher_refresh_cb(void *user_data) { |
213 | 296 | struct refresh_info *data = (struct refresh_info *)user_data; | 254 | struct refresh_info *data = (struct refresh_info *)user_data; |
214 | 297 | 255 | ||
217 | 298 | AccountInfo *info = g_hash_table_lookup( | 256 | char *key = g_strdup_printf("%d/%s", data->account_id, data->service_name); |
218 | 299 | data->watcher->services, GUINT_TO_POINTER(data->account_id)); | 257 | AccountInfo *info = g_hash_table_lookup(data->watcher->services, key); |
219 | 300 | if (info != NULL) { | 258 | if (info != NULL) { |
220 | 301 | account_info_login(info); | 259 | account_info_login(info); |
221 | 302 | } | 260 | } |
222 | @@ -304,10 +262,12 @@ | |||
223 | 304 | return G_SOURCE_REMOVE; | 262 | return G_SOURCE_REMOVE; |
224 | 305 | } | 263 | } |
225 | 306 | 264 | ||
227 | 307 | void account_watcher_refresh(AccountWatcher *watcher, unsigned int account_id) { | 265 | void account_watcher_refresh(AccountWatcher *watcher, unsigned int account_id, |
228 | 266 | const char *service_name) { | ||
229 | 308 | struct refresh_info *data = g_new(struct refresh_info, 1); | 267 | struct refresh_info *data = g_new(struct refresh_info, 1); |
230 | 309 | data->watcher = watcher; | 268 | data->watcher = watcher; |
231 | 310 | data->account_id = account_id; | 269 | data->account_id = account_id; |
232 | 270 | data->service_name = g_strdup(service_name); | ||
233 | 311 | g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, account_watcher_refresh_cb, | 271 | g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, account_watcher_refresh_cb, |
235 | 312 | data, g_free); | 272 | data, (GDestroyNotify)refresh_info_free); |
236 | 313 | } | 273 | } |
237 | 314 | 274 | ||
238 | === modified file 'accounts/account-watcher.h' | |||
239 | --- accounts/account-watcher.h 2016-04-19 19:58:25 +0000 | |||
240 | +++ accounts/account-watcher.h 2016-07-22 08:01:34 +0000 | |||
241 | @@ -32,10 +32,12 @@ | |||
242 | 32 | const char *token_secret, | 32 | const char *token_secret, |
243 | 33 | void *user_data); | 33 | void *user_data); |
244 | 34 | 34 | ||
247 | 35 | AccountWatcher *account_watcher_new(const char *service_type, | 35 | AccountWatcher *account_watcher_new(AccountEnabledCallback callback, |
246 | 36 | AccountEnabledCallback callback, | ||
248 | 37 | void *user_data); | 36 | void *user_data); |
249 | 37 | void account_watcher_run(AccountWatcher *watcher); | ||
250 | 38 | 38 | ||
252 | 39 | void account_watcher_refresh(AccountWatcher *watcher, unsigned int account_id); | 39 | void account_watcher_refresh(AccountWatcher *watcher, |
253 | 40 | unsigned int account_id, | ||
254 | 41 | const char *service_name); | ||
255 | 40 | 42 | ||
256 | 41 | #endif | 43 | #endif |
257 | 42 | 44 | ||
258 | === modified file 'accounts/accounts.c' | |||
259 | --- accounts/accounts.c 2016-04-19 19:58:25 +0000 | |||
260 | +++ accounts/accounts.c 2016-07-22 08:01:34 +0000 | |||
261 | @@ -1,6 +1,6 @@ | |||
262 | 1 | #include "_cgo_export.h" | 1 | #include "_cgo_export.h" |
263 | 2 | 2 | ||
265 | 3 | AccountWatcher *watch_for_service_type(const char *service_type) { | 3 | AccountWatcher *watch() { |
266 | 4 | /* Transfer service names to hash table */ | 4 | /* Transfer service names to hash table */ |
267 | 5 | if (FALSE) { | 5 | if (FALSE) { |
268 | 6 | /* The Go callback doesn't quite match the | 6 | /* The Go callback doesn't quite match the |
269 | @@ -20,6 +20,6 @@ | |||
270 | 20 | } | 20 | } |
271 | 21 | 21 | ||
272 | 22 | AccountWatcher *watcher = account_watcher_new( | 22 | AccountWatcher *watcher = account_watcher_new( |
274 | 23 | service_type, (AccountEnabledCallback)authCallback, NULL); | 23 | (AccountEnabledCallback)authCallback, NULL); |
275 | 24 | return watcher; | 24 | return watcher; |
276 | 25 | } | 25 | } |
277 | 26 | 26 | ||
278 | === modified file 'accounts/accounts.go' | |||
279 | --- accounts/accounts.go 2016-04-19 19:58:25 +0000 | |||
280 | +++ accounts/accounts.go 2016-07-22 08:01:34 +0000 | |||
281 | @@ -22,7 +22,7 @@ | |||
282 | 22 | #include <glib.h> | 22 | #include <glib.h> |
283 | 23 | #include "account-watcher.h" | 23 | #include "account-watcher.h" |
284 | 24 | 24 | ||
286 | 25 | AccountWatcher *watch_for_service_type(const char *service_type); | 25 | AccountWatcher *watch(); |
287 | 26 | */ | 26 | */ |
288 | 27 | import "C" | 27 | import "C" |
289 | 28 | import ( | 28 | import ( |
290 | @@ -54,12 +54,10 @@ | |||
291 | 54 | authChannelsLock sync.Mutex | 54 | authChannelsLock sync.Mutex |
292 | 55 | ) | 55 | ) |
293 | 56 | 56 | ||
296 | 57 | // NewWatcher creates a new account watcher for the given service names | 57 | // NewWatcher creates a new account watcher |
297 | 58 | func NewWatcher(serviceType string) *Watcher { | 58 | func NewWatcher() *Watcher { |
298 | 59 | w := new(Watcher) | 59 | w := new(Watcher) |
302 | 60 | cServiceType := C.CString(serviceType) | 60 | w.watcher = C.watch() |
300 | 61 | defer C.free(unsafe.Pointer(cServiceType)) | ||
301 | 62 | w.watcher = C.watch_for_service_type(cServiceType) | ||
303 | 63 | 61 | ||
304 | 64 | ch := make(chan AuthData) | 62 | ch := make(chan AuthData) |
305 | 65 | w.C = ch | 63 | w.C = ch |
306 | @@ -70,10 +68,16 @@ | |||
307 | 70 | return w | 68 | return w |
308 | 71 | } | 69 | } |
309 | 72 | 70 | ||
310 | 71 | // Walk through the enabled accounts, and get auth tokens for each of them. | ||
311 | 72 | // The new access token will be delivered over the watcher's channel. | ||
312 | 73 | func (w *Watcher) Run() { | ||
313 | 74 | C.account_watcher_run(w.watcher) | ||
314 | 75 | } | ||
315 | 76 | |||
316 | 73 | // Refresh requests that the token for the given account be refreshed. | 77 | // Refresh requests that the token for the given account be refreshed. |
317 | 74 | // The new access token will be delivered over the watcher's channel. | 78 | // The new access token will be delivered over the watcher's channel. |
320 | 75 | func (w *Watcher) Refresh(accountId uint) { | 79 | func (w *Watcher) Refresh(accountId uint, serviceName string) { |
321 | 76 | C.account_watcher_refresh(w.watcher, C.uint(accountId)) | 80 | C.account_watcher_refresh(w.watcher, C.uint(accountId), C.CString(serviceName)) |
322 | 77 | } | 81 | } |
323 | 78 | 82 | ||
324 | 79 | //export authCallback | 83 | //export authCallback |
325 | 80 | 84 | ||
326 | === renamed file 'cmd/account-polld/account_manager.go' => 'cmd/account-polld/account_service.go' | |||
327 | --- cmd/account-polld/account_manager.go 2016-06-30 19:21:46 +0000 | |||
328 | +++ cmd/account-polld/account_service.go 2016-07-22 08:01:34 +0000 | |||
329 | @@ -26,7 +26,7 @@ | |||
330 | 26 | "launchpad.net/ubuntu-push/click" | 26 | "launchpad.net/ubuntu-push/click" |
331 | 27 | ) | 27 | ) |
332 | 28 | 28 | ||
334 | 29 | type AccountManager struct { | 29 | type AccountService struct { |
335 | 30 | watcher *accounts.Watcher | 30 | watcher *accounts.Watcher |
336 | 31 | authData accounts.AuthData | 31 | authData accounts.AuthData |
337 | 32 | plugin plugins.Plugin | 32 | plugin plugins.Plugin |
338 | @@ -51,8 +51,8 @@ | |||
339 | 51 | clickNotInstalledError = errors.New("Click not installed") | 51 | clickNotInstalledError = errors.New("Click not installed") |
340 | 52 | ) | 52 | ) |
341 | 53 | 53 | ||
344 | 54 | func NewAccountManager(watcher *accounts.Watcher, postWatch chan *PostWatch, plugin plugins.Plugin) *AccountManager { | 54 | func NewAccountService(watcher *accounts.Watcher, postWatch chan *PostWatch, plugin plugins.Plugin) *AccountService { |
345 | 55 | return &AccountManager{ | 55 | return &AccountService{ |
346 | 56 | watcher: watcher, | 56 | watcher: watcher, |
347 | 57 | plugin: plugin, | 57 | plugin: plugin, |
348 | 58 | postWatch: postWatch, | 58 | postWatch: postWatch, |
349 | @@ -61,20 +61,18 @@ | |||
350 | 61 | } | 61 | } |
351 | 62 | } | 62 | } |
352 | 63 | 63 | ||
354 | 64 | func (a *AccountManager) Delete() { | 64 | func (a *AccountService) Delete() { |
355 | 65 | close(a.authChan) | 65 | close(a.authChan) |
356 | 66 | close(a.doneChan) | 66 | close(a.doneChan) |
357 | 67 | } | 67 | } |
358 | 68 | 68 | ||
359 | 69 | // Poll() always needs to be called asynchronously as otherwise qtcontacs' GetAvatar() | 69 | // Poll() always needs to be called asynchronously as otherwise qtcontacs' GetAvatar() |
360 | 70 | // will raise an error: "QSocketNotifier: Can only be used with threads started with QThread" | 70 | // will raise an error: "QSocketNotifier: Can only be used with threads started with QThread" |
362 | 71 | func (a *AccountManager) Poll(bootstrap bool) { | 71 | func (a *AccountService) Poll(bootstrap bool) { |
363 | 72 | gotNewAuthData := false | 72 | gotNewAuthData := false |
369 | 73 | if !a.authData.Enabled { | 73 | if a.authData, gotNewAuthData = <-a.authChan; !gotNewAuthData { |
370 | 74 | if a.authData, gotNewAuthData = <-a.authChan; !gotNewAuthData { | 74 | log.Println("Account", a.authData.AccountId, "no longer enabled") |
371 | 75 | log.Println("Account", a.authData.AccountId, "no longer enabled") | 75 | return |
367 | 76 | return | ||
368 | 77 | } | ||
372 | 78 | } | 76 | } |
373 | 79 | 77 | ||
374 | 80 | if a.penaltyCount > 0 { | 78 | if a.penaltyCount > 0 { |
375 | @@ -126,7 +124,7 @@ | |||
376 | 126 | // and mark the data as disabled. | 124 | // and mark the data as disabled. |
377 | 127 | // Do not refresh immediately when we just got new (faulty) auth data as immediately trying | 125 | // Do not refresh immediately when we just got new (faulty) auth data as immediately trying |
378 | 128 | // again is probably not going to help. Instead, we wait for the next poll cycle. | 126 | // again is probably not going to help. Instead, we wait for the next poll cycle. |
380 | 129 | a.watcher.Refresh(a.authData.AccountId) | 127 | a.watcher.Refresh(a.authData.AccountId, a.authData.ServiceName) |
381 | 130 | a.authData.Enabled = false | 128 | a.authData.Enabled = false |
382 | 131 | a.authData.Error = err | 129 | a.authData.Error = err |
383 | 132 | } | 130 | } |
384 | @@ -139,7 +137,7 @@ | |||
385 | 139 | log.Printf("Ending poll for account %d", a.authData.AccountId) | 137 | log.Printf("Ending poll for account %d", a.authData.AccountId) |
386 | 140 | } | 138 | } |
387 | 141 | 139 | ||
389 | 142 | func (a *AccountManager) poll() { | 140 | func (a *AccountService) poll() { |
390 | 143 | log.Println("Polling account", a.authData.AccountId) | 141 | log.Println("Polling account", a.authData.AccountId) |
391 | 144 | if !isClickInstalled(a.plugin.ApplicationId()) { | 142 | if !isClickInstalled(a.plugin.ApplicationId()) { |
392 | 145 | log.Println( | 143 | log.Println( |
393 | @@ -167,7 +165,7 @@ | |||
394 | 167 | } | 165 | } |
395 | 168 | } | 166 | } |
396 | 169 | 167 | ||
398 | 170 | func (a *AccountManager) updateAuthData(authData accounts.AuthData) { | 168 | func (a *AccountService) updateAuthData(authData accounts.AuthData) { |
399 | 171 | a.authChan <- authData | 169 | a.authChan <- authData |
400 | 172 | } | 170 | } |
401 | 173 | 171 | ||
402 | 174 | 172 | ||
403 | === modified file 'cmd/account-polld/main.go' | |||
404 | --- cmd/account-polld/main.go 2016-04-21 23:33:48 +0000 | |||
405 | +++ cmd/account-polld/main.go 2016-07-22 08:01:34 +0000 | |||
406 | @@ -41,16 +41,13 @@ | |||
407 | 41 | } | 41 | } |
408 | 42 | 42 | ||
409 | 43 | type AccountKey struct { | 43 | type AccountKey struct { |
411 | 44 | serviceType string | 44 | serviceId string |
412 | 45 | accountId uint | 45 | accountId uint |
413 | 46 | } | 46 | } |
414 | 47 | 47 | ||
415 | 48 | /* Use identifiers and API keys provided by the respective webapps which are the official | 48 | /* Use identifiers and API keys provided by the respective webapps which are the official |
416 | 49 | end points for the notifications */ | 49 | end points for the notifications */ |
417 | 50 | const ( | 50 | const ( |
418 | 51 | SERVICETYPE_WEBAPPS = "webapps" | ||
419 | 52 | SERVICETYPE_CALENDAR = "calendar" | ||
420 | 53 | |||
421 | 54 | SERVICENAME_GMAIL = "com.ubuntu.developer.webapps.webapp-gmail_webapp-gmail" | 51 | SERVICENAME_GMAIL = "com.ubuntu.developer.webapps.webapp-gmail_webapp-gmail" |
422 | 55 | SERVICENAME_TWITTER = "com.ubuntu.developer.webapps.webapp-twitter_webapp-twitter" | 52 | SERVICENAME_TWITTER = "com.ubuntu.developer.webapps.webapp-twitter_webapp-twitter" |
423 | 56 | SERVICENAME_GCALENDAR = "google-caldav" | 53 | SERVICENAME_GCALENDAR = "google-caldav" |
424 | @@ -101,16 +98,14 @@ | |||
425 | 101 | } | 98 | } |
426 | 102 | 99 | ||
427 | 103 | func monitorAccounts(postWatch chan *PostWatch, pollBus *pollbus.PollBus) { | 100 | func monitorAccounts(postWatch chan *PostWatch, pollBus *pollbus.PollBus) { |
431 | 104 | watchers := make(map[string]*accounts.Watcher) | 101 | watcher := accounts.NewWatcher() |
429 | 105 | watchers[SERVICETYPE_WEBAPPS] = accounts.NewWatcher(SERVICETYPE_WEBAPPS) | ||
430 | 106 | watchers[SERVICETYPE_CALENDAR] = accounts.NewWatcher(SERVICETYPE_CALENDAR) | ||
432 | 107 | 102 | ||
434 | 108 | mgr := make(map[AccountKey]*AccountManager) | 103 | mgr := make(map[AccountKey]*AccountService) |
435 | 109 | 104 | ||
436 | 110 | var wg sync.WaitGroup | 105 | var wg sync.WaitGroup |
437 | 111 | 106 | ||
438 | 112 | pullAccount := func(data accounts.AuthData) bool { | 107 | pullAccount := func(data accounts.AuthData) bool { |
440 | 113 | accountKey := AccountKey{data.ServiceType, data.AccountId} | 108 | accountKey := AccountKey{data.ServiceName, data.AccountId} |
441 | 114 | if account, ok := mgr[accountKey]; ok { | 109 | if account, ok := mgr[accountKey]; ok { |
442 | 115 | if data.Enabled { | 110 | if data.Enabled { |
443 | 116 | log.Println("New account data for existing account with id", data.AccountId) | 111 | log.Println("New account data for existing account with id", data.AccountId) |
444 | @@ -131,7 +126,7 @@ | |||
445 | 131 | } | 126 | } |
446 | 132 | } else if data.Enabled { | 127 | } else if data.Enabled { |
447 | 133 | var plugin plugins.Plugin | 128 | var plugin plugins.Plugin |
449 | 134 | log.Println("Creat plugin for service: ", data.ServiceName) | 129 | log.Println("Creating plugin for service: ", data.ServiceName) |
450 | 135 | switch data.ServiceName { | 130 | switch data.ServiceName { |
451 | 136 | case SERVICENAME_GMAIL: | 131 | case SERVICENAME_GMAIL: |
452 | 137 | log.Println("Creating account with id", data.AccountId, "for", data.ServiceName) | 132 | log.Println("Creating account with id", data.AccountId, "for", data.ServiceName) |
453 | @@ -147,7 +142,7 @@ | |||
454 | 147 | log.Println("Unhandled account with id", data.AccountId, "for", data.ServiceName) | 142 | log.Println("Unhandled account with id", data.AccountId, "for", data.ServiceName) |
455 | 148 | return false | 143 | return false |
456 | 149 | } | 144 | } |
458 | 150 | mgr[accountKey] = NewAccountManager(watchers[data.ServiceType], postWatch, plugin) | 145 | mgr[accountKey] = NewAccountService(watcher, postWatch, plugin) |
459 | 151 | mgr[accountKey].updateAuthData(data) | 146 | mgr[accountKey].updateAuthData(data) |
460 | 152 | wg.Add(1) | 147 | wg.Add(1) |
461 | 153 | go func() { | 148 | go func() { |
462 | @@ -165,27 +160,14 @@ | |||
463 | 165 | L: | 160 | L: |
464 | 166 | for { | 161 | for { |
465 | 167 | select { | 162 | select { |
472 | 168 | case data := <-watchers[SERVICETYPE_CALENDAR].C: | 163 | case data := <-watcher.C: |
473 | 169 | if pullAccount(data) == false { | 164 | if pullAccount(data) == false { |
474 | 170 | continue L | 165 | log.Println("pullAccount returned false, continuing") |
469 | 171 | } | ||
470 | 172 | case data := <-watchers[SERVICETYPE_WEBAPPS].C: | ||
471 | 173 | if pullAccount(data) == false { | ||
475 | 174 | continue L | 166 | continue L |
476 | 175 | } | 167 | } |
477 | 176 | case <-pollBus.PollChan: | 168 | case <-pollBus.PollChan: |
478 | 177 | wg.Wait() // Finish all running Poll() calls before potentially polling the same accounts again | 169 | wg.Wait() // Finish all running Poll() calls before potentially polling the same accounts again |
490 | 178 | for _, v := range mgr { | 170 | watcher.Run() |
480 | 179 | if v.authData.Error != plugins.ErrTokenExpired { // Do not poll if the new token hasn't been loaded yet | ||
481 | 180 | wg.Add(1) | ||
482 | 181 | go func(accountManager *AccountManager) { | ||
483 | 182 | defer wg.Done() | ||
484 | 183 | accountManager.Poll(false) | ||
485 | 184 | }(v) | ||
486 | 185 | } else { | ||
487 | 186 | log.Println("Skipping account with id", v.authData.AccountId, "as it is refreshing its token") | ||
488 | 187 | } | ||
489 | 188 | } | ||
491 | 189 | wg.Wait() | 171 | wg.Wait() |
492 | 190 | pollBus.SignalDone() | 172 | pollBus.SignalDone() |
493 | 191 | } | 173 | } |
494 | 192 | 174 | ||
495 | === modified file 'cmd/account-watcher-test/main.go' | |||
496 | --- cmd/account-watcher-test/main.go 2014-07-24 05:38:51 +0000 | |||
497 | +++ cmd/account-watcher-test/main.go 2016-07-22 08:01:34 +0000 | |||
498 | @@ -2,14 +2,12 @@ | |||
499 | 2 | 2 | ||
500 | 3 | import ( | 3 | import ( |
501 | 4 | "fmt" | 4 | "fmt" |
502 | 5 | "os" | ||
503 | 6 | 5 | ||
504 | 7 | "launchpad.net/account-polld/accounts" | 6 | "launchpad.net/account-polld/accounts" |
505 | 8 | ) | 7 | ) |
506 | 9 | 8 | ||
507 | 10 | func main() { | 9 | func main() { |
510 | 11 | // Expects a list of service names as command line arguments | 10 | for data := range accounts.NewWatcher().C { |
509 | 12 | for data := range accounts.NewWatcher(os.Args[1]).C { | ||
511 | 13 | if data.Error != nil { | 11 | if data.Error != nil { |
512 | 14 | fmt.Println("Failed to authenticate account", data.AccountId, ":", data.Error) | 12 | fmt.Println("Failed to authenticate account", data.AccountId, ":", data.Error) |
513 | 15 | } else { | 13 | } else { |
PASSED: Continuous integration, rev:177 /jenkins. canonical. com/system- apps/job/ lp-account- polld-ci/ 13/ /jenkins. canonical. com/system- apps/job/ build/1029 /jenkins. canonical. com/system- apps/job/ test-0- autopkgtest/ label=phone- armhf,release= vivid+overlay, testname= default/ 197 /jenkins. canonical. com/system- apps/job/ build-0- fetch/1029 /jenkins. canonical. com/system- apps/job/ build-1- sourcepkg/ release= vivid+overlay/ 926 /jenkins. canonical. com/system- apps/job/ build-1- sourcepkg/ release= xenial+ overlay/ 926 /jenkins. canonical. com/system- apps/job/ build-1- sourcepkg/ release= yakkety/ 926 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 920 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 920/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 920 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 920/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 920 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 920/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 920 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 920/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 920 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 920/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 920 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 920/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 920 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 920/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 920 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 920/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= yakkety/ 920 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= yakkety/ 920/artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- apps/job/ lp-account- polld-ci/ 13/rebuild
https:/