Merge lp:~sergiusens/nuntium/message-api into lp:nuntium

Proposed by Sergio Schvezov
Status: Merged
Approved by: Manuel de la Peña
Approved revision: 64
Merged at revision: 47
Proposed branch: lp:~sergiusens/nuntium/message-api
Merge into: lp:nuntium
Prerequisite: lp:~sergiusens/nuntium/getservices
Diff against target: 412 lines (+247/-23)
5 files modified
mediator.go (+21/-8)
storage/storage.go (+18/-0)
telepathy/const.go (+10/-0)
telepathy/message.go (+107/-0)
telepathy/service.go (+91/-15)
To merge this branch: bzr merge lp:~sergiusens/nuntium/message-api
Reviewer Review Type Date Requested Status
Manuel de la Peña (community) Approve
Review via email: mp+225147@code.launchpad.net

Commit message

Adding a minimal telepathy message interface

To post a comment you must log in.
Revision history for this message
Manuel de la Peña (mandel) :
review: Needs Fixing
lp:~sergiusens/nuntium/message-api updated
63. By Sergio Schvezov

Merged getservices into message-api.

64. By Sergio Schvezov

Using the sort package to find valid status values

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

Fixed, comments inline

Revision history for this message
Manuel de la Peña (mandel) :
review: Approve
lp:~sergiusens/nuntium/message-api updated
65. By Sergio Schvezov

Adding missing return

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mediator.go'
2--- mediator.go 2014-07-02 21:07:14 +0000
3+++ mediator.go 2014-07-02 21:07:14 +0000
4@@ -41,7 +41,7 @@
5 NewMSendReq chan *mms.MSendReq
6 NewMRetrieveConfFile chan string
7 NewMNotifyRespIndFile chan string
8- NewMSendReqFile chan string
9+ NewMSendReqFile chan struct{ filePath, uuid string }
10 outMessage chan *telepathy.OutgoingMessage
11 terminate chan bool
12 }
13@@ -62,7 +62,7 @@
14 mediator.NewMNotifyRespInd = make(chan *mms.MNotifyRespInd)
15 mediator.NewMNotifyRespIndFile = make(chan string)
16 mediator.NewMSendReq = make(chan *mms.MSendReq)
17- mediator.NewMSendReqFile = make(chan string)
18+ mediator.NewMSendReqFile = make(chan struct{ filePath, uuid string })
19 mediator.outMessage = make(chan *telepathy.OutgoingMessage)
20 mediator.terminate = make(chan bool)
21 return mediator
22@@ -100,8 +100,8 @@
23 go mediator.handleOutgoingMessage(msg)
24 case mSendReq := <-mediator.NewMSendReq:
25 go mediator.handleMSendReq(mSendReq)
26- case mSendReqFilePath := <-mediator.NewMSendReqFile:
27- go mediator.sendMSendReq(mSendReqFilePath)
28+ case mSendReqFile := <-mediator.NewMSendReqFile:
29+ go mediator.sendMSendReq(mSendReqFile.filePath, mSendReqFile.uuid)
30 case id := <-mediator.modem.IdentityAdded:
31 var err error
32 mediator.telepathyService, err = mmsManager.AddService(id, mediator.outMessage, useDeliveryReports)
33@@ -258,8 +258,10 @@
34 cts = append(cts, ct)
35 }
36 mSendReq := mms.NewMSendReq(msg.Recipients, cts)
37- //TODO
38- mediator.telepathyService.ReplySendMessage(msg.Reply, mSendReq.UUID)
39+ if _, err := mediator.telepathyService.ReplySendMessage(msg.Reply, mSendReq.UUID); err != nil {
40+ log.Print(err)
41+ return
42+ }
43 mediator.NewMSendReq <- mSendReq
44 }
45
46@@ -274,17 +276,28 @@
47 enc := mms.NewEncoder(f)
48 if err := enc.Encode(mSendReq); err != nil {
49 log.Print("Unable to encode m-send.req for ", mSendReq.UUID)
50+ if err := mediator.telepathyService.MessageStatusChanged(mSendReq.UUID, telepathy.PERMANENT_ERROR); err != nil {
51+ log.Println(err)
52+ }
53 return
54 }
55 filePath := f.Name()
56 log.Printf("Created %s to handle m-send.req for %s", filePath, mSendReq.UUID)
57- mediator.NewMSendReqFile <- filePath
58+ mediator.sendMSendReq(filePath, mSendReq.UUID)
59 }
60
61-func (mediator *Mediator) sendMSendReq(mSendReqFile string) {
62+func (mediator *Mediator) sendMSendReq(mSendReqFile, uuid string) {
63 defer os.Remove(mSendReqFile)
64+ defer mediator.telepathyService.MessageDestroy(uuid)
65 if err := mediator.uploadFile(mSendReqFile); err != nil {
66+ if err := mediator.telepathyService.MessageStatusChanged(uuid, telepathy.TRANSIENT_ERROR); err != nil {
67+ log.Println(err)
68+ }
69 log.Printf("Cannot upload m-send.req encoded file %s to message center: %s", mSendReqFile, err)
70+ return
71+ }
72+ if err := mediator.telepathyService.MessageStatusChanged(uuid, telepathy.SENT); err != nil {
73+ log.Println(err)
74 }
75 }
76
77
78=== modified file 'storage/storage.go'
79--- storage/storage.go 2014-07-02 21:07:14 +0000
80+++ storage/storage.go 2014-07-02 21:07:14 +0000
81@@ -44,6 +44,24 @@
82 return writeState(state, storePath)
83 }
84
85+func Destroy(uuid string) error {
86+ if storePath, err := xdg.Data.Ensure(path.Join(SUBPATH, uuid+".db")); err == nil {
87+ if err := os.Remove(storePath); err != nil {
88+ return err
89+ }
90+ } else {
91+ return err
92+ }
93+ if mmsPath, err := GetMMS(uuid); err == nil {
94+ if err := os.Remove(mmsPath); err != nil {
95+ return err
96+ }
97+ } else {
98+ return err
99+ }
100+ return nil
101+}
102+
103 func CreateResponseFile(uuid string) (*os.File, error) {
104 filePath, err := xdg.Cache.Ensure(path.Join(SUBPATH, uuid+".m-notifyresp.ind"))
105 if err != nil {
106
107=== modified file 'telepathy/const.go'
108--- telepathy/const.go 2014-04-04 19:54:59 +0000
109+++ telepathy/const.go 2014-07-02 21:07:14 +0000
110@@ -24,6 +24,7 @@
111 const (
112 MMS_DBUS_NAME = "org.ofono.mms"
113 MMS_DBUS_PATH = "/org/ofono/mms"
114+ MMS_MESSAGE_DBUS_IFACE = "org.ofono.mms.Message"
115 MMS_SERVICE_DBUS_IFACE = "org.ofono.mms.Service"
116 MMS_MANAGER_DBUS_IFACE = "org.ofono.mms.Manager"
117 )
118@@ -32,8 +33,17 @@
119 IDENTITY = "Identity"
120 USE_DELIVERY_REPORTS = "UseDeliveryReports"
121 MESSAGE_ADDED = "MessageAdded"
122+ MESSAGE_REMOVED = "MessageRemoved"
123 SERVICE_ADDED = "ServiceAdded"
124 SERVICE_REMOVED = "ServiceRemoved"
125+ PROPERTY_CHANGED = "PropertyChanged"
126+ STATUS = "Status"
127+)
128+
129+const (
130+ PERMANENT_ERROR = "PermanentError"
131+ SENT = "Sent"
132+ TRANSIENT_ERROR = "TransientError"
133 )
134
135 const (
136
137=== added file 'telepathy/message.go'
138--- telepathy/message.go 1970-01-01 00:00:00 +0000
139+++ telepathy/message.go 2014-07-02 21:07:14 +0000
140@@ -0,0 +1,107 @@
141+/*
142+ * Copyright 2014 Canonical Ltd.
143+ *
144+ * Authors:
145+ * Sergio Schvezov: sergio.schvezov@cannical.com
146+ *
147+ * This file is part of telepathy.
148+ *
149+ * mms is free software; you can redistribute it and/or modify
150+ * it under the terms of the GNU General Public License as published by
151+ * the Free Software Foundation; version 3.
152+ *
153+ * mms is distributed in the hope that it will be useful,
154+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
155+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
156+ * GNU General Public License for more details.
157+ *
158+ * You should have received a copy of the GNU General Public License
159+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
160+ */
161+
162+package telepathy
163+
164+import (
165+ "fmt"
166+ "log"
167+ "sort"
168+
169+ "launchpad.net/go-dbus/v1"
170+)
171+
172+var validStatus sort.StringSlice
173+
174+func init() {
175+ validStatus = sort.StringSlice{SENT, PERMANENT_ERROR, TRANSIENT_ERROR}
176+ sort.Strings(validStatus)
177+}
178+
179+type MessageInterface struct {
180+ conn *dbus.Connection
181+ objectPath dbus.ObjectPath
182+ msgChan chan *dbus.Message
183+ deleteChan chan dbus.ObjectPath
184+ status string
185+}
186+
187+func NewMessageInterface(conn *dbus.Connection, objectPath dbus.ObjectPath, deleteChan chan dbus.ObjectPath) *MessageInterface {
188+ msgInterface := MessageInterface{
189+ conn: conn,
190+ objectPath: objectPath,
191+ deleteChan: deleteChan,
192+ msgChan: make(chan *dbus.Message),
193+ }
194+ go msgInterface.watchDBusMethodCalls()
195+ conn.RegisterObjectPath(msgInterface.objectPath, msgInterface.msgChan)
196+ return &msgInterface
197+}
198+
199+func (msgInterface *MessageInterface) Close() {
200+ close(msgInterface.msgChan)
201+ msgInterface.msgChan = nil
202+ msgInterface.conn.UnregisterObjectPath(msgInterface.objectPath)
203+}
204+
205+func (msgInterface *MessageInterface) watchDBusMethodCalls() {
206+ var reply *dbus.Message
207+
208+ for msg := range msgInterface.msgChan {
209+ if msg.Interface != MMS_MESSAGE_DBUS_IFACE {
210+ log.Println("Received unkown method call on", msg.Interface, msg.Member)
211+ reply = dbus.NewErrorMessage(msg, "org.freedesktop.DBus.Error.UnknownMethod", "Unknown method")
212+ continue
213+ }
214+ switch msg.Member {
215+ case "Delete":
216+ reply = dbus.NewMethodReturnMessage(msg)
217+ //TODO implement store and forward
218+ if err := msgInterface.conn.Send(reply); err != nil {
219+ log.Println("Could not send reply:", err)
220+ }
221+ msgInterface.deleteChan <- msgInterface.objectPath
222+ default:
223+ log.Println("Received unkown method call on", msg.Interface, msg.Member)
224+ reply = dbus.NewErrorMessage(msg, "org.freedesktop.DBus.Error.UnknownMethod", "Unknown method")
225+ if err := msgInterface.conn.Send(reply); err != nil {
226+ log.Println("Could not send reply:", err)
227+ }
228+ }
229+ }
230+}
231+
232+func (msgInterface *MessageInterface) StatusChanged(status string) error {
233+ i := validStatus.Search(status)
234+ if i < validStatus.Len() && validStatus[i] == status {
235+ msgInterface.status = status
236+ signal := dbus.NewSignalMessage(msgInterface.objectPath, MMS_MESSAGE_DBUS_IFACE, PROPERTY_CHANGED)
237+ if err := signal.AppendArgs(STATUS, dbus.Variant{status}); err != nil {
238+ return err
239+ }
240+ if err := msgInterface.conn.Send(signal); err != nil {
241+ return err
242+ }
243+ log.Print("Status changed for ", msgInterface.objectPath, " to ", status)
244+ return nil
245+ }
246+ return fmt.Errorf("status %s is not a valid status", status)
247+}
248
249=== modified file 'telepathy/service.go'
250--- telepathy/service.go 2014-07-02 21:07:14 +0000
251+++ telepathy/service.go 2014-07-02 21:07:14 +0000
252@@ -24,6 +24,7 @@
253 import (
254 "fmt"
255 "log"
256+ "path/filepath"
257 "strings"
258 "time"
259
260@@ -40,12 +41,14 @@
261 }
262
263 type MMSService struct {
264- Payload ServicePayload
265- Properties map[string]dbus.Variant
266- conn *dbus.Connection
267- msgChan chan *dbus.Message
268- identity string
269- outMessage chan *OutgoingMessage
270+ Payload ServicePayload
271+ Properties map[string]dbus.Variant
272+ conn *dbus.Connection
273+ msgChan chan *dbus.Message
274+ messageHandlers map[dbus.ObjectPath]*MessageInterface
275+ msgDeleteChan chan dbus.ObjectPath
276+ identity string
277+ outMessage chan *OutgoingMessage
278 }
279
280 type Attachment struct {
281@@ -78,18 +81,29 @@
282 Properties: properties,
283 }
284 service := MMSService{
285- Payload: payload,
286- Properties: serviceProperties,
287- conn: conn,
288- msgChan: make(chan *dbus.Message),
289- outMessage: outgoingChannel,
290- identity: identity,
291+ Payload: payload,
292+ Properties: serviceProperties,
293+ conn: conn,
294+ msgChan: make(chan *dbus.Message),
295+ msgDeleteChan: make(chan dbus.ObjectPath),
296+ messageHandlers: make(map[dbus.ObjectPath]*MessageInterface),
297+ outMessage: outgoingChannel,
298+ identity: identity,
299 }
300 go service.watchDBusMethodCalls()
301+ go service.watchMessageDeleteCalls()
302 conn.RegisterObjectPath(payload.Path, service.msgChan)
303 return &service
304 }
305
306+func (service *MMSService) watchMessageDeleteCalls() {
307+ for msgObjectPath := range service.msgDeleteChan {
308+ if err := service.MessageRemoved(msgObjectPath); err != nil {
309+ log.Print("Failed to delete ", msgObjectPath, ": ", err)
310+ }
311+ }
312+}
313+
314 func (service *MMSService) watchDBusMethodCalls() {
315 for msg := range service.msgChan {
316 var reply *dbus.Message
317@@ -147,6 +161,44 @@
318 }
319 }
320
321+func getUUIDFromObjectPath(objectPath dbus.ObjectPath) (string, error) {
322+ str := string(objectPath)
323+ defaultError := fmt.Errorf("%s is not a proper object path for a Message", str)
324+ if str == "" {
325+ return "", defaultError
326+ }
327+ uuid := filepath.Base(str)
328+ if uuid == "" || uuid == ".." || uuid == "." {
329+ return "", defaultError
330+ }
331+ return uuid, nil
332+}
333+
334+//MessageRemoved emits the MessageRemoved signal with the path of the removed
335+//message.
336+//It also actually removes the message from storage.
337+func (service *MMSService) MessageRemoved(objectPath dbus.ObjectPath) error {
338+ service.messageHandlers[objectPath].Close()
339+ delete(service.messageHandlers, objectPath)
340+
341+ uuid, err := getUUIDFromObjectPath(objectPath)
342+ if err != nil {
343+ return err
344+ }
345+ if err := storage.Destroy(uuid); err != nil {
346+ return err
347+ }
348+
349+ signal := dbus.NewSignalMessage(service.Payload.Path, MMS_SERVICE_DBUS_IFACE, MESSAGE_REMOVED)
350+ if err := signal.AppendArgs(objectPath); err != nil {
351+ return err
352+ }
353+ if err := service.conn.Send(signal); err != nil {
354+ return err
355+ }
356+ return nil
357+}
358+
359 //MessageAdded emits a MessageAdded with the path to the added message which
360 //is taken as a parameter
361 func (service *MMSService) MessageAdded(mRetConf *mms.MRetrieveConf) error {
362@@ -154,6 +206,7 @@
363 if err != nil {
364 return err
365 }
366+ service.messageHandlers[payload.Path] = NewMessageInterface(service.conn, payload.Path, service.msgDeleteChan)
367 signal := dbus.NewSignalMessage(service.Payload.Path, MMS_SERVICE_DBUS_IFACE, MESSAGE_ADDED)
368 if err := signal.AppendArgs(payload.Path, payload.Properties); err != nil {
369 return err
370@@ -175,6 +228,7 @@
371 func (service *MMSService) Close() {
372 service.conn.UnregisterObjectPath(service.Payload.Path)
373 close(service.msgChan)
374+ close(service.msgDeleteChan)
375 }
376
377 func (service *MMSService) parseMessage(mRetConf *mms.MRetrieveConf) (ServicePayload, error) {
378@@ -236,9 +290,31 @@
379 return recipients
380 }
381
382-func (service *MMSService) ReplySendMessage(reply *dbus.Message, uuid string) error {
383- reply.AppendArgs(service.genMessagePath(uuid))
384- return service.conn.Send(reply)
385+func (service *MMSService) MessageDestroy(uuid string) error {
386+ msgObjectPath := service.genMessagePath(uuid)
387+ if msgInterface, ok := service.messageHandlers[msgObjectPath]; ok {
388+ msgInterface.Close()
389+ delete(service.messageHandlers, msgObjectPath)
390+ }
391+ return fmt.Errorf("no message interface handler for object path %s", msgObjectPath)
392+}
393+
394+func (service *MMSService) MessageStatusChanged(uuid, status string) error {
395+ msgObjectPath := service.genMessagePath(uuid)
396+ if msgInterface, ok := service.messageHandlers[msgObjectPath]; ok {
397+ return msgInterface.StatusChanged(status)
398+ }
399+ return fmt.Errorf("no message interface handler for object path %s", msgObjectPath)
400+}
401+
402+func (service *MMSService) ReplySendMessage(reply *dbus.Message, uuid string) (dbus.ObjectPath, error) {
403+ msgObjectPath := service.genMessagePath(uuid)
404+ reply.AppendArgs(msgObjectPath)
405+ if err := service.conn.Send(reply); err != nil {
406+ return "", err
407+ }
408+ service.messageHandlers[msgObjectPath] = NewMessageInterface(service.conn, msgObjectPath, service.msgDeleteChan)
409+ return msgObjectPath, nil
410 }
411
412 //TODO randomly creating a uuid until the download manager does this for us

Subscribers

People subscribed via source and target branches