Mercurial > pumpbridge
comparison app.js_to_pump.io-client-app_lib @ 0:b73191efc65b
Initial import of pumpbridge (bloody bloody alpha)
author | Mathias Gebbe <mgebbe@intevation.de> |
---|---|
date | Thu, 05 Jun 2014 10:35:15 +0200 |
parents | |
children | f190abf340ef |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:b73191efc65b |
---|---|
1 // app.js | |
2 // | |
3 // entrypoint for pump.io-enabled node.js apps | |
4 // | |
5 // Copyright 2013, E14N https://e14n.com/ | |
6 // | |
7 // Licensed under the Apache License, Version 2.0 (the "License"); | |
8 // you may not use this file except in compliance with the License. | |
9 // You may obtain a copy of the License at | |
10 // | |
11 // http://www.apache.org/licenses/LICENSE-2.0 | |
12 // | |
13 // Unless required by applicable law or agreed to in writing, software | |
14 // distributed under the License is distributed on an "AS IS" BASIS, | |
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
16 // See the License for the specific language governing permissions and | |
17 // limitations under the License. | |
18 | |
19 var fs = require("fs"), | |
20 async = require("async"), | |
21 path = require("path"), | |
22 http = require("http"), | |
23 https = require("https"), | |
24 _ = require("underscore"), | |
25 express = require('express'), | |
26 DialbackClient = require("dialback-client"), | |
27 Logger = require("bunyan"), | |
28 routes = require('./routes'), | |
29 databank = require("databank"), | |
30 uuid = require("node-uuid"), | |
31 Databank = databank.Databank, | |
32 DatabankObject = databank.DatabankObject, | |
33 DatabankStore = require('connect-databank')(express), | |
34 RequestToken = require("./models/requesttoken"), | |
35 RememberMe = require("./models/rememberme"), | |
36 User = require("./models/user"), | |
37 Host = require("./models/host"), | |
38 site = require("./models/site"), | |
39 auth = require("./auth.js"), | |
40 defaults = { | |
41 port: 4000, | |
42 hostname: "localhost", | |
43 driver: "memory", | |
44 params: null, | |
45 name: "An unconfigured pump.io client", | |
46 description: "A pump.io client that is not correctly configured.", | |
47 logfile: null, | |
48 loglevel: "info", | |
49 nologger: false, | |
50 key: null, | |
51 cert: null, | |
52 sessionSecret: "insecure", | |
53 static: null, | |
54 address: null, | |
55 useCDN: true | |
56 }; | |
57 | |
58 var PumpIOClientApp = function(configArg) { | |
59 | |
60 var clap = this, | |
61 config = _.defaults(configArg, defaults), | |
62 log, | |
63 db, | |
64 app, | |
65 setupLog = function() { | |
66 var logParams = { | |
67 serializers: { | |
68 req: Logger.stdSerializers.req, | |
69 res: Logger.stdSerializers.res, | |
70 err: Logger.stdSerializers.err | |
71 }, | |
72 level: config.loglevel | |
73 }; | |
74 | |
75 if (config.logfile) { | |
76 logParams.streams = [{path: config.logfile}]; | |
77 } else if (config.nologger) { | |
78 logParams.streams = [{path: "/dev/null"}]; | |
79 } else { | |
80 logParams.streams = [{stream: process.stderr}]; | |
81 } | |
82 | |
83 logParams.name = config.name; | |
84 | |
85 log = new Logger(logParams); | |
86 | |
87 log.debug("Initializing"); | |
88 | |
89 // Configure the service object | |
90 | |
91 log.debug({name: config.name, | |
92 description: config.description, | |
93 hostname: config.hostname}, | |
94 "Initializing site object"); | |
95 }, | |
96 setupSite = function() { | |
97 site.name = config.name; | |
98 site.description = config.description; | |
99 site.hostname = config.hostname; | |
100 | |
101 site.protocol = (config.key) ? "https" : "http"; | |
102 }, | |
103 setupDB = function(callback) { | |
104 if (!config.params) { | |
105 if (config.driver == "disk") { | |
106 config.params = {dir: "/var/lib/"+config.hostname+"/"}; | |
107 } else { | |
108 config.params = {}; | |
109 } | |
110 } | |
111 | |
112 // Define the database schema | |
113 | |
114 if (!config.params.schema) { | |
115 config.params.schema = {}; | |
116 } | |
117 | |
118 _.extend(config.params.schema, DialbackClient.schema); | |
119 _.extend(config.params.schema, DatabankStore.schema); | |
120 | |
121 // Now, our stuff | |
122 | |
123 _.each([User, Host, RequestToken, RememberMe], function(Cls) { | |
124 config.params.schema[Cls.type] = Cls.schema; | |
125 }); | |
126 | |
127 db = Databank.get(config.driver, config.params); | |
128 | |
129 log.debug({driver: config.driver, params: config.params}, | |
130 "Connecting to DB"); | |
131 | |
132 // Set global databank info | |
133 | |
134 DatabankObject.bank = db; | |
135 }, | |
136 requestLogger = function(log) { | |
137 return function(req, res, next) { | |
138 var weblog = log.child({"req_id": uuid.v4(), component: "web"}); | |
139 var end = res.end; | |
140 req.log = weblog; | |
141 res.end = function(chunk, encoding) { | |
142 var rec; | |
143 res.end = end; | |
144 res.end(chunk, encoding); | |
145 rec = {req: req, res: res}; | |
146 weblog.info(rec); | |
147 }; | |
148 next(); | |
149 }; | |
150 }, | |
151 setupApp = function() { | |
152 var client; | |
153 | |
154 app = new express(); | |
155 | |
156 // Configuration | |
157 | |
158 var dbstore = new DatabankStore(db, log, 60000); | |
159 | |
160 log.debug("Configuring app"); | |
161 | |
162 app.configure(function(){ | |
163 var serverVersion = site.userAgent() + ' express/'+express.version + ' node.js/'+process.version, | |
164 versionStamp = function(req, res, next) { | |
165 res.setHeader('Server', serverVersion); | |
166 next(); | |
167 }, | |
168 appObject = function(req, res, next) { | |
169 req.site = site; | |
170 res.locals.site = site; | |
171 res.locals.config = req.app.config; | |
172 next(); | |
173 }; | |
174 | |
175 app.set('views', path.join(__dirname, '../../../views')); | |
176 app.set('view engine', 'jade'); | |
177 app.use(requestLogger(log)); | |
178 app.use(versionStamp); | |
179 app.use(appObject); | |
180 app.use(express.bodyParser()); | |
181 app.use(express.cookieParser()); | |
182 app.use(express.methodOverride()); | |
183 app.use(express.session({secret: config.sessionSecret, | |
184 cookie: {path: '/', httpOnly: true}, | |
185 store: dbstore})); | |
186 app.use(app.router); | |
187 if (config.static) { | |
188 app.use(express.static(config.static)); | |
189 } | |
190 app.use(express.static(path.join(__dirname, 'public'))); | |
191 }); | |
192 | |
193 app.configure('development', function(){ | |
194 app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); | |
195 }); | |
196 | |
197 app.configure('production', function(){ | |
198 app.use(express.errorHandler()); | |
199 }); | |
200 | |
201 // Routes | |
202 | |
203 log.debug("Initializing routes"); | |
204 | |
205 app.get('/', auth.userAuth, auth.userOptional, routes.index); | |
206 app.get('/login', auth.userAuth, auth.noUser, routes.login); | |
207 app.post('/login', auth.userAuth, auth.noUser, routes.handleLogin); | |
208 app.post('/logout', auth.userAuth, auth.userRequired, routes.handleLogout); | |
209 app.get('/about', auth.userAuth, auth.userOptional, routes.about); | |
210 app.get('/authorized/:hostname', routes.authorized); | |
211 app.get('/.well-known/host-meta.json', routes.hostmeta); | |
212 | |
213 // Create a dialback client | |
214 | |
215 log.debug("Initializing dialback client"); | |
216 | |
217 client = new DialbackClient({ | |
218 hostname: config.hostname, | |
219 app: app, | |
220 bank: db, | |
221 userAgent: site.userAgent() | |
222 }); | |
223 | |
224 // Configure this global object | |
225 | |
226 Host.dialbackClient = client; | |
227 | |
228 // Let Web stuff get to config | |
229 | |
230 app.config = config; | |
231 | |
232 // For handling errors | |
233 | |
234 app.log = function(obj) { | |
235 if (obj instanceof Error) { | |
236 log.error(obj); | |
237 } else { | |
238 log.info(obj); | |
239 } | |
240 }; | |
241 }; | |
242 | |
243 // Dynamic default | |
244 | |
245 if (!config.address) { | |
246 config.address = config.hostname; | |
247 } | |
248 | |
249 // Set up aspects | |
250 | |
251 setupLog(); | |
252 setupSite(); | |
253 setupDB(); | |
254 setupApp(); | |
255 | |
256 // Delegate | |
257 | |
258 _.each(_.functions(app), function(name) { | |
259 clap[name] = function() { | |
260 app[name].apply(app, arguments); | |
261 }; | |
262 }); | |
263 | |
264 // Expose the log so clients can use it | |
265 | |
266 clap.log = log; | |
267 | |
268 // Expose the site so clients can use it | |
269 | |
270 clap.site = site; | |
271 | |
272 // Run | |
273 | |
274 clap.run = function(callback) { | |
275 | |
276 var srv, | |
277 bounce; | |
278 | |
279 if (config.key) { | |
280 | |
281 log.debug("Using SSL"); | |
282 | |
283 srv = https.createServer({key: fs.readFileSync(config.key), | |
284 cert: fs.readFileSync(config.cert)}, | |
285 app); | |
286 | |
287 bounce = http.createServer(function(req, res, next) { | |
288 var host = req.headers.host, | |
289 url = 'https://'+host+req.url; | |
290 res.writeHead(301, {'Location': url, | |
291 'Content-Type': 'text/html'}); | |
292 res.end('<a href="'+url+'">'+url+'</a>'); | |
293 }); | |
294 | |
295 } else { | |
296 log.debug("Not using SSL"); | |
297 srv = http.createServer(app); | |
298 } | |
299 | |
300 // Start the app | |
301 | |
302 async.waterfall([ | |
303 function(callback) { | |
304 db.connect(config.params, callback); | |
305 }, | |
306 function(callback) { | |
307 // Wrapper function to give a callback-like interface to network servers | |
308 var listenBack = function(server, port, address, callback) { | |
309 var a, | |
310 removeListeners = function() { | |
311 server.removeListener("listening", listenSuccessHandler); | |
312 server.removeListener("error", listenErrorHandler); | |
313 }, | |
314 listenErrorHandler = function(err) { | |
315 removeListeners(); | |
316 callback(err); | |
317 }, | |
318 listenSuccessHandler = function() { | |
319 removeListeners(); | |
320 callback(null); | |
321 }; | |
322 server.on("error", listenErrorHandler); | |
323 server.on("listening", listenSuccessHandler); | |
324 server.listen(port, address); | |
325 }; | |
326 | |
327 async.parallel([ | |
328 function(callback) { | |
329 log.debug({port: config.port, address: config.address}, "Starting app listener"); | |
330 listenBack(srv, config.port, config.address, callback); | |
331 }, | |
332 function(callback) { | |
333 if (bounce) { | |
334 log.debug({port: 80, address: config.address}, "Starting bounce listener"); | |
335 listenBack(bounce, 80, config.address, callback); | |
336 } else { | |
337 callback(null, null); | |
338 } | |
339 } | |
340 ], callback); | |
341 } | |
342 ], function(err, results) { | |
343 // Ignore meaningless results | |
344 callback(err); | |
345 }); | |
346 }; | |
347 }; | |
348 | |
349 // Export the auth methods | |
350 | |
351 _.each(_.keys(auth), function(key) { | |
352 PumpIOClientApp[key] = auth[key]; | |
353 }); | |
354 | |
355 // Export the model classes | |
356 | |
357 PumpIOClientApp.User = User; | |
358 PumpIOClientApp.Host = Host; | |
359 PumpIOClientApp.RequestToken = RequestToken; | |
360 PumpIOClientApp.RememberMe = RememberMe; | |
361 | |
362 module.exports = PumpIOClientApp; |