~nikwen/ubuntu-push/gmail-messages-missed-fix

« back to all changes in this revision

Viewing changes to docs/example-server/app.js

  • Committer: CI bot
  • Author(s): Roberto Alsina
  • Date: 2014-09-08 18:04:57 UTC
  • mfrom: (128.1.2 ubuntu-push)
  • Revision ID: ps-jenkins@lists.canonical.com-20140908180457-qga5piu3743an3lw
Latest changes from the automatic branch. 
Approved by: Roberto Alsina

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
var express = require('express')
 
2
  , bodyParser = require('body-parser')
 
3
 
 
4
var Registry = require('./lib/registry')
 
5
  , Inbox = require('./lib/inbox')
 
6
  , Notifier = require('./lib/notifier')
 
7
 
 
8
function wire(db, cfg) {
 
9
    var reg, inbox, notifier, app
 
10
 
 
11
    // control whether not to have persistent inboxes
 
12
    var no_inbox = cfg.no_inbox
 
13
 
 
14
    app = express()
 
15
 
 
16
    reg = new Registry(db)
 
17
    if (!no_inbox) {
 
18
        inbox = new Inbox(db)
 
19
    } else {
 
20
        inbox = null
 
21
    }
 
22
    var push_url = process.env.PUSH_URL || cfg.push_url
 
23
    notifier = new Notifier(push_url, cfg)
 
24
    notifier.on('unknownToken', function(nick, token) {
 
25
        reg.removeToken(nick, token, function() {},
 
26
                        function(err) {
 
27
                            app.emit('mongoError', err)
 
28
                        })
 
29
    })
 
30
    notifier.on('pushError', function(err, resp, body) {
 
31
        app.emit('pushError', err, resp, body)
 
32
    })
 
33
 
 
34
    function unavailable(resp, err) {
 
35
        app.emit('mongoError', err)
 
36
        var ctype = resp.get('Content-Type')
 
37
        if (ctype&&ctype.substr(0,10) == 'text/plain') {
 
38
            resp.send(503, "db is hopefully only momentarily :(\n")
 
39
        } else {
 
40
            resp.json(503, {error: "unavailable"})
 
41
        }
 
42
    }
 
43
 
 
44
    app.get("/_check", function(req, resp) {
 
45
        db.command({ping: 1}, function(err, res) {
 
46
            if(!err) {
 
47
                resp.json({ok: true})
 
48
            } else {
 
49
                unavailable(resp, err)
 
50
            }
 
51
        })
 
52
    })
 
53
 
 
54
    app.use(bodyParser.json())
 
55
    app.use('/play-notify-form', bodyParser.urlencoded({extended: false}))
 
56
    app.use(function(err, req, resp, next) {
 
57
        resp.json(err.status, {error: "invalid", message: err.message})
 
58
    })
 
59
 
 
60
    app.get("/", function(req, resp) {
 
61
        if (!cfg.play_notify_form) {
 
62
            resp.sendfile(__dirname + '/index.html')
 
63
        } else {
 
64
            resp.sendfile(__dirname + '/notify-form.html')
 
65
        }
 
66
    })
 
67
 
 
68
    // NB: simplified, minimal identity and auth piggybacking on push tokens
 
69
 
 
70
    /*
 
71
      POST /register let's register a pair nick, token taking a JSON obj:
 
72
      { "nick": string, "token": token-string }
 
73
    */
 
74
    app.post("/register", function(req, resp) {
 
75
        if(typeof(req.body.token) != "string" ||
 
76
           typeof(req.body.nick) != "string" ||
 
77
           req.body.token == "" || req.body.nick == "") {
 
78
            resp.json(400, {"error": "invalid"})
 
79
            return
 
80
        }
 
81
        reg.insertToken(req.body.nick, req.body.token, function() {
 
82
            resp.json({ok: true})
 
83
        }, function() {
 
84
            resp.json(400, {"error": "dup"})
 
85
        }, function(err) {
 
86
            unavailable(resp, err)
 
87
        })
 
88
    })
 
89
 
 
90
    function checkToken(nick, token, okCb, resp) {
 
91
        function bad() {
 
92
            resp.json(401, {error: "unauthorized"})
 
93
        }
 
94
        reg.findToken(nick, function(nickToken) {
 
95
            if (nickToken == token) {
 
96
                okCb()
 
97
                return
 
98
            }
 
99
            bad()
 
100
        }, bad, function(err) {
 
101
            unavailable(resp, err)
 
102
        })
 
103
    }
 
104
 
 
105
    /* doNotify
 
106
 
 
107
       ephemeral is true: message not put in the inbox, _ephemeral flag added
 
108
 
 
109
       ephemeral is false: message put in inbox, with added unix _timestamp and
 
110
       increasing _serial
 
111
 
 
112
     */
 
113
    function doNotify(ephemeral, nick, data, okCb, unknownNickCb, resp) {
 
114
        function notify(token, data) {
 
115
            notifier.notify(nick, token, data)
 
116
            okCb()
 
117
        }
 
118
        reg.findToken(nick, function(token) {
 
119
            if (ephemeral||no_inbox) {
 
120
                data._ephemeral = Date.now()
 
121
                notify(token, data)
 
122
            } else {
 
123
                inbox.pushMessage(token, data, function(msg) {
 
124
                    notify(token, msg)
 
125
                }, function(err) {
 
126
                    unavailable(resp, err)
 
127
                })
 
128
            }
 
129
        }, function() { // not found
 
130
            unknownNickCb()
 
131
        }, function(err) {
 
132
            unavailable(resp, err)
 
133
        })
 
134
    }
 
135
 
 
136
    /*
 
137
      POST /message let's send a message to nick taking a JSON obj:
 
138
      { "nick": string, "data": data,  "from_nick": string, "from_token": string}
 
139
    */
 
140
    app.post("/message", function(req, resp) {
 
141
        if (!req.body.data||!req.body.nick||!req.body.from_token||!req.body.from_nick) {
 
142
            resp.json(400, {"error": "invalid"})
 
143
            return
 
144
        }
 
145
        checkToken(req.body.from_nick, req.body.from_token, function() {
 
146
            var data = req.body.data
 
147
            data._from = req.body.from_nick
 
148
            doNotify(false, req.body.nick, data, function() {
 
149
                resp.json({ok: true})
 
150
            }, function() { // not found
 
151
                resp.json(400, {"error": "unknown-nick"})
 
152
            }, resp)
 
153
        }, resp)
 
154
    })
 
155
 
 
156
    if (!no_inbox) { // /drain supported only if no_inbox false
 
157
        /*
 
158
          POST /drain let's get pending messages for nick+token:
 
159
          it removes messages older than timestamp and return newer ones
 
160
          { "nick": string, "token": string, "timestamp": unix-timestamp }
 
161
        */
 
162
        app.post("/drain", function(req, resp) {
 
163
            if(!req.body.token||!req.body.nick||
 
164
               typeof(req.body.timestamp) != "number") {
 
165
                resp.json(400, {"error": "invalid"})
 
166
                return
 
167
            }
 
168
            checkToken(req.body.nick, req.body.token, function() {
 
169
                inbox.drain(req.body.token, req.body.timestamp, function(msgs) {
 
170
                    resp.json(200, {ok: true, msgs: msgs})
 
171
                }, function(err) {
 
172
                    unavailable(resp, err)
 
173
                })
 
174
            }, resp)
 
175
        })
 
176
    }
 
177
 
 
178
    /*
 
179
      Form /play-notify-form
 
180
      messages sent through the form are ephemeral, just transmitted through PN,
 
181
      without being pushed into the inbox
 
182
    */
 
183
    if (cfg.play_notify_form) {
 
184
        app.post("/play-notify-form", function(req, resp) {
 
185
            resp.type('text/plain')
 
186
            if (!req.body.data||!req.body.nick) {
 
187
                resp.send(400, "invalid/empty fields\n")
 
188
                return
 
189
            }
 
190
            var data
 
191
            try {
 
192
                data = JSON.parse(req.body.data)
 
193
            } catch(e) {
 
194
                resp.send(400, "data is not JSON\n")
 
195
                return
 
196
            }
 
197
            doNotify(true, req.body.nick, data, function() {
 
198
                resp.send(200, 'OK\n')
 
199
            }, function() { // not found
 
200
                resp.send(400, "unknown nick\n")
 
201
            }, resp)
 
202
        })
 
203
    }
 
204
 
 
205
    // for testing
 
206
    app.set('_reg', reg)
 
207
    app.set('_inbox', inbox)
 
208
    app.set('_notifier', notifier)
 
209
    return app
 
210
}
 
211
 
 
212
exports.wire = wire