Merge lp:~sergiusens/account-polld/qtcontact into lp:~ubuntu-push-hackers/account-polld/trunk
- qtcontact
- Merge into trunk
Proposed by
Sergio Schvezov
Status: | Superseded |
---|---|
Proposed branch: | lp:~sergiusens/account-polld/qtcontact |
Merge into: | lp:~ubuntu-push-hackers/account-polld/trunk |
Prerequisite: | lp:~sergiusens/account-polld/icon_fixes |
Diff against target: |
850 lines (+546/-94) 12 files modified
accounts/accounts.go (+0/-10) cmd/account-polld/account_manager.go (+47/-46) cmd/account-polld/main.go (+70/-37) cmd/qtcontact-test/main.go (+37/-0) debian/control (+3/-0) plugins/gmail/gmail.go (+5/-1) pollbus/bus.go (+94/-0) qtcontact/contacts.go (+68/-0) qtcontact/qtcontacts.cpp (+69/-0) qtcontact/qtcontacts.h (+32/-0) qtcontact/qtcontacts.hpp (+33/-0) qtcontact/qtcontacts.moc (+88/-0) |
To merge this branch: | bzr merge lp:~sergiusens/account-polld/qtcontact |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Manuel de la Peña (community) | Approve | ||
Roberto Alsina (community) | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email: mp+228969@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-08-25.
Commit message
Adding gmail avatar's through QtContacts
Description of the change
This seems to work standalone but falls short when integrated; I am thinking it's a Qt versus glib mainloop problem here.
I haven't done this in callback mode yet; not sure if it's worth it; please advice.
To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
review:
Approve
(continuous-integration)
Revision history for this message
Roberto Alsina (ralsina) : | # |
review:
Approve
- 39. By Sergio Schvezov
-
Merging poll
Revision history for this message
Manuel de la Peña (mandel) : | # |
review:
Approve
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'accounts/accounts.go' |
2 | --- accounts/accounts.go 2014-07-25 20:09:20 +0000 |
3 | +++ accounts/accounts.go 2014-08-25 14:55:20 +0000 |
4 | @@ -50,18 +50,10 @@ |
5 | } |
6 | |
7 | var ( |
8 | - mainLoopOnce sync.Once |
9 | authChannels = make(map[*C.AccountWatcher]chan<- AuthData) |
10 | authChannelsLock sync.Mutex |
11 | ) |
12 | |
13 | -func startMainLoop() { |
14 | - mainLoopOnce.Do(func() { |
15 | - mainLoop := C.g_main_loop_new(nil, C.gboolean(1)) |
16 | - go C.g_main_loop_run(mainLoop) |
17 | - }) |
18 | -} |
19 | - |
20 | // NewWatcher creates a new account watcher for the given service names |
21 | func NewWatcher(serviceType string) *Watcher { |
22 | w := new(Watcher) |
23 | @@ -75,8 +67,6 @@ |
24 | authChannels[w.watcher] = ch |
25 | authChannelsLock.Unlock() |
26 | |
27 | - startMainLoop() |
28 | - |
29 | return w |
30 | } |
31 | |
32 | |
33 | === modified file 'cmd/account-polld/account_manager.go' |
34 | --- cmd/account-polld/account_manager.go 2014-08-05 20:14:24 +0000 |
35 | +++ cmd/account-polld/account_manager.go 2014-08-25 14:55:20 +0000 |
36 | @@ -19,8 +19,6 @@ |
37 | |
38 | import ( |
39 | "log" |
40 | - "os" |
41 | - "strconv" |
42 | "time" |
43 | |
44 | "launchpad.net/account-polld/accounts" |
45 | @@ -29,62 +27,74 @@ |
46 | ) |
47 | |
48 | type AccountManager struct { |
49 | - watcher *accounts.Watcher |
50 | - authData accounts.AuthData |
51 | - plugin plugins.Plugin |
52 | - interval time.Duration |
53 | - postWatch chan *PostWatch |
54 | - authChan chan accounts.AuthData |
55 | + watcher *accounts.Watcher |
56 | + authData accounts.AuthData |
57 | + plugin plugins.Plugin |
58 | + interval time.Duration |
59 | + postWatch chan *PostWatch |
60 | + authChan chan accounts.AuthData |
61 | + doneChan chan error |
62 | + penaltyCount int |
63 | } |
64 | |
65 | var ( |
66 | - pollInterval = time.Duration(5 * time.Minute) |
67 | - maxInterval = time.Duration(20 * time.Minute) |
68 | + pollTimeout = time.Duration(30 * time.Second) |
69 | + bootstrapPollTimeout = time.Duration(5 * time.Minute) |
70 | + maxCounter = 4 |
71 | ) |
72 | |
73 | -func init() { |
74 | - if intervalEnv := os.Getenv("ACCOUNT_POLLD_POLL_INTERVAL_MINUTES"); intervalEnv != "" { |
75 | - if interval, err := strconv.ParseInt(intervalEnv, 0, 0); err == nil { |
76 | - pollInterval = time.Duration(interval) * time.Minute |
77 | - } |
78 | - } |
79 | -} |
80 | - |
81 | func NewAccountManager(watcher *accounts.Watcher, postWatch chan *PostWatch, plugin plugins.Plugin) *AccountManager { |
82 | return &AccountManager{ |
83 | watcher: watcher, |
84 | plugin: plugin, |
85 | - interval: pollInterval, |
86 | postWatch: postWatch, |
87 | authChan: make(chan accounts.AuthData, 1), |
88 | + doneChan: make(chan error, 1), |
89 | } |
90 | } |
91 | |
92 | func (a *AccountManager) Delete() { |
93 | close(a.authChan) |
94 | + close(a.doneChan) |
95 | } |
96 | |
97 | -func (a *AccountManager) Loop() { |
98 | - var ok bool |
99 | - if a.authData, ok = <-a.authChan; !ok { |
100 | +func (a *AccountManager) Poll(bootstrap bool) { |
101 | + if !a.authData.Enabled { |
102 | + var ok bool |
103 | + if a.authData, ok = <-a.authChan; !ok { |
104 | + log.Println("Account", a.authData.AccountId, "no longer enabled") |
105 | + return |
106 | + } |
107 | + } |
108 | + if a.penaltyCount > 0 { |
109 | + log.Printf("Leaving poll for account %d as penaly count is %d", a.authData.AccountId, a.penaltyCount) |
110 | + a.penaltyCount-- |
111 | return |
112 | } |
113 | - // This is an initial out of loop poll |
114 | - a.poll() |
115 | -L: |
116 | - for { |
117 | - log.Println("Next poll set to", a.interval, "for account", a.authData.AccountId) |
118 | - select { |
119 | - case <-time.After(a.interval): |
120 | - a.poll() |
121 | - case a.authData, ok = <-a.authChan: |
122 | - if !ok { |
123 | - break L |
124 | + timeout := pollTimeout |
125 | + if bootstrap { |
126 | + timeout = bootstrapPollTimeout |
127 | + } |
128 | + |
129 | + log.Printf("Starting poll for account %d", a.authData.AccountId) |
130 | + go a.poll() |
131 | + |
132 | + select { |
133 | + case <-time.After(timeout): |
134 | + log.Println("Poll for account", a.authData.AccountId, "has timed out out after", timeout) |
135 | + a.penaltyCount++ |
136 | + case err := <-a.doneChan: |
137 | + if err == nil { |
138 | + log.Println("Poll for account", a.authData.AccountId, "was successful") |
139 | + a.penaltyCount = 0 |
140 | + } else { |
141 | + log.Println("Poll for account", a.authData.AccountId, "has failed:", err) |
142 | + if a.penaltyCount < maxCounter { |
143 | + a.penaltyCount++ |
144 | } |
145 | - a.poll() |
146 | } |
147 | } |
148 | - log.Printf("Ending poll loop for account %d", a.authData.AccountId) |
149 | + log.Printf("Ending poll for account %d", a.authData.AccountId) |
150 | } |
151 | |
152 | func (a *AccountManager) poll() { |
153 | @@ -96,11 +106,6 @@ |
154 | return |
155 | } |
156 | |
157 | - if !a.authData.Enabled { |
158 | - log.Println("Account", a.authData.AccountId, "no longer enabled") |
159 | - return |
160 | - } |
161 | - |
162 | if a.authData.Error != nil { |
163 | log.Println("Account", a.authData.AccountId, "failed to authenticate:", a.authData.Error) |
164 | return |
165 | @@ -108,10 +113,6 @@ |
166 | |
167 | if n, err := a.plugin.Poll(&a.authData); err != nil { |
168 | log.Print("Error while polling ", a.authData.AccountId, ": ", err) |
169 | - // penalizing the next poll |
170 | - if a.interval.Minutes() < maxInterval.Minutes() { |
171 | - a.interval += pollInterval |
172 | - } |
173 | |
174 | // If the error indicates that the authentication |
175 | // token has expired, request reauthentication and |
176 | @@ -120,13 +121,13 @@ |
177 | a.watcher.Refresh(a.authData.AccountId) |
178 | a.authData.Enabled = false |
179 | } |
180 | + a.doneChan <- err |
181 | } else { |
182 | log.Println("Account", a.authData.AccountId, "has", len(n), "updates to report") |
183 | if len(n) > 0 { |
184 | a.postWatch <- &PostWatch{messages: n, appId: a.plugin.ApplicationId()} |
185 | } |
186 | - // on success we reset the timeout to the default interval |
187 | - a.interval = pollInterval |
188 | + a.doneChan <- nil |
189 | } |
190 | } |
191 | |
192 | |
193 | === modified file 'cmd/account-polld/main.go' |
194 | --- cmd/account-polld/main.go 2014-08-08 20:11:14 +0000 |
195 | +++ cmd/account-polld/main.go 2014-08-25 14:55:20 +0000 |
196 | @@ -21,6 +21,7 @@ |
197 | "encoding/json" |
198 | "fmt" |
199 | "strings" |
200 | + "sync" |
201 | |
202 | "log" |
203 | |
204 | @@ -30,6 +31,8 @@ |
205 | "launchpad.net/account-polld/plugins/facebook" |
206 | "launchpad.net/account-polld/plugins/gmail" |
207 | "launchpad.net/account-polld/plugins/twitter" |
208 | + "launchpad.net/account-polld/pollbus" |
209 | + "launchpad.net/account-polld/qtcontact" |
210 | "launchpad.net/go-dbus/v1" |
211 | ) |
212 | |
213 | @@ -52,7 +55,16 @@ |
214 | POSTAL_OBJECT_PATH_PART = "/com/ubuntu/Postal/" |
215 | ) |
216 | |
217 | +var mainLoopOnce sync.Once |
218 | + |
219 | func init() { |
220 | + startMainLoop() |
221 | +} |
222 | + |
223 | +func startMainLoop() { |
224 | + mainLoopOnce.Do(func() { |
225 | + go qtcontact.MainLoopStart() |
226 | + }) |
227 | } |
228 | |
229 | func main() { |
230 | @@ -64,52 +76,73 @@ |
231 | gettext.Textdomain("account-polld") |
232 | gettext.BindTextdomain("account-polld", "/usr/share/locale") |
233 | |
234 | - if bus, err := dbus.Connect(dbus.SessionBus); err != nil { |
235 | + bus, err := dbus.Connect(dbus.SessionBus) |
236 | + if err != nil { |
237 | log.Fatal("Cannot connect to bus", err) |
238 | - } else { |
239 | - go postOffice(bus, postWatch) |
240 | - } |
241 | - |
242 | - go monitorAccounts(postWatch) |
243 | + } |
244 | + |
245 | + pollBus := pollbus.New(bus) |
246 | + go postOffice(bus, postWatch) |
247 | + go monitorAccounts(postWatch, pollBus) |
248 | + |
249 | + if err := pollBus.Init(); err != nil { |
250 | + log.Fatal("Issue while setting up the poll bus:", err) |
251 | + } |
252 | |
253 | done := make(chan bool) |
254 | <-done |
255 | } |
256 | |
257 | -func monitorAccounts(postWatch chan *PostWatch) { |
258 | +func monitorAccounts(postWatch chan *PostWatch, pollBus *pollbus.PollBus) { |
259 | watcher := accounts.NewWatcher(SERVICETYPE_POLL) |
260 | mgr := make(map[uint]*AccountManager) |
261 | + |
262 | L: |
263 | - for data := range watcher.C { |
264 | - if account, ok := mgr[data.AccountId]; ok { |
265 | - if data.Enabled { |
266 | - log.Println("New account data for existing account with id", data.AccountId) |
267 | - account.updateAuthData(data) |
268 | - } else { |
269 | - account.Delete() |
270 | - delete(mgr, data.AccountId) |
271 | - } |
272 | - } else if data.Enabled { |
273 | - var plugin plugins.Plugin |
274 | - switch data.ServiceName { |
275 | - case SERVICENAME_GMAIL: |
276 | - log.Println("Creating account with id", data.AccountId, "for", data.ServiceName) |
277 | - plugin = gmail.New(data.AccountId) |
278 | - case SERVICENAME_FACEBOOK: |
279 | - // This is just stubbed until the plugin exists. |
280 | - log.Println("Creating account with id", data.AccountId, "for", data.ServiceName) |
281 | - plugin = facebook.New(data.AccountId) |
282 | - case SERVICENAME_TWITTER: |
283 | - // This is just stubbed until the plugin exists. |
284 | - log.Println("Creating account with id", data.AccountId, "for", data.ServiceName) |
285 | - plugin = twitter.New() |
286 | - default: |
287 | - log.Println("Unhandled account with id", data.AccountId, "for", data.ServiceName) |
288 | - continue L |
289 | - } |
290 | - mgr[data.AccountId] = NewAccountManager(watcher, postWatch, plugin) |
291 | - mgr[data.AccountId].updateAuthData(data) |
292 | - go mgr[data.AccountId].Loop() |
293 | + for { |
294 | + select { |
295 | + case data := <-watcher.C: |
296 | + if account, ok := mgr[data.AccountId]; ok { |
297 | + if data.Enabled { |
298 | + log.Println("New account data for existing account with id", data.AccountId) |
299 | + account.updateAuthData(data) |
300 | + } else { |
301 | + account.Delete() |
302 | + delete(mgr, data.AccountId) |
303 | + } |
304 | + } else if data.Enabled { |
305 | + var plugin plugins.Plugin |
306 | + switch data.ServiceName { |
307 | + case SERVICENAME_GMAIL: |
308 | + log.Println("Creating account with id", data.AccountId, "for", data.ServiceName) |
309 | + plugin = gmail.New(data.AccountId) |
310 | + case SERVICENAME_FACEBOOK: |
311 | + // This is just stubbed until the plugin exists. |
312 | + log.Println("Creating account with id", data.AccountId, "for", data.ServiceName) |
313 | + plugin = facebook.New(data.AccountId) |
314 | + case SERVICENAME_TWITTER: |
315 | + // This is just stubbed until the plugin exists. |
316 | + log.Println("Creating account with id", data.AccountId, "for", data.ServiceName) |
317 | + plugin = twitter.New() |
318 | + default: |
319 | + log.Println("Unhandled account with id", data.AccountId, "for", data.ServiceName) |
320 | + continue L |
321 | + } |
322 | + mgr[data.AccountId] = NewAccountManager(watcher, postWatch, plugin) |
323 | + mgr[data.AccountId].updateAuthData(data) |
324 | + mgr[data.AccountId].Poll(true) |
325 | + } |
326 | + case <-pollBus.PollChan: |
327 | + var wg sync.WaitGroup |
328 | + for _, v := range mgr { |
329 | + wg.Add(1) |
330 | + poll := v.Poll |
331 | + go func() { |
332 | + defer wg.Done() |
333 | + poll(false) |
334 | + }() |
335 | + } |
336 | + wg.Wait() |
337 | + pollBus.SignalDone() |
338 | } |
339 | } |
340 | } |
341 | |
342 | === added directory 'cmd/qtcontact-test' |
343 | === added file 'cmd/qtcontact-test/main.go' |
344 | --- cmd/qtcontact-test/main.go 1970-01-01 00:00:00 +0000 |
345 | +++ cmd/qtcontact-test/main.go 2014-08-25 14:55:20 +0000 |
346 | @@ -0,0 +1,37 @@ |
347 | +/* |
348 | + Copyright 2014 Canonical Ltd. |
349 | + Authors: Sergio Schvezov <sergio.schvezov@canonical.com> |
350 | + |
351 | + This program is free software: you can redistribute it and/or modify it |
352 | + under the terms of the GNU General Public License version 3, as published |
353 | + by the Free Software Foundation. |
354 | + |
355 | + This program is distributed in the hope that it will be useful, but |
356 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
357 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
358 | + PURPOSE. See the GNU General Public License for more details. |
359 | + |
360 | + You should have received a copy of the GNU General Public License along |
361 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
362 | +*/ |
363 | + |
364 | +package main |
365 | + |
366 | +import ( |
367 | + "fmt" |
368 | + "os" |
369 | + |
370 | + "launchpad.net/account-polld/qtcontact" |
371 | +) |
372 | + |
373 | +func main() { |
374 | + qtcontact.MainLoopStart() |
375 | + |
376 | + if len(os.Args) != 2 { |
377 | + fmt.Println("usage:", os.Args[0], "[email address]") |
378 | + os.Exit(1) |
379 | + } |
380 | + |
381 | + path := qtcontact.GetAvatar(os.Args[1]) |
382 | + fmt.Println("Avatar found:", path) |
383 | +} |
384 | |
385 | === modified file 'debian/control' |
386 | --- debian/control 2014-07-31 18:08:37 +0000 |
387 | +++ debian/control 2014-08-25 14:55:20 +0000 |
388 | @@ -13,6 +13,9 @@ |
389 | libaccounts-glib-dev, |
390 | libclick-0.4-dev, |
391 | libsignon-glib-dev, |
392 | + qt5-default, |
393 | + qtbase5-dev, |
394 | + qtpim5-dev, |
395 | Standards-Version: 3.9.5 |
396 | Homepage: https://launchpad.net/account-polld |
397 | Vcs-Browser: http://bazaar.launchpad.net/~phablet-team/account-polld/trunk/files |
398 | |
399 | === modified file 'debian/rules' (properties changed: +x to -x) |
400 | === modified file 'plugins/gmail/gmail.go' |
401 | --- plugins/gmail/gmail.go 2014-08-08 20:11:14 +0000 |
402 | +++ plugins/gmail/gmail.go 2014-08-25 14:55:20 +0000 |
403 | @@ -32,6 +32,7 @@ |
404 | "launchpad.net/account-polld/accounts" |
405 | "launchpad.net/account-polld/gettext" |
406 | "launchpad.net/account-polld/plugins" |
407 | + "launchpad.net/account-polld/qtcontact" |
408 | ) |
409 | |
410 | const ( |
411 | @@ -141,9 +142,12 @@ |
412 | hdr := msg.Payload.mapHeaders() |
413 | |
414 | from := hdr[hdrFROM] |
415 | + var avatarPath string |
416 | + |
417 | if emailAddress, err := mail.ParseAddress(hdr[hdrFROM]); err == nil { |
418 | if emailAddress.Name != "" { |
419 | from = emailAddress.Name |
420 | + avatarPath = qtcontact.GetAvatar(emailAddress.Address) |
421 | } |
422 | } |
423 | msgStamp := hdr.getTimestamp() |
424 | @@ -159,7 +163,7 @@ |
425 | // fmt with label personal and threadId |
426 | action := fmt.Sprintf(gmailDispatchUrl, "personal", msg.ThreadId) |
427 | epoch := hdr.getEpoch() |
428 | - pushMsgMap[msg.ThreadId] = *plugins.NewStandardPushMessage(summary, body, action, "", epoch) |
429 | + pushMsgMap[msg.ThreadId] = *plugins.NewStandardPushMessage(summary, body, action, avatarPath, epoch) |
430 | } else { |
431 | log.Print("gmail plugin ", p.accountId, ": skipping message id ", msg.Id, " with date ", msgStamp, " older than ", timeDelta) |
432 | } |
433 | |
434 | === added directory 'pollbus' |
435 | === added file 'pollbus/bus.go' |
436 | --- pollbus/bus.go 1970-01-01 00:00:00 +0000 |
437 | +++ pollbus/bus.go 2014-08-25 14:55:20 +0000 |
438 | @@ -0,0 +1,94 @@ |
439 | +/* |
440 | + Copyright 2014 Canonical Ltd. |
441 | + Authors: Sergio Schvezov <sergio.schvezov@canonical.com> |
442 | + |
443 | + This program is free software: you can redistribute it and/or modify it |
444 | + under the terms of the GNU General Public License version 3, as published |
445 | + by the Free Software Foundation. |
446 | + |
447 | + This program is distributed in the hope that it will be useful, but |
448 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
449 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
450 | + PURPOSE. See the GNU General Public License for more details. |
451 | + |
452 | + You should have received a copy of the GNU General Public License along |
453 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
454 | +*/ |
455 | + |
456 | +package pollbus |
457 | + |
458 | +import ( |
459 | + "fmt" |
460 | + "runtime" |
461 | + |
462 | + "log" |
463 | + |
464 | + "launchpad.net/go-dbus/v1" |
465 | +) |
466 | + |
467 | +const ( |
468 | + busInterface = "com.ubuntu.AccountPolld" |
469 | + busPath = "/com/ubuntu/AccountPolld" |
470 | + busName = "com.ubuntu.AccountPolld" |
471 | +) |
472 | + |
473 | +type PollBus struct { |
474 | + conn *dbus.Connection |
475 | + msgChan chan *dbus.Message |
476 | + PollChan chan bool |
477 | +} |
478 | + |
479 | +func New(conn *dbus.Connection) *PollBus { |
480 | + p := &PollBus{ |
481 | + conn: conn, |
482 | + msgChan: make(chan *dbus.Message), |
483 | + PollChan: make(chan bool), |
484 | + } |
485 | + runtime.SetFinalizer(p, clean) |
486 | + return p |
487 | +} |
488 | + |
489 | +func clean(p *PollBus) { |
490 | + p.conn.UnregisterObjectPath(busPath) |
491 | + close(p.msgChan) |
492 | + close(p.PollChan) |
493 | +} |
494 | + |
495 | +func (p *PollBus) Init() error { |
496 | + name := p.conn.RequestName(busName, dbus.NameFlagDoNotQueue) |
497 | + err := <-name.C |
498 | + if err != nil { |
499 | + return fmt.Errorf("bus name could not be take: %s", err) |
500 | + } |
501 | + |
502 | + go p.watchMethodCalls() |
503 | + p.conn.RegisterObjectPath(busPath, p.msgChan) |
504 | + |
505 | + return nil |
506 | +} |
507 | + |
508 | +func (p *PollBus) SignalDone() error { |
509 | + signal := dbus.NewSignalMessage(busPath, busInterface, "Done") |
510 | + if err := p.conn.Send(signal); err != nil { |
511 | + return err |
512 | + } |
513 | + return nil |
514 | +} |
515 | + |
516 | +func (p *PollBus) watchMethodCalls() { |
517 | + for msg := range p.msgChan { |
518 | + var reply *dbus.Message |
519 | + switch { |
520 | + case msg.Interface == busInterface && msg.Member == "Poll": |
521 | + log.Println("Received Poll()") |
522 | + p.PollChan <- true |
523 | + reply = dbus.NewMethodReturnMessage(msg) |
524 | + default: |
525 | + log.Println("Received unkown method call on", msg.Interface, msg.Member) |
526 | + reply = dbus.NewErrorMessage(msg, "org.freedesktop.DBus.Error.UnknownMethod", "Unknown method") |
527 | + } |
528 | + if err := p.conn.Send(reply); err != nil { |
529 | + log.Println("Could not send reply:", err) |
530 | + } |
531 | + } |
532 | +} |
533 | |
534 | === added directory 'qtcontact' |
535 | === added file 'qtcontact/contacts.go' |
536 | --- qtcontact/contacts.go 1970-01-01 00:00:00 +0000 |
537 | +++ qtcontact/contacts.go 2014-08-25 14:55:20 +0000 |
538 | @@ -0,0 +1,68 @@ |
539 | +/* |
540 | + Copyright 2014 Canonical Ltd. |
541 | + Authors: Sergio Schvezov <sergio.schvezov@canonical.com> |
542 | + |
543 | + This program is free software: you can redistribute it and/or modify it |
544 | + under the terms of the GNU General Public License version 3, as published |
545 | + by the Free Software Foundation. |
546 | + |
547 | + This program is distributed in the hope that it will be useful, but |
548 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
549 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
550 | + PURPOSE. See the GNU General Public License for more details. |
551 | + |
552 | + You should have received a copy of the GNU General Public License along |
553 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
554 | +*/ |
555 | + |
556 | +package qtcontact |
557 | + |
558 | +// #cgo CXXFLAGS: -std=c++0x -pedantic-errors -Wall -fno-strict-aliasing -I/usr/share/c++/4.8 |
559 | +// #cgo LDFLAGS: -lstdc++ |
560 | +// #cgo pkg-config: Qt5Core Qt5Contacts |
561 | +// #include "qtcontacts.h" |
562 | +import "C" |
563 | + |
564 | +import ( |
565 | + "log" |
566 | + "sync" |
567 | + "time" |
568 | +) |
569 | + |
570 | +var ( |
571 | + avatarPathChan chan string |
572 | + m sync.Mutex |
573 | +) |
574 | + |
575 | +//export callback |
576 | +func callback(path *C.char) { |
577 | + avatarPathChan <- C.GoString(path) |
578 | +} |
579 | + |
580 | +func MainLoopStart() { |
581 | + go C.mainloopStart() |
582 | +} |
583 | + |
584 | +// GetAvatar retrieves an avatar path for the specified email |
585 | +// address. Multiple calls to this func will be in sync |
586 | +func GetAvatar(emailAddress string) string { |
587 | + if emailAddress == "" { |
588 | + return "" |
589 | + } |
590 | + |
591 | + m.Lock() |
592 | + defer m.Unlock() |
593 | + |
594 | + avatarPathChan = make(chan string, 1) |
595 | + defer close(avatarPathChan) |
596 | + |
597 | + C.getAvatar(C.CString(emailAddress)) |
598 | + |
599 | + select { |
600 | + case <-time.After(3 * time.Second): |
601 | + log.Println("Timeout while seeking avatar for", emailAddress) |
602 | + return "" |
603 | + case path := <-avatarPathChan: |
604 | + return path |
605 | + } |
606 | +} |
607 | |
608 | === added file 'qtcontact/qtcontacts.cpp' |
609 | --- qtcontact/qtcontacts.cpp 1970-01-01 00:00:00 +0000 |
610 | +++ qtcontact/qtcontacts.cpp 2014-08-25 14:55:20 +0000 |
611 | @@ -0,0 +1,69 @@ |
612 | +/* |
613 | + Copyright 2014 Canonical Ltd. |
614 | + Authors: Sergio Schvezov <sergio.schvezov@canonical.com> |
615 | + |
616 | + This program is free software: you can redistribute it and/or modify it |
617 | + under the terms of the GNU General Public License version 3, as published |
618 | + by the Free Software Foundation. |
619 | + |
620 | + This program is distributed in the hope that it will be useful, but |
621 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
622 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
623 | + PURPOSE. See the GNU General Public License for more details. |
624 | + |
625 | + You should have received a copy of the GNU General Public License along |
626 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
627 | +*/ |
628 | + |
629 | +#include <QContactManager> |
630 | +#include <QContactFilter> |
631 | +#include <QContactEmailAddress> |
632 | +#include <QContactDetailFilter> |
633 | +#include <QContactManager> |
634 | +#include <QContactAvatar> |
635 | +#include <QCoreApplication> |
636 | +#include <QScopedPointer> |
637 | +#include <QTimer> |
638 | +#include <thread> |
639 | + |
640 | +#include "qtcontacts.h" |
641 | +#include "qtcontacts.hpp" |
642 | +#include "qtcontacts.moc" |
643 | + |
644 | +#ifdef __cplusplus |
645 | +extern "C" { |
646 | +#include "_cgo_export.h" |
647 | +} |
648 | +#endif |
649 | + |
650 | +QTCONTACTS_USE_NAMESPACE |
651 | + |
652 | +int mainloopStart() { |
653 | + static char empty[1] = {0}; |
654 | + static char *argv[] = {empty, empty, empty}; |
655 | + static int argc = 1; |
656 | + |
657 | + QCoreApplication mApp(argc, argv); |
658 | + return mApp.exec(); |
659 | +} |
660 | + |
661 | +void getAvatar(char *email) { |
662 | + QScopedPointer<Avatar> avatar(new Avatar()); |
663 | + avatar->retrieveThumbnail(QString(email)); |
664 | +} |
665 | + |
666 | +void Avatar::retrieveThumbnail(const QString& email) { |
667 | + QString avatar; |
668 | + |
669 | + QContactManager manager ("galera"); |
670 | + QContactDetailFilter filter(QContactEmailAddress::match(email)); |
671 | + QList<QContact> contacts = manager.contacts(filter); |
672 | + if(contacts.size() > 0) { |
673 | + avatar = contacts[0].detail<QContactAvatar>().imageUrl().path(); |
674 | + } |
675 | + |
676 | + QByteArray byteArray = avatar.toUtf8(); |
677 | + char* cString = byteArray.data(); |
678 | + |
679 | + callback(cString); |
680 | +} |
681 | |
682 | === added file 'qtcontact/qtcontacts.h' |
683 | --- qtcontact/qtcontacts.h 1970-01-01 00:00:00 +0000 |
684 | +++ qtcontact/qtcontacts.h 2014-08-25 14:55:20 +0000 |
685 | @@ -0,0 +1,32 @@ |
686 | +/* |
687 | + Copyright 2014 Canonical Ltd. |
688 | + Authors: Sergio Schvezov <sergio.schvezov@canonical.com> |
689 | + |
690 | + This program is free software: you can redistribute it and/or modify it |
691 | + under the terms of the GNU General Public License version 3, as published |
692 | + by the Free Software Foundation. |
693 | + |
694 | + This program is distributed in the hope that it will be useful, but |
695 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
696 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
697 | + PURPOSE. See the GNU General Public License for more details. |
698 | + |
699 | + You should have received a copy of the GNU General Public License along |
700 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
701 | +*/ |
702 | + |
703 | +#ifndef __QTCONTACTS_GOLANG__ |
704 | +#define __QTCONTACTS_GOLANG__ |
705 | + |
706 | +#ifdef __cplusplus |
707 | +extern "C" { |
708 | +#endif |
709 | + |
710 | +void getAvatar(char *); |
711 | +int mainloopStart(); |
712 | + |
713 | +#ifdef __cplusplus |
714 | +} |
715 | +#endif |
716 | + |
717 | +#endif |
718 | |
719 | === added file 'qtcontact/qtcontacts.hpp' |
720 | --- qtcontact/qtcontacts.hpp 1970-01-01 00:00:00 +0000 |
721 | +++ qtcontact/qtcontacts.hpp 2014-08-25 14:55:20 +0000 |
722 | @@ -0,0 +1,33 @@ |
723 | +/* |
724 | + Copyright 2014 Canonical Ltd. |
725 | + Authors: Sergio Schvezov <sergio.schvezov@canonical.com> |
726 | + |
727 | + This program is free software: you can redistribute it and/or modify it |
728 | + under the terms of the GNU General Public License version 3, as published |
729 | + by the Free Software Foundation. |
730 | + |
731 | + This program is distributed in the hope that it will be useful, but |
732 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
733 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
734 | + PURPOSE. See the GNU General Public License for more details. |
735 | + |
736 | + You should have received a copy of the GNU General Public License along |
737 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
738 | +*/ |
739 | + |
740 | +#ifndef __QTCONTACTS_HPP_ |
741 | +#define __QTCONTACTS_HPP_ |
742 | + |
743 | +#include <QObject> |
744 | +#include <QSignalMapper> |
745 | + |
746 | +class Avatar : QObject { |
747 | + Q_OBJECT |
748 | + public: |
749 | + explicit Avatar(QObject* parent=0) |
750 | + : QObject(parent) { |
751 | + } |
752 | + void retrieveThumbnail(const QString& email); |
753 | +}; |
754 | + |
755 | +#endif |
756 | |
757 | === added file 'qtcontact/qtcontacts.moc' |
758 | --- qtcontact/qtcontacts.moc 1970-01-01 00:00:00 +0000 |
759 | +++ qtcontact/qtcontacts.moc 2014-08-25 14:55:20 +0000 |
760 | @@ -0,0 +1,88 @@ |
761 | +/**************************************************************************** |
762 | +** Meta object code from reading C++ file 'qtcontacts.hpp' |
763 | +** |
764 | +** Created by: The Qt Meta Object Compiler version 67 (Qt 5.2.1) |
765 | +** |
766 | +** WARNING! All changes made in this file will be lost! |
767 | +*****************************************************************************/ |
768 | + |
769 | +#include "qtcontacts.hpp" |
770 | +#include <QtCore/qbytearray.h> |
771 | +#include <QtCore/qmetatype.h> |
772 | +#if !defined(Q_MOC_OUTPUT_REVISION) |
773 | +#error "The header file 'qtcontacts.hpp' doesn't include <QObject>." |
774 | +#elif Q_MOC_OUTPUT_REVISION != 67 |
775 | +#error "This file was generated using the moc from 5.2.1. It" |
776 | +#error "cannot be used with the include files from this version of Qt." |
777 | +#error "(The moc has changed too much.)" |
778 | +#endif |
779 | + |
780 | +QT_BEGIN_MOC_NAMESPACE |
781 | +struct qt_meta_stringdata_Avatar_t { |
782 | + QByteArrayData data[1]; |
783 | + char stringdata[8]; |
784 | +}; |
785 | +#define QT_MOC_LITERAL(idx, ofs, len) \ |
786 | + Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ |
787 | + offsetof(qt_meta_stringdata_Avatar_t, stringdata) + ofs \ |
788 | + - idx * sizeof(QByteArrayData) \ |
789 | + ) |
790 | +static const qt_meta_stringdata_Avatar_t qt_meta_stringdata_Avatar = { |
791 | + { |
792 | +QT_MOC_LITERAL(0, 0, 6) |
793 | + }, |
794 | + "Avatar\0" |
795 | +}; |
796 | +#undef QT_MOC_LITERAL |
797 | + |
798 | +static const uint qt_meta_data_Avatar[] = { |
799 | + |
800 | + // content: |
801 | + 7, // revision |
802 | + 0, // classname |
803 | + 0, 0, // classinfo |
804 | + 0, 0, // methods |
805 | + 0, 0, // properties |
806 | + 0, 0, // enums/sets |
807 | + 0, 0, // constructors |
808 | + 0, // flags |
809 | + 0, // signalCount |
810 | + |
811 | + 0 // eod |
812 | +}; |
813 | + |
814 | +void Avatar::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) |
815 | +{ |
816 | + Q_UNUSED(_o); |
817 | + Q_UNUSED(_id); |
818 | + Q_UNUSED(_c); |
819 | + Q_UNUSED(_a); |
820 | +} |
821 | + |
822 | +const QMetaObject Avatar::staticMetaObject = { |
823 | + { &QObject::staticMetaObject, qt_meta_stringdata_Avatar.data, |
824 | + qt_meta_data_Avatar, qt_static_metacall, 0, 0} |
825 | +}; |
826 | + |
827 | + |
828 | +const QMetaObject *Avatar::metaObject() const |
829 | +{ |
830 | + return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; |
831 | +} |
832 | + |
833 | +void *Avatar::qt_metacast(const char *_clname) |
834 | +{ |
835 | + if (!_clname) return 0; |
836 | + if (!strcmp(_clname, qt_meta_stringdata_Avatar.stringdata)) |
837 | + return static_cast<void*>(const_cast< Avatar*>(this)); |
838 | + return QObject::qt_metacast(_clname); |
839 | +} |
840 | + |
841 | +int Avatar::qt_metacall(QMetaObject::Call _c, int _id, void **_a) |
842 | +{ |
843 | + _id = QObject::qt_metacall(_c, _id, _a); |
844 | + if (_id < 0) |
845 | + return _id; |
846 | + return _id; |
847 | +} |
848 | +QT_END_MOC_NAMESPACE |
849 | |
850 | === modified file 'update_translations.sh' (properties changed: +x to -x) |
PASSED: Continuous integration, rev:38 jenkins. qa.ubuntu. com/job/ account- polld-ci/ 72/ jenkins. qa.ubuntu. com/job/ account- polld-utopic- amd64-ci/ 72 jenkins. qa.ubuntu. com/job/ account- polld-utopic- armhf-ci/ 72 jenkins. qa.ubuntu. com/job/ account- polld-utopic- armhf-ci/ 72/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ account- polld-utopic- i386-ci/ 72
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/account- polld-ci/ 72/rebuild
http://