git ssb

0+

dangerousbeans / yap



forked from Dominic / yap

Tree: aeff60d9b646561b229dc372cfff8ab13da2eb8c

Files: aeff60d9b646561b229dc372cfff8ab13da2eb8c / index.js

7197 bytesRaw
1var fs = require('fs')
2var path = require('path')
3var apis = require('./apis')
4var nested = require('libnested')
5var Stack = require('stack')
6var URL = require('url')
7var QS = require('qs')
8var u = require('./util')
9var toHTML = u.toHTML
10var h = u.h
11var pull = require('pull-stream')
12var toPull = require('stream-to-pull-stream')
13var Logger = require('morgan')
14var BodyParser = require('urlencoded-request-parser')
15var Coherence = require('coherence-framework')
16
17var doctype = '<!DOCTYPE html \n PUBLIC "-//W3C//DTD HTML 4.01//EN"\n "http://www.w3.org/TR/html4/strict.dtd">'
18
19//actions may make writes to sbot, or can set things
20var actions = {
21 //note: opts is post body
22 identitySelect: function (opts, apply, req, cb) {
23 var context = this.context
24 context.id = opts.id
25 cb(null, opts, context)
26 },
27 preview: function (opts, apply, req, cb) {
28 cb(null, opts)
29 },
30 publish: function (opts, apply, req, cb) {
31 if(opts.content.recps === '')
32 delete opts.content.recps
33 else if('string' === typeof opts.content.recps) {
34 opts.content.recps = opts.content.recps.split(',')
35 }
36
37 if(Array.isArray(opts.content.recps))
38 opts.private = true
39
40 sbot.identities.publishAs(opts, function (err, msg) {
41 if(err) cb(err)
42 else cb()
43 })
44 },
45 bounce: function (opts, cb) {
46 delete opts.type
47 cb(null, opts)
48 }
49}
50
51var coherence = Coherence(function (opts, content, apply) {
52 return ['html',
53 ['head', {profile: "http://www.w3.org/2005/10/profile"},
54 ['meta', {charset: 'UTF-8'}],
55 ['link', {href: '/static/style.css', rel: 'stylesheet'}],
56 ['script', {src: coherence.scriptUrl}],
57 ['link', {rel: 'icon', type: 'image/png', href: '/favicon.ico'}],
58 ],
59 ['body',
60 ['div#AppHeader',
61 ['nav',
62 ['div', {style: 'display:flex;flex-direction:row'},
63 ['h2', 'yap'],
64 ['img', {src: '/favicon.ico'}]
65 ],
66 ['a', {href: '/public'}, 'Public'],
67 ['a', {href: '/private'}, 'Private'],
68// ['a', {href: '/gatherings'}, 'Gatherings'],
69 ['form', {method: 'GET', action: '/search'},
70 ['input', {type: 'text', name: 'query', placeholder: 'Search'}],
71 ['input', {type: 'hidden', name: 'limit', value: 20}],
72 ['button', {}, 'go']
73 ],
74 apply('identitySelect', {main: true})
75 ],
76 apply('progress', {})
77 ],
78 ['div.main', content]
79 ]
80 ]
81})
82
83var favicon = fs.readFileSync(path.join(__dirname, 'static', 'favicon.ico'))
84
85//stack, but check if you called next twice!
86function _Stack() {
87 var args = [].slice.call(arguments)
88 return Stack.apply(this, args.map(function (fn) {
89 return function (req, res, next) {
90 var err = new Error('already called')
91 var called = false
92 fn(req, res, function _next (err) {
93 if(err) console.error(err)
94 if(called) throw called
95 called = new Error('called already')
96 return next(err)
97 })
98
99 }
100 }))
101}
102
103require('ssb-client')(function (err, sbot) {
104 if(err) throw err
105
106 coherence
107 .use('avatar', require('./apis/avatar')(sbot))
108 .use('identitySelect', require('./apis/identity-select')(sbot))
109 .use('public', require('./apis/public')(sbot))
110 .use('private', require('./apis/private')(sbot))
111 .use('message', require('./apis/message')(sbot))
112 .use('messages/post', require('./apis/messages/post')(sbot))
113 .use('messages/vote', require('./apis/messages/vote')(sbot))
114 .use('progress', require('./apis/progress')(sbot))
115 .use('thread', require('./apis/thread')(sbot))
116 .use('compose', require('./apis/compose')(sbot))
117 .use('publish', require('./apis/publish')(sbot))
118 .use('preview', require('./apis/preview')(sbot))
119 .use('friends', require('./apis/friends')(sbot))
120 .use('search', require('./apis/search')(sbot))
121 .use('mentions', require('./apis/mentions')(sbot))
122
123 require('http').createServer(_Stack(
124 Logger(),
125 //everything breaks if blobs isn't first, but not sure why?
126 require('ssb-ws/blobs')(sbot, {prefix: '/blobs'}),
127 /*
128 some settings we want to store in a cookie:
129 * current identity
130 * current language
131
132 stuff that shouldn't be in links.
133 this makes it possible to share links without including
134 state people might not want for them.
135 also: light/dark theme etc
136 */
137 function (req, res, next) {
138 if(req.url == '/favicon.ico')
139 return res.end(favicon)
140 if(req.url == '/')
141 return res.end('<h1>yap<img src="/favicon.ico"></h1>')
142
143 next()
144 },
145 BodyParser(),
146 function context (req, res, next) {
147 req.context = QS.parse(req.headers.cookie||'') || {id: sbot.id}
148 req.context.id = req.context.id || sbot.id
149 next()
150 },
151 //handle posts.
152 function (req, res, next) {
153 if(req.method == 'GET') return next()
154 var id = req.context.id || sbot.id
155// var opts = QS.parse(req.body)
156 var opts = req.body
157 console.log('B', opts)
158 function callApi (path, opts) {
159 try {
160 var fn = nested.get(apis, path)
161 if(!fn) return next()
162 return fn(opts, apply, req)
163 } catch(err) {
164 next(err)
165 }
166 }
167 if(opts.type === 'preview') {
168 // TODO: pass opts.id in, and wether this message
169 // preview should allow recipient selection, or changing id.
170 // api.preview can set the shape of the message if it likes.
171
172
173 req.url = '/preview?'+QS.stringify(opts)
174 coherence(req, res, next)
175
176 //XXX this isn't working
177
178// toHTML(layout.call(self, callApi(['preview'], opts))) (function (err, result) {
179// if(err) next(err)
180// else res.end('<!DOCTYPE html>'+result.outerHTML)
181// })
182 return
183 }
184 actions[opts.type](opts, apply, req, function (err, _opts, context) {
185 if(err) return next(err)
186 if(context) {
187 req.context = context
188 res.setHeader('set-cookie', QS.stringify(context))
189 }
190 /*
191 after handling the post,
192 redirect to a normal page.
193 this is a work around for if you hit refresh
194 and the browser wants to resubmit the POST.
195
196 I think we want to do this for most types,
197 exception is for preview - in which we return
198 the same data rendered differently and don't write
199 to DB at all.
200 */
201 res.setHeader('location', req.url)
202 res.writeHead(303)
203 res.end()
204 })
205 },
206
207 //HANDLE BLOBS
208 require('emoji-server')('/img/emoji'),
209 function (req, res, next) {
210 if(!/\/partial\//.test(req.url)) return next()
211 req.url = req.url.substring('/partial'.length)
212 render(true, req, res, next)
213 },
214 //static files
215 function (req, res, next) {
216 if(/\/static\/[\w\d-_]+\.\w+/.test(req.url)) {
217 console.log("STATIC", req.url)
218 fs.createReadStream(path.join(__dirname, req.url)).pipe(res)
219 } else
220 next()
221 },
222 //mount coherence!
223 coherence
224 )).listen(8005)
225})
226
227

Built with git-ssb-web