Merge lp:~jamesh/account-polld/accounts-integration into lp:~phablet-team/account-polld/trunk
- accounts-integration
- Merge into trunk
Proposed by
James Henstridge
Status: | Merged |
---|---|
Approved by: | Sergio Schvezov |
Approved revision: | 13 |
Merged at revision: | 5 |
Proposed branch: | lp:~jamesh/account-polld/accounts-integration |
Merge into: | lp:~phablet-team/account-polld/trunk |
Prerequisite: | lp:~sergiusens/account-polld/daemon |
Diff against target: |
606 lines (+372/-164) 5 files modified
accounts/account-watcher.c (+279/-0) accounts/account-watcher.h (+38/-0) accounts/accounts.c (+16/-152) accounts/accounts.go (+24/-12) cmd/account-watcher-test/main.go (+15/-0) |
To merge this branch: | bzr merge lp:~jamesh/account-polld/accounts-integration |
Related bugs: | |
Related blueprints: |
account-polld push and account notification
(Undefined)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sergio Schvezov | Approve | ||
Review via email: mp+226463@code.launchpad.net |
Commit message
Description of the change
Update and refactor the online-accounts binding to support tracking multiple services and multiple instances of each service. I also split the main C logic into a separate file independent of the Go binding since it allowed me to run it independently.
There is a compiler warning due to the callback function exported from Go not matching the signature expected by the C interface: the first argument should be *C.AccountWatcher, but that doesn't seem to work right. The Go 1.3 release notes seem to indicate that they've fixed up handling of incomplete types there, but I haven't tested it yet.
The Go interface remains compatible, but perhaps it could do with some changes too.
To post a comment you must log in.
- 13. By James Henstridge
-
Remove unneeded includes.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'accounts/account-watcher.c' |
2 | --- accounts/account-watcher.c 1970-01-01 00:00:00 +0000 |
3 | +++ accounts/account-watcher.c 2014-07-11 13:44:43 +0000 |
4 | @@ -0,0 +1,279 @@ |
5 | +/* |
6 | + Copyright 2014 Canonical Ltd. |
7 | + Authors: James Henstridge <james.henstridge@canonical.com> |
8 | + |
9 | + This program is free software: you can redistribute it and/or modify it |
10 | + under the terms of the GNU General Public License version 3, as published |
11 | + by the Free Software Foundation. |
12 | + |
13 | + This program is distributed in the hope that it will be useful, but |
14 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
15 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
16 | + PURPOSE. See the GNU General Public License for more details. |
17 | + |
18 | + You should have received a copy of the GNU General Public License along |
19 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | +*/ |
21 | +#include <stdio.h> |
22 | + |
23 | +#include <glib.h> |
24 | +#include <libaccounts-glib/accounts-glib.h> |
25 | +#include <libsignon-glib/signon-glib.h> |
26 | + |
27 | +#include "account-watcher.h" |
28 | + |
29 | +struct _AccountWatcher { |
30 | + AgManager *manager; |
31 | + /* A hash table of the service names we are interested in */ |
32 | + GHashTable *services_to_watch; |
33 | + /* A hash table of the enabled accounts we know of. |
34 | + * Keys are account ID integers, and AccountInfo structs as values. |
35 | + */ |
36 | + GHashTable *services; |
37 | + |
38 | + gulong enabled_event_signal_id; |
39 | + gulong account_deleted_signal_id; |
40 | + |
41 | + AccountEnabledCallback callback; |
42 | + void *user_data; |
43 | +}; |
44 | + |
45 | +typedef struct _AccountInfo AccountInfo; |
46 | +struct _AccountInfo { |
47 | + AccountWatcher *watcher; |
48 | + /* Manage signin session for account */ |
49 | + AgAccountService *account_service; |
50 | + SignonAuthSession *session; |
51 | + GVariant *auth_params; |
52 | + GVariant *session_data; |
53 | + |
54 | + gulong enabled_signal_id; |
55 | + AgAccountId account_id; |
56 | + gboolean enabled; /* the last known state of the account */ |
57 | +}; |
58 | + |
59 | +static void account_info_clear_login(AccountInfo *info) { |
60 | + if (info->session_data) { |
61 | + g_variant_unref(info->session_data); |
62 | + info->session_data = NULL; |
63 | + } |
64 | + if (info->auth_params) { |
65 | + g_variant_unref(info->auth_params); |
66 | + info->auth_params = NULL; |
67 | + } |
68 | + if (info->session) { |
69 | + signon_auth_session_cancel(info->session); |
70 | + g_object_unref(info->session); |
71 | + info->session = NULL; |
72 | + } |
73 | +} |
74 | + |
75 | +static void account_info_free(AccountInfo *info) { |
76 | + account_info_clear_login(info); |
77 | + if (info->enabled_signal_id != 0) { |
78 | + g_signal_handler_disconnect( |
79 | + info->account_service, info->enabled_signal_id); |
80 | + } |
81 | + info->enabled_signal_id = 0; |
82 | + if (info->account_service) { |
83 | + g_object_unref(info->account_service); |
84 | + info->account_service = NULL; |
85 | + } |
86 | + g_free(info); |
87 | +} |
88 | + |
89 | +static void account_info_notify(AccountInfo *info) { |
90 | + AgService *service = ag_account_service_get_service(info->account_service); |
91 | + const char *service_name = ag_service_get_name(service); |
92 | + char *client_id = NULL; |
93 | + char *client_secret = NULL; |
94 | + char *access_token = NULL; |
95 | + char *token_secret = NULL; |
96 | + |
97 | + if (info->enabled) { |
98 | + /* Look up OAuth 2 parameters, falling back to OAuth 1 names */ |
99 | + g_variant_lookup(info->auth_params, "ClientId", "&s", &client_id); |
100 | + g_variant_lookup(info->auth_params, "ClientSecret", "&s", &client_secret); |
101 | + g_variant_lookup(info->session_data, "AccessToken", "&s", &access_token); |
102 | + g_variant_lookup(info->session_data, "TokenSecret", "&s", &token_secret); |
103 | + |
104 | + if (client_id == NULL) { |
105 | + g_variant_lookup(info->auth_params, "ConsumerKey", "&s", &client_id); |
106 | + } |
107 | + if (client_secret == NULL) { |
108 | + g_variant_lookup(info->auth_params, "ConsumerSecret", "&s", &client_secret); |
109 | + } |
110 | + } |
111 | + |
112 | + info->watcher->callback(info->watcher, |
113 | + info->account_id, |
114 | + service_name, |
115 | + info->enabled, |
116 | + client_id, |
117 | + client_secret, |
118 | + access_token, |
119 | + token_secret, |
120 | + info->watcher->user_data); |
121 | +} |
122 | + |
123 | +static void account_info_login_cb(GObject *source, GAsyncResult *result, void *user_data) { |
124 | + SignonAuthSession *session = (SignonAuthSession *)source; |
125 | + AccountInfo *info = (AccountInfo *)user_data; |
126 | + |
127 | + fprintf(stderr, "Authentication for account %u complete\n", info->account_id); |
128 | + |
129 | + GError *error = NULL; |
130 | + info->session_data = signon_auth_session_process_finish(session, result, &error); |
131 | + |
132 | + if (error != NULL) { |
133 | + fprintf(stderr, "Authentication failed: %s\n", error->message); |
134 | + g_error_free(error); |
135 | + return; |
136 | + } |
137 | + account_info_notify(info); |
138 | +} |
139 | + |
140 | +static void account_info_enabled_cb( |
141 | + AgAccountService *account_service, gboolean enabled, AccountInfo *info) { |
142 | + fprintf(stderr, "account_info_enabled_cb for %u, enabled=%d\n", info->account_id, enabled); |
143 | + if (info->enabled == enabled) { |
144 | + /* no change */ |
145 | + return; |
146 | + } |
147 | + info->enabled = enabled; |
148 | + |
149 | + account_info_clear_login(info); |
150 | + if (!enabled) { |
151 | + // Send notification that account has been disabled */ |
152 | + account_info_notify(info); |
153 | + return; |
154 | + } |
155 | + |
156 | + AgAuthData *auth_data = ag_account_service_get_auth_data(account_service); |
157 | + GError *error = NULL; |
158 | + fprintf(stderr, "Starting authentication session for account %u\n", info->account_id); |
159 | + info->session = signon_auth_session_new( |
160 | + ag_auth_data_get_credentials_id(auth_data), |
161 | + ag_auth_data_get_method(auth_data), &error); |
162 | + if (error != NULL) { |
163 | + fprintf(stderr, "Could not set up auth session: %s\n", error->message); |
164 | + g_error_free(error); |
165 | + g_object_unref(auth_data); |
166 | + return; |
167 | + } |
168 | + |
169 | + GVariantBuilder builder; |
170 | + g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); |
171 | + g_variant_builder_add( |
172 | + &builder, "{sv}", |
173 | + SIGNON_SESSION_DATA_UI_POLICY, |
174 | + g_variant_new_int32(SIGNON_POLICY_NO_USER_INTERACTION)); |
175 | + |
176 | + info->auth_params = g_variant_ref_sink( |
177 | + ag_auth_data_get_login_parameters( |
178 | + auth_data, g_variant_builder_end(&builder))); |
179 | + |
180 | + signon_auth_session_process_async( |
181 | + info->session, |
182 | + info->auth_params, |
183 | + ag_auth_data_get_mechanism(auth_data), |
184 | + NULL, /* cancellable */ |
185 | + account_info_login_cb, info); |
186 | + ag_auth_data_unref(auth_data); |
187 | +} |
188 | + |
189 | +static AccountInfo *account_info_new(AccountWatcher *watcher, AgAccountService *account_service) { |
190 | + AccountInfo *info = g_new0(AccountInfo, 1); |
191 | + info->watcher = watcher; |
192 | + info->account_service = g_object_ref(account_service); |
193 | + |
194 | + AgAccount *account = ag_account_service_get_account(account_service); |
195 | + g_object_get(account, "id", &info->account_id, NULL); |
196 | + |
197 | + info->enabled_signal_id = g_signal_connect( |
198 | + account_service, "enabled", |
199 | + G_CALLBACK(account_info_enabled_cb), info); |
200 | + // Set initial state |
201 | + account_info_enabled_cb(account_service, ag_account_service_get_enabled(account_service), info); |
202 | + |
203 | + return info; |
204 | +} |
205 | + |
206 | +static void account_watcher_enabled_event_cb( |
207 | + AgManager *manager, AgAccountId account_id, AccountWatcher *watcher) { |
208 | + fprintf(stderr, "enabled-event for %u\n", account_id); |
209 | + if (g_hash_table_contains(watcher->services, GUINT_TO_POINTER(account_id))) { |
210 | + /* We are already tracking this account */ |
211 | + return; |
212 | + } |
213 | + AgAccount *account = ag_manager_get_account(manager, account_id); |
214 | + if (account == NULL) { |
215 | + /* There was a problem looking up the account */ |
216 | + return; |
217 | + } |
218 | + GList *services = ag_account_list_services(account); |
219 | + GList *l; |
220 | + for (l = services; l != NULL; l = l->next) { |
221 | + AgService *service = l->data; |
222 | + |
223 | + const char *name = ag_service_get_name(service); |
224 | + if (g_hash_table_contains(watcher->services_to_watch, name)) { |
225 | + AgAccountService *account_service = ag_account_service_new( |
226 | + account, service); |
227 | + AccountInfo *info = account_info_new(watcher, account_service); |
228 | + g_object_unref(account_service); |
229 | + g_hash_table_insert(watcher->services, GUINT_TO_POINTER(account_id), info); |
230 | + break; |
231 | + } |
232 | + } |
233 | + ag_service_list_free(services); |
234 | + g_object_unref(account); |
235 | +} |
236 | + |
237 | +static void account_watcher_account_deleted_cb( |
238 | + AgManager *manager, AgAccountId account_id, AccountWatcher *watcher) { |
239 | + fprintf(stderr, "account-deleted for %u\n", account_id); |
240 | + /* A disabled event should have been sent prior to this, so no |
241 | + * need to send any notification. */ |
242 | + g_hash_table_remove(watcher->services, GUINT_TO_POINTER(account_id)); |
243 | +} |
244 | + |
245 | +static gboolean account_watcher_setup(void *user_data) { |
246 | + AccountWatcher *watcher = (AccountWatcher *)user_data; |
247 | + |
248 | + /* Track changes to accounts */ |
249 | + watcher->enabled_event_signal_id = g_signal_connect( |
250 | + watcher->manager, "enabled-event", |
251 | + G_CALLBACK(account_watcher_enabled_event_cb), watcher); |
252 | + watcher->account_deleted_signal_id = g_signal_connect( |
253 | + watcher->manager, "account-deleted", |
254 | + G_CALLBACK(account_watcher_account_deleted_cb), watcher); |
255 | + |
256 | + /* Now check initial state */ |
257 | + GList *enabled_accounts = ag_manager_list(watcher->manager); |
258 | + GList *l; |
259 | + for (l = enabled_accounts; l != NULL; l = l->next) { |
260 | + AgAccountId account_id = GPOINTER_TO_UINT(l->data); |
261 | + account_watcher_enabled_event_cb(watcher->manager, account_id, watcher); |
262 | + } |
263 | + ag_manager_list_free(enabled_accounts); |
264 | + |
265 | + return FALSE; |
266 | +} |
267 | + |
268 | +AccountWatcher *account_watcher_new(GHashTable *services_to_watch, |
269 | + AccountEnabledCallback callback, |
270 | + void *user_data) { |
271 | + AccountWatcher *watcher = g_new0(AccountWatcher, 1); |
272 | + |
273 | + watcher->manager = ag_manager_new(); |
274 | + watcher->services_to_watch = g_hash_table_ref(services_to_watch); |
275 | + watcher->services = g_hash_table_new_full( |
276 | + g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)account_info_free); |
277 | + watcher->callback = callback; |
278 | + watcher->user_data = user_data; |
279 | + |
280 | + /* Make sure main setup occurs within the mainloop thread */ |
281 | + g_idle_add(account_watcher_setup, watcher); |
282 | + return watcher; |
283 | +} |
284 | |
285 | === added file 'accounts/account-watcher.h' |
286 | --- accounts/account-watcher.h 1970-01-01 00:00:00 +0000 |
287 | +++ accounts/account-watcher.h 2014-07-11 13:44:43 +0000 |
288 | @@ -0,0 +1,38 @@ |
289 | +/* |
290 | + Copyright 2014 Canonical Ltd. |
291 | + Authors: James Henstridge <james.henstridge@canonical.com> |
292 | + |
293 | + This program is free software: you can redistribute it and/or modify it |
294 | + under the terms of the GNU General Public License version 3, as published |
295 | + by the Free Software Foundation. |
296 | + |
297 | + This program is distributed in the hope that it will be useful, but |
298 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
299 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
300 | + PURPOSE. See the GNU General Public License for more details. |
301 | + |
302 | + You should have received a copy of the GNU General Public License along |
303 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
304 | +*/ |
305 | +#ifndef ACCOUNT_WATCHER_H |
306 | +#define ACCOUNT_WATCHER_H |
307 | + |
308 | +#include <glib.h> |
309 | + |
310 | +typedef struct _AccountWatcher AccountWatcher; |
311 | + |
312 | +typedef void (*AccountEnabledCallback)(AccountWatcher *watcher, |
313 | + unsigned int account_id, |
314 | + const char *service_name, |
315 | + int enabled, |
316 | + const char *client_id, |
317 | + const char *client_secret, |
318 | + const char *access_token, |
319 | + const char *token_secret, |
320 | + void *user_data); |
321 | + |
322 | +AccountWatcher *account_watcher_new(GHashTable *services_to_watch, |
323 | + AccountEnabledCallback callback, |
324 | + void *user_data); |
325 | + |
326 | +#endif |
327 | |
328 | === modified file 'accounts/accounts.c' |
329 | --- accounts/accounts.c 2014-07-11 13:44:43 +0000 |
330 | +++ accounts/accounts.c 2014-07-11 13:44:43 +0000 |
331 | @@ -1,154 +1,18 @@ |
332 | #include "_cgo_export.h" |
333 | -#include <stdio.h> |
334 | -#include <string.h> |
335 | -#include <unistd.h> |
336 | - |
337 | -#include <glib.h> |
338 | -#include <libaccounts-glib/accounts-glib.h> |
339 | -#include <libsignon-glib/signon-glib.h> |
340 | - |
341 | -typedef struct _AuthContext AuthContext; |
342 | -struct _AuthContext { |
343 | - AgManager *manager; |
344 | - char *service_name; |
345 | - AgAccountService *account_service; |
346 | - AgAuthData *auth_data; |
347 | - SignonAuthSession *session; |
348 | - |
349 | - GVariant *auth_params; |
350 | - GVariant *session_data; |
351 | -}; |
352 | - |
353 | -static void login_cb(GObject *source, GAsyncResult *result, void *user_data) { |
354 | - SignonAuthSession *session = (SignonAuthSession *)source; |
355 | - AuthContext *ctx = (AuthContext *)user_data; |
356 | - |
357 | - GError *error = NULL; |
358 | - ctx->session_data = signon_auth_session_process_finish(session, result, &error); |
359 | - |
360 | - g_object_unref(ctx->session); |
361 | - ctx->session = NULL; |
362 | - |
363 | - if (error != NULL) { |
364 | - fprintf(stderr, "Authentication failed: %s\n", error->message); |
365 | - g_error_free(error); |
366 | - return; |
367 | - } |
368 | - |
369 | - char *client_id = NULL; |
370 | - char *client_secret = NULL; |
371 | - char *access_token = NULL; |
372 | - g_variant_lookup(ctx->auth_params, "ClientId", "&s", &client_id); |
373 | - g_variant_lookup(ctx->auth_params, "ClientSecret", "&s", &client_secret); |
374 | - g_variant_lookup(ctx->session_data, "AccessToken", "&s", &access_token); |
375 | - |
376 | - authLogin(ctx, client_id, client_secret, access_token); |
377 | -} |
378 | - |
379 | -static void login_service(AuthContext *ctx) { |
380 | - ctx->auth_data = ag_account_service_get_auth_data(ctx->account_service); |
381 | - |
382 | - GError *error = NULL; |
383 | - ctx->session = signon_auth_session_new( |
384 | - ag_auth_data_get_credentials_id(ctx->auth_data), |
385 | - ag_auth_data_get_method(ctx->auth_data), &error); |
386 | - if (error != NULL) { |
387 | - fprintf(stderr, "Could not set up auth session: %s\n", error->message); |
388 | - g_error_free(error); |
389 | - return; |
390 | - } |
391 | - |
392 | - GVariantBuilder builder; |
393 | - g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); |
394 | - g_variant_builder_add( |
395 | - &builder, "{sv}", |
396 | - SIGNON_SESSION_DATA_UI_POLICY, |
397 | - g_variant_new_int32(SIGNON_POLICY_NO_USER_INTERACTION)); |
398 | - |
399 | - ctx->auth_params = g_variant_ref_sink( |
400 | - ag_auth_data_get_login_parameters( |
401 | - ctx->auth_data, g_variant_builder_end(&builder))); |
402 | - |
403 | - signon_auth_session_process_async( |
404 | - ctx->session, |
405 | - ctx->auth_params, |
406 | - ag_auth_data_get_mechanism(ctx->auth_data), |
407 | - NULL, /* cancellable */ |
408 | - login_cb, ctx); |
409 | -} |
410 | - |
411 | -static void logout_service(AuthContext *ctx) { |
412 | - if (ctx->session_data) { |
413 | - g_variant_unref(ctx->session_data); |
414 | - ctx->session_data = NULL; |
415 | - } |
416 | - if (ctx->auth_params) { |
417 | - g_variant_unref(ctx->auth_params); |
418 | - ctx->auth_params = NULL; |
419 | - } |
420 | - if (ctx->session) { |
421 | - signon_auth_session_cancel(ctx->session); |
422 | - g_object_unref(ctx->session); |
423 | - ctx->session = NULL; |
424 | - } |
425 | - if (ctx->auth_data) { |
426 | - g_object_unref(ctx->auth_data); |
427 | - ctx->auth_data = NULL; |
428 | - } |
429 | - if (ctx->account_service) { |
430 | - g_object_unref(ctx->account_service); |
431 | - ctx->account_service = NULL; |
432 | - } |
433 | - |
434 | - authLogin(ctx, NULL, NULL, NULL); |
435 | -} |
436 | - |
437 | -static void lookup_account_service(AuthContext *ctx) { |
438 | - GList *account_services = ag_manager_get_enabled_account_services(ctx->manager); |
439 | - GList *tmp; |
440 | - for (tmp = account_services; tmp != NULL; tmp = tmp->next) { |
441 | - AgAccountService *acct_svc = AG_ACCOUNT_SERVICE(tmp->data); |
442 | - AgService *service = ag_account_service_get_service(acct_svc); |
443 | - if (!strcmp(ctx->service_name, ag_service_get_name(service))) { |
444 | - ctx->account_service = g_object_ref(acct_svc); |
445 | - break; |
446 | - } |
447 | - } |
448 | - g_list_foreach(account_services, (GFunc)g_object_unref, NULL); |
449 | - g_list_free(account_services); |
450 | - |
451 | - if (ctx->account_service != NULL) { |
452 | - login_service(ctx); |
453 | - } |
454 | -} |
455 | - |
456 | -static void account_enabled_cb(AgManager *manager, guint account_id, void *user_data) { |
457 | - AuthContext *ctx = (AuthContext *)user_data; |
458 | - |
459 | - printf("enabled_cb account_id=%u\n", account_id); |
460 | - |
461 | - if (ctx->account_service != NULL && |
462 | - !ag_account_service_get_enabled(ctx->account_service)) { |
463 | - logout_service(ctx); |
464 | - } |
465 | - lookup_account_service(ctx); |
466 | -} |
467 | - |
468 | -static gboolean |
469 | -setup_context(void *user_data) { |
470 | - AuthContext *ctx = (AuthContext *)user_data; |
471 | - |
472 | - lookup_account_service(ctx); |
473 | - g_signal_connect(ctx->manager, "enabled-event", |
474 | - G_CALLBACK(account_enabled_cb), ctx); |
475 | - return FALSE; |
476 | -} |
477 | - |
478 | -AuthContext *watch_for_service(const char *service_name) { |
479 | - AuthContext *ctx = g_new0(AuthContext, 1); |
480 | - ctx->manager = ag_manager_new(); |
481 | - ctx->service_name = g_strdup(service_name); |
482 | - |
483 | - g_idle_add(setup_context, ctx); |
484 | - return ctx; |
485 | +#include "account-watcher.h" |
486 | + |
487 | +AccountWatcher *watch_for_services(void *array_of_service_names, int length) { |
488 | + /* Transfer service names to hash table */ |
489 | + GoString *service_names = (GoString *)array_of_service_names; |
490 | + GHashTable *services_to_watch = g_hash_table_new_full( |
491 | + g_str_hash, g_str_equal, g_free, NULL); |
492 | + int i; |
493 | + for (i = 0; i < length; i++) { |
494 | + g_hash_table_insert(services_to_watch, g_strdup(service_names[i].p), NULL); |
495 | + } |
496 | + |
497 | + AccountWatcher *watcher = account_watcher_new( |
498 | + services_to_watch, authCallback, NULL); |
499 | + g_hash_table_unref(services_to_watch); |
500 | + return watcher; |
501 | } |
502 | |
503 | === modified file 'accounts/accounts.go' |
504 | --- accounts/accounts.go 2014-07-11 13:44:43 +0000 |
505 | +++ accounts/accounts.go 2014-07-11 13:44:43 +0000 |
506 | @@ -22,49 +22,58 @@ |
507 | #include <stdlib.h> |
508 | #include <glib.h> |
509 | |
510 | -typedef struct _AuthContext AuthContext; |
511 | +typedef struct _AccountWatcher AccountWatcher; |
512 | |
513 | -AuthContext *watch_for_service(const char *service_name); |
514 | +AccountWatcher *watch_for_services(void *array_of_service_names, int length); |
515 | */ |
516 | import "C" |
517 | import "unsafe" |
518 | |
519 | type AuthData struct { |
520 | + AccountId uint |
521 | + ServiceName string |
522 | + Enabled bool |
523 | + |
524 | ClientId string |
525 | ClientSecret string |
526 | AccessToken string |
527 | + TokenSecret string |
528 | } |
529 | |
530 | var ( |
531 | mainLoop *C.GMainLoop |
532 | - authChannels = make(map[*C.AuthContext]chan<- AuthData) |
533 | + authChannels = make(map[*C.AccountWatcher]chan<- AuthData) |
534 | ) |
535 | |
536 | -func WatchForService(serviceName string) <-chan AuthData { |
537 | +func WatchForService(serviceNames... string) <-chan AuthData { |
538 | if mainLoop == nil { |
539 | mainLoop = C.g_main_loop_new(nil, C.gboolean(1)) |
540 | go C.g_main_loop_run(mainLoop) |
541 | } |
542 | |
543 | - cService := C.CString(serviceName) |
544 | - defer C.free(unsafe.Pointer(cService)) |
545 | - ctx := C.watch_for_service(cService) |
546 | + watcher := C.watch_for_services(unsafe.Pointer(&serviceNames[0]), C.int(len(serviceNames))) |
547 | |
548 | ch := make(chan AuthData) |
549 | - authChannels[ctx] = ch |
550 | + authChannels[watcher] = ch |
551 | return ch |
552 | } |
553 | |
554 | -//export authLogin |
555 | -func authLogin(user_data unsafe.Pointer, clientId *C.char, clientSecret *C.char, accessToken *C.char) { |
556 | - ctx := (*C.AuthContext)(user_data) |
557 | - ch := authChannels[ctx] |
558 | +//export authCallback |
559 | +func authCallback(watcher unsafe.Pointer, accountId C.uint, serviceName *C.char, enabled C.int, clientId, clientSecret, accessToken, tokenSecret *C.char, userData unsafe.Pointer) { |
560 | + // Ideally the first argument would be of type |
561 | + // *C.AccountWatcher, but that fails with Go 1.2. |
562 | + ch := authChannels[(*C.AccountWatcher)(watcher)] |
563 | if ch == nil { |
564 | // Log the error |
565 | return |
566 | } |
567 | |
568 | var data AuthData |
569 | + data.AccountId = uint(accountId) |
570 | + data.ServiceName = C.GoString(serviceName) |
571 | + if enabled != 0 { |
572 | + data.Enabled = true |
573 | + } |
574 | if clientId != nil { |
575 | data.ClientId = C.GoString(clientId) |
576 | } |
577 | @@ -74,5 +83,8 @@ |
578 | if accessToken != nil { |
579 | data.AccessToken = C.GoString(accessToken) |
580 | } |
581 | + if tokenSecret != nil { |
582 | + data.TokenSecret = C.GoString(tokenSecret) |
583 | + } |
584 | ch <- data |
585 | } |
586 | |
587 | === added directory 'cmd/account-watcher-test' |
588 | === added file 'cmd/account-watcher-test/main.go' |
589 | --- cmd/account-watcher-test/main.go 1970-01-01 00:00:00 +0000 |
590 | +++ cmd/account-watcher-test/main.go 2014-07-11 13:44:43 +0000 |
591 | @@ -0,0 +1,15 @@ |
592 | +package main |
593 | + |
594 | +import ( |
595 | + "fmt" |
596 | + "os" |
597 | + |
598 | + "launchpad.net/account-polld/accounts" |
599 | +) |
600 | + |
601 | +func main() { |
602 | + // Expects a list of service names as command line arguments |
603 | + for data := range accounts.WatchForService(os.Args[1:]...) { |
604 | + fmt.Printf("%#v\n", data) |
605 | + } |
606 | +} |
looks good to me, the only thing I'd forward fix for Poll is to use this
type AuthData struct
instead of that map type which seems to just be a complication.