Files: 93f8be5cd174b9ced30164c1efaf91df91e4ac0f / util.js
4424 bytesRaw
1 | var pull = require('pull-stream') |
2 | var ref = require('ssb-ref') |
3 | var hash = require('ssb-keys/util').hash |
4 | var markdown = require('ssb-markdown') |
5 | |
6 | function isString (s) { |
7 | return 'string' == typeof s |
8 | } |
9 | |
10 | function update (state, msg) { |
11 | if(msg.content.type === 'channel') { |
12 | if(msg.content.subscribed) |
13 | state.channels[msg.content.channel] = msg.content.irc || msg.content.channel |
14 | else |
15 | delete state.channels[msg.content.channel] |
16 | } |
17 | else if(msg.content.type === 'about' && ref.isFeed(msg.content.about) && (msg.content.name || msg.content.irc != null)) { |
18 | state.users[msg.content.about] = msg.content.irc == null ? msg.content.name : msg.content.irc |
19 | } |
20 | return state |
21 | } |
22 | |
23 | function init(sbot, id, cb) { |
24 | var state = {users: {}, channels: {}} |
25 | |
26 | pull( |
27 | sbot.createHistoryStream({id: id || sbot.id, live: true}), |
28 | pull.drain(function (msg) { |
29 | if(msg.sync) |
30 | return cb && cb(null, state) |
31 | state = update(state, msg.value) |
32 | }) |
33 | ) |
34 | return state |
35 | } |
36 | |
37 | function toKey(fn) { |
38 | return function (state, msg) { |
39 | var key |
40 | if(msg.key) { |
41 | key = msg.key |
42 | msg = msg.value |
43 | } |
44 | else |
45 | key = '%'+hash(JSON.stringify(msg, null, 2)) |
46 | return fn(state, msg, key) |
47 | } |
48 | } |
49 | |
50 | exports.isChannelPost = toKey(function isChannelPost (state, msg, key) { |
51 | if(state.channels[msg.content.channel] && !msg.content.root) { |
52 | var text = msg.content.text |
53 | if(isString(text) && text) { |
54 | text = text.split('\n') |
55 | if(text.length > 1) |
56 | text = text[0] |
57 | else |
58 | text = text[0] |
59 | |
60 | return [{ |
61 | author: msg.author, |
62 | target: msg.content.channel, |
63 | text: text.length > 100 ? text.substring(0, 97)+'...' : text, |
64 | id: key, |
65 | type: 'channel' |
66 | }] |
67 | } |
68 | } |
69 | }) |
70 | |
71 | function uniq (a) { |
72 | var b = [] |
73 | for(var i = 0; i < a.length; i++) |
74 | if(!~b.indexOf(a[i])) b.push(a[i]) |
75 | return b |
76 | } |
77 | |
78 | function getChannel(state, name) { |
79 | name = name.replace(/^#/,'') |
80 | return state.channels[name] === true ? name : state.channels[name] |
81 | } |
82 | |
83 | function surrounding(text, match, length) { |
84 | var i = Math.max(text.indexOf(match)-100, 0) |
85 | return (i > 0 ? '...' : '') + text.substring(i, i+100) + (i + 100 < text.length ? '...' : '') |
86 | } |
87 | |
88 | exports.isChannelMention = toKey(function (state, msg, key) { |
89 | var text = msg.content.text |
90 | if(isString(text) && text) { |
91 | text = markdown.inline(text) |
92 | if(!/(#\w+)/.test(text)) return [] |
93 | |
94 | var m = uniq(text.match(/(#\w+)/g)) |
95 | return m.filter(function (name) { |
96 | return getChannel(state, name) |
97 | }).map(function (name) { |
98 | return { |
99 | author: msg.author, |
100 | target: getChannel(state, name), |
101 | text: surrounding(text, name, 100), |
102 | id: key, |
103 | type: 'channel' |
104 | } |
105 | }) |
106 | } |
107 | return [] |
108 | }) |
109 | |
110 | exports.isUserMention = toKey(function (state, msg, key) { |
111 | var text = msg.content.text |
112 | if(isString(text) && text && Array.isArray(msg.content.mentions)) { |
113 | text = markdown.inline(text) |
114 | return msg.content.mentions.filter(function (mention) { |
115 | return state.users[mention.link] |
116 | }).map(function (mention) { |
117 | return { |
118 | author: msg.author, |
119 | target: state.users[mention.link], |
120 | text: surrounding(markdown.inline(text), '@'+mention.name, 100), |
121 | id: key, |
122 | type: 'user' |
123 | } |
124 | }) |
125 | } |
126 | }) |
127 | |
128 | exports.isUserFollow = toKey(function (state, msg, key) { |
129 | if(msg.content.type == 'contact' && msg.content.following && state.users[msg.content.contact]) |
130 | return { |
131 | author: msg.author, |
132 | target: state.users[msg.content.contact], |
133 | text: 'followed you', //this will make sense since the notification will be a direct message |
134 | id: key, |
135 | type: 'user' |
136 | } |
137 | }) |
138 | |
139 | if(!module.parent) { |
140 | //this is just for testing... |
141 | require('ssb-client')(function (err, sbot) { |
142 | if(err) throw err |
143 | var state = init(sbot, process.argv[2] || sbot.id) |
144 | //XXX: properly persist state with a flumeview? |
145 | setTimeout(function () { |
146 | var tests = [ |
147 | exports.isChannelPost, |
148 | exports.isChannelMention, |
149 | exports.isUserMention, |
150 | exports.isUserFollow |
151 | ] |
152 | |
153 | pull( |
154 | sbot.createLogStream({}), |
155 | pull.drain(function (msg) { |
156 | if(msg.sync) return |
157 | var a = tests.reduce(function (found, test) { |
158 | return found.concat(test(state, msg) || []) |
159 | }, []) |
160 | if(a.length) console.log('ARY', a) |
161 | }) |
162 | ) |
163 | }, 5000) |
164 | }) |
165 | } |
166 | |
167 |
Built with git-ssb-web