Merge lp:~sergiusens/nuntium/message-api into lp:nuntium
- message-api
- Merge into trunk
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 |
Related bugs: |
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
Description of the change
To post a comment you must log in.
Revision history for this message
Manuel de la Peña (mandel) : | # |
review:
Needs Fixing
- 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 : | # |
Revision history for this message
Manuel de la Peña (mandel) : | # |
review:
Approve
- 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 |
Fixed, comments inline