| Comment: | begin replacing inefficient memory management with a pool-based solution; fix memory leaks |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
7c8769bf968cda064fdda9ccd9fcd551 |
| User & Date: | lexi on 2021-01-10 08:19:56 |
| Other Links: | manifest | tags |
|
2021-01-10
| ||
| 11:17 | add follow notices check-in: 00a6815988 user: lexi tags: trunk | |
| 08:19 | begin replacing inefficient memory management with a pool-based solution; fix memory leaks check-in: 7c8769bf96 user: lexi tags: trunk | |
| 03:54 | add memory pool impl, handle various little details, add beginnings of mimelib check-in: 8d35307a7f user: lexi tags: trunk | |
Modified html.t from [f6f8bc0dcc] to [06c69e3651].
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
-- vim: ft=terra
local m={}
local pstr = lib.mem.ptr(int8)
terra m.sanitize(txt: pstr, quo: bool)
if txt.ptr == nil then return pstr.null() end
if txt.ct == 0 then txt.ct = lib.str.sz(txt.ptr) end
var a: lib.str.acc a:init(txt.ct*1.3)
for i=0,txt.ct do
if txt(i) == @'<' then a:lpush('<')
elseif txt(i) == @'>' then a:lpush('>')
elseif txt(i) == @'&' then a:lpush('&')
elseif quo and txt(i) == @'"' then a:lpush('"')
else a:push(&txt(i),1) end
end
................................................................................
terra m.hexbyte(i: uint8): int8[2]
return arrayof(int8,
m.hexdgt(i / 0x10),
m.hexdgt(i % 0x10))
end
terra m.urlenc(txt: pstr, qparam: bool)
if txt.ptr == nil then return pstr.null() end
if txt.ct == 0 then txt.ct = lib.str.sz(txt.ptr) end
var a: lib.str.acc a:init(txt.ct*1.3)
for i=0,txt.ct do
if txt(i) == @' ' then a:lpush('+')
elseif txt(i) == @'&' and not qparam then a:lpush('&')
elseif (txt(i) < 0x2c or
(txt(i) > @';' and txt(i) < @'@') or
(txt(i) > @'Z' and txt(i) < @'a') or
(txt(i) >= 0x7b and txt(i) <= 0x7f)) and
|
|
|
|
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
-- vim: ft=terra
local m={}
local pstr = lib.mem.ptr(int8)
terra m.sanitize(pool: &lib.mem.pool, txt: pstr, quo: bool)
if txt.ptr == nil then return pstr.null() end
if txt.ct == 0 then txt.ct = lib.str.sz(txt.ptr) end
var a: lib.str.acc a:pool(pool,txt.ct*1.3)
for i=0,txt.ct do
if txt(i) == @'<' then a:lpush('<')
elseif txt(i) == @'>' then a:lpush('>')
elseif txt(i) == @'&' then a:lpush('&')
elseif quo and txt(i) == @'"' then a:lpush('"')
else a:push(&txt(i),1) end
end
................................................................................
terra m.hexbyte(i: uint8): int8[2]
return arrayof(int8,
m.hexdgt(i / 0x10),
m.hexdgt(i % 0x10))
end
terra m.urlenc(pool: &lib.mem.pool, txt: pstr, qparam: bool)
if txt.ptr == nil then return pstr.null() end
if txt.ct == 0 then txt.ct = lib.str.sz(txt.ptr) end
var a: lib.str.acc a:pool(pool,txt.ct*1.3)
for i=0,txt.ct do
if txt(i) == @' ' then a:lpush('+')
elseif txt(i) == @'&' and not qparam then a:lpush('&')
elseif (txt(i) < 0x2c or
(txt(i) > @';' and txt(i) < @'@') or
(txt(i) > @'Z' and txt(i) < @'a') or
(txt(i) >= 0x7b and txt(i) <= 0x7f)) and
|
Modified mem.t from [de24aef2de] to [7e2b478eaf].
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
end)
struct m.pool {
-- implements growable memory pools. EVERY THREAD MUST HAVE ITS OWN
storage: &opaque
cursor: &opaque
sz: intptr
}
terra m.pool:cue(sz: intptr)
if self.storage == nil then
self.storage = m.heapa_raw(sz)
self.cursor = self.storage
self.sz = sz
else
if self.sz >= sz then return self end
var ofs = [&uint8](self.cursor) - [&uint8](self.storage)
self.storage = m.heapr_raw(self.storage, sz)
self.cursor = [&opaque]([&uint8](self.storage) + ofs)
self.sz = sz
end
return self
end
terra m.pool:init(sz: intptr)
self.storage = nil
self:cue(sz)
return self
end
terra m.pool:free()
m.heapf(self.storage)
self.storage = nil
self.cursor = nil
self.sz = 0
end
terra m.pool:clear()
self.cursor = self.storage
return self
end
terra m.pool:alloc_bytes(sz: intptr): &opaque
var space = self.sz - ([&uint8](self.cursor) - [&uint8](self.storage))
if space < sz then self:cue(space + sz + 256) end
var ptr = self.cursor
self.cursor = [&opaque]([&uint8](self.cursor) + sz)
return ptr
end
m.pool.methods.alloc = macro(function(self,ty,sz)
return `[ty](self:alloc_bytes(sizeof(ty) * sz))
end)
terra m.pool:frame() -- stack-style linear mgmt
return self.cursor
end
terra m.pool:reset(frame: &opaque)
self.cursor = frame
return self
end
return m
|
> | | | < > > > > > | < | > | > > > > > > > | > > > > > > > > > > > > > > > > | > > | > > > > > > > > > > > > > | > > > |
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
end)
struct m.pool {
-- implements growable memory pools. EVERY THREAD MUST HAVE ITS OWN
storage: &opaque
cursor: &opaque
sz: intptr
debris: &m.pool
}
terra m.pool:cue(sz: intptr)
if self.storage == nil then
self.storage = m.heapa_raw(sz)
self.cursor = self.storage
self.sz = sz
else
if self.sz >= sz then return self end
var oldblock = @self
self:init(sz)
@self.debris = oldblock
end
return self
end
terra m.pool:init(sz: intptr)
var b = m.heapa_raw(sz + sizeof(m.pool))
self.storage = [&uint8](b) + sizeof(m.pool)
self.cursor = self.storage
self.sz = sz
self.debris = [&m.pool](b)
self.debris.storage = nil
return self
end
terra m.pool:free(): {}
lib.io.fmt('DRAINING POOL %p\n',self.storage)
if self.storage == nil then return end
if self.debris.storage ~= nil then self.debris:free() end
m.heapf(self.debris) -- storage + debris field allocated in one block
self.storage = nil
self.cursor = nil
self.sz = 0
self.debris = nil
end
terra m.pool:clear()
if self.debris.storage ~= nil then self.debris:free() end
self.cursor = self.storage
return self
end
terra m.pool:alloc_bytes(sz: intptr): &opaque
var space = self.sz - ([&uint8](self.cursor) - [&uint8](self.storage))
lib.io.fmt('%p / %p @ allocating %llu bytes in %llu of space\n',self.storage,self.cursor,sz,space)
if space < sz then
lib.dbg('reserving more space')
self:cue(space + sz + 256) end
var ptr = self.cursor
self.cursor = [&opaque]([&uint8](self.cursor) + sz)
return ptr
end
terra m.pool:realloc_bytes(oldptr: &opaque, oldsz: intptr, newsz: intptr): &opaque
var space = self.sz - ([&uint8](self.cursor) - [&uint8](self.storage))
var cur = [&uint8](self.cursor)
if cur - [&uint8](oldptr) == oldsz and newsz - oldsz < space then
lib.dbg('moving pool cursor')
cur = cur + (newsz - oldsz)
self.cursor = [&opaque](cur)
return oldptr
else
lib.dbg('copying pool object')
var new = self:alloc_bytes(newsz)
m.cpy(new, oldptr, oldsz)
return new
end
end
m.pool.methods.alloc = macro(function(self,typ,sz)
local ty = typ:astype()
return `[m.ptr(ty)] {
ptr = [&ty](self:alloc_bytes(sizeof([ty]) * [sz]));
ct = [sz];
}
end)
m.pool.methods.realloc = macro(function(self,ptr,oldsz,newsz)
local ty = self.tree.type.type
return `[m.ptr(ty)] {
ptr = [&ty](self:realloc_bytes(ptr,
sizeof(ty) * oldsz,
sizeof(ty) * newsz));
ct = sz;
}
end)
terra m.pool:frame() -- stack-style linear mgmt
return self.cursor
end
terra m.pool:reset(frame: &opaque)
if frame >= self.storage and frame <= self.cursor then
self.cursor = frame
else -- trying to rewind into a previous block! not possible
self.cursor = self.storage
end
return self
end
return m
|
Modified render/compose.t from [13509724e6] to [95dc7dcbc1].
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
form.acl = lib.trn(target == nil, 'all', 'mentioned') -- TODO default acl setting? else form.content = lib.coalesce(edit.body, '') form.acl = edit.acl end if acc ~= nil then form:append(acc) return end var cotxt = form:tostr() defer cotxt:free() var doc = [lib.srv.convo.page] { title = lib.str.plit 'compose'; body = cotxt; class = lib.str.plit 'compose'; cache = true; } co:stdpage(doc) end return render_compose |
| |
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
form.acl = lib.trn(target == nil, 'all', 'mentioned') -- TODO default acl setting? else form.content = lib.coalesce(edit.body, '') form.acl = edit.acl end if acc ~= nil then form:append(acc) return end var cotxt = form:poolstr(&co.srv.pool) -- defer cotxt:free() var doc = [lib.srv.convo.page] { title = lib.str.plit 'compose'; body = cotxt; class = lib.str.plit 'compose'; cache = true; } co:stdpage(doc) end return render_compose |
Modified render/conf.t from [241a1c4277] to [cd79efba6f].
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
local invoker = quote co:complain(404,'not found','no such control panel is available in this version of parsav') end for i, m in ipairs(mappings) do if lib.render.conf[m.render] then invoker = quote if path(1):cmp(lib.str.lit([m.url])) then var body = [lib.render.conf[m.render]] (co, path) var a: lib.str.acc a:init(body.ct+48) if not body then a:lpush(['<h1>' .. m.title .. ' :: error</h1>' .. '<p>the requested resource is not available.</p>']) panel = a:finalize() else a:lpush(['<h1>' .. m.title .. '</h1>']):ppush(body) panel = a:finalize() body:free() end else [invoker] end end end end local terra render_conf([co], [path], notify: pstr) var menu: lib.str.acc menu:init(64):lpush('<hr>') defer menu:free() -- build menu do var p = co.who.rights.powers if p:affect_users() then menu:lpush '<a href="/conf/users">users</a>' end if p.censor() then menu:lpush '<a href="/conf/censor">badthink alerts</a>' end if p.config() then menu:lpush([ '<a href="/conf/srv">server & policy</a>' .. ................................................................................ menu = mptr; panel = panel; } var pgt: pstr if notify:ref() then var fnpg: lib.str.acc fnpg:compose('<div class="flashmsg">', notify, '</div>') pg:append(&fnpg) pgt = fnpg:finalize() else pgt = pg:tostr() end defer pgt:free() co:stdpage([lib.srv.convo.page] { title = 'configure'; body = pgt; class = lib.str.plit 'conf'; cache = false; }) if panel.ct ~= 0 then panel:free() end end return render_conf |
|
|
|
>
|
|
|
|
|
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
..
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
local invoker = quote co:complain(404,'not found','no such control panel is available in this version of parsav') end for i, m in ipairs(mappings) do if lib.render.conf[m.render] then invoker = quote if path(1):cmp(lib.str.lit([m.url])) then var body = [lib.render.conf[m.render]] (co, path) var a = co:stra(body.ct+48) if not body then a:lpush(['<h1>' .. m.title .. ' :: error</h1>' .. '<p>the requested resource is not available.</p>']) panel = a:finalize() else a:lpush(['<h1>' .. m.title .. '</h1>']):ppush(body) panel = a:finalize() --body:free() end else [invoker] end end end end local terra render_conf([co], [path], notify: pstr) var menu = co:stra(256) menu:lpush('<hr>') -- build menu do var p = co.who.rights.powers if p:affect_users() then menu:lpush '<a href="/conf/users">users</a>' end if p.censor() then menu:lpush '<a href="/conf/censor">badthink alerts</a>' end if p.config() then menu:lpush([ '<a href="/conf/srv">server & policy</a>' .. ................................................................................ menu = mptr; panel = panel; } var pgt: pstr if notify:ref() then var fnpg: lib.str.acc fnpg:pcompose(&co.srv.pool, '<div class="flashmsg">', notify, '</div>') pg:append(&fnpg) pgt = fnpg:finalize() else pgt = pg:poolstr(&co.srv.pool) end --defer pgt:free() co:stdpage([lib.srv.convo.page] { title = 'configure'; body = pgt; class = lib.str.plit 'conf'; cache = false; }) --if panel.ct ~= 0 then panel:free() end end return render_conf |
Modified render/conf/profile.t from [864a63a85e] to [5b3736f2f4].
11 12 13 14 15 16 17 18 19 20 21 |
var hue: int8[21]
var c = data.view.conf_profile {
handle = cs(co.who.handle);
nym = cs(lib.coalesce(co.who.nym,''));
bio = cs(lib.coalesce(co.who.bio,''));
hue = lib.math.decstr(co.ui_hue, &hue[20]);
}
return c:tostr()
end
return render_conf_profile
|
| |
11 12 13 14 15 16 17 18 19 20 21 |
var hue: int8[21]
var c = data.view.conf_profile {
handle = cs(co.who.handle);
nym = cs(lib.coalesce(co.who.nym,''));
bio = cs(lib.coalesce(co.who.bio,''));
hue = lib.math.decstr(co.ui_hue, &hue[20]);
}
return c:poolstr(&co.srv.pool)
end
return render_conf_profile
|
Modified render/conf/sec.t from [f6e2d18341] to [d16c1b9a13].
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
lib.osclock.ctime_r(&time, &tstr[0])
var body = data.view.conf_sec {
lastreset = pstr {
ptr = &tstr[0], ct = lib.str.sz(&tstr[0])
}
}
var a: lib.str.acc a:init(768) defer a:free()
if co.srv.cfg.credmgd then
var new = co:pgetv('new')
if not new then
body:append(&a)
var credmgr = data.view.conf_sec_credmg {
credlist = pstr{'',0};
}
var creds = co.srv:auth_enum_uid(uid)
if creds.ct > 0 then defer creds:free()
var cl: lib.str.acc cl:init(256)
for i=0, creds.ct do var c = creds(i).ptr
if not c.blacklist then
cl:lpush('<option value="'):shpush(c.aid):lpush('"> ['):push(c.kind,0):lpush('] '):push(c.comment,0)
if c.netmask.pv ~= 0 then
-- push string rep
end
cl:lpush('</option>')
end
end
credmgr.credlist = cl:finalize()
end
credmgr:append(&a)
if credmgr.credlist.ct > 0 then credmgr.credlist:free() end
else
if new:cmp(lib.str.plit'pw') then
var d: data.view.conf_sec_pwnew
var time = lib.osclock.time(nil)
var timestr: int8[26] lib.osclock.ctime_r(&time, ×tr[0])
var cmt: lib.str.acc
cmt:init(48):lpush('enrolled over http on '):push(×tr[0],0)
d.comment = cmt:finalize()
var st = d:tostr()
d.comment:free()
return st
elseif new:cmp(lib.str.plit'challenge') then
-- we're going to break the rules a bit and do database munging from
-- the rendering code, because doing otherwise in this case would be
-- genuinely nightmarish
elseif new:cmp(lib.str.plit'otp') then
elseif new:cmp(lib.str.plit'api') then
|
| | | | | | | |
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
lib.osclock.ctime_r(&time, &tstr[0])
var body = data.view.conf_sec {
lastreset = pstr {
ptr = &tstr[0], ct = lib.str.sz(&tstr[0])
}
}
var a = co:stra(768) -- defer a:free()
if co.srv.cfg.credmgd then
var new = co:pgetv('new')
if not new then
body:append(&a)
var credmgr = data.view.conf_sec_credmg {
credlist = pstr{'',0};
}
var creds = co.srv:auth_enum_uid(uid)
if creds.ct > 0 then defer creds:free()
var cl = co:stra(256)
for i=0, creds.ct do var c = creds(i).ptr
if not c.blacklist then
cl:lpush('<option value="'):shpush(c.aid):lpush('"> ['):push(c.kind,0):lpush('] '):push(c.comment,0)
if c.netmask.pv ~= 0 then
-- push string rep
end
cl:lpush('</option>')
end
end
credmgr.credlist = cl:finalize()
end
credmgr:append(&a)
--if credmgr.credlist.ct > 0 then credmgr.credlist:free() end
else
if new:cmp(lib.str.plit'pw') then
var d: data.view.conf_sec_pwnew
var time = lib.osclock.time(nil)
var timestr: int8[26] lib.osclock.ctime_r(&time, ×tr[0])
var cmt = co:stra(48)
cmt:lpush('enrolled over http on '):push(×tr[0],0)
d.comment = cmt:finalize()
var st = d:poolstr(&co.srv.pool)
--d.comment:free()
return st
elseif new:cmp(lib.str.plit'challenge') then
-- we're going to break the rules a bit and do database munging from
-- the rendering code, because doing otherwise in this case would be
-- genuinely nightmarish
elseif new:cmp(lib.str.plit'otp') then
elseif new:cmp(lib.str.plit'api') then
|
Modified render/conf/users.t from [59cb9f4fac] to [7c5c858095].
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
|
-- FIXME allow xids as well, for manual queries if not user then goto e404 end defer user:free() if not co.who:overpowers(user.ptr) then goto e403 end if path.ct == 4 then if path(3):cmp(lib.str.lit'cred') then var pg: lib.str.acc pg:init(1024) pg:lpush('<div class="context">editing credentials for user <a href="/conf/users/'):rpush(path(2)):lpush('">'):push(user(0).xid,0):lpush('</a></div>') var credmgr = lib.render.conf.sec(co, uid) pg:ppush(credmgr) credmgr:free() return pg:finalize() else goto e404 end elseif path.ct == 3 then var cinp: lib.str.acc cinp:init(256) cinp:lpush('<div class="elem-group">') if user.ptr.rights.rank > 0 and (co.who.rights.powers.elevate() or co.who.rights.powers.demote()) then var max = co.who.rights.rank if not co.who.rights.powers.elevate() then max = user.ptr.rights.rank end var min = co.srv.cfg.nranks if not co.who.rights.powers.demote() then min = user.ptr.rights.rank end push_num_field(cinp, 'rank', 'rank', max, min, user.ptr.rights.rank, user.ptr.id == co.who.id) end if co.who.rights.powers.herald() then var sanitized: pstr if user.ptr.epithet == nil then sanitized = pstr {ptr='', ct=0} else sanitized = lib.html.sanitize(cs(user.ptr.epithet),true) end cinp:lpush('<div class="elem"><label for="epithet">epithet</label><input type="text" id="epithet" name="epithet" value="'):ppush(sanitized):lpush('"></div>') if user.ptr.epithet ~= nil then sanitized:free() end end if co.who.rights.powers.invite() or co.who.rights.powers.discipline() then var min: uint32 = 0 if not (co.who.rights.powers.discipline() or co.who.rights.powers.demote() and co.who.rights.powers.invite()) then min = user.ptr.rights.invites end var max: uint32 = co.srv.cfg.maxinvites ................................................................................ var map = array([lib.store.powmap]) cinp:lpush('<details><summary>powers</summary><div class="pick-list">') for i=0, [map.type.N] do if (co.who.rights.powers and map[i].val):sz() > 0 then var on = (user.ptr.rights.powers and map[i].val):sz() > 0 var enabled = ( on and co.who.rights.powers.demote() ) or ((not on) and co.who.rights.powers.elevate()) var namea: lib.str.acc namea:compose('power-', map[i].name) var name = namea:finalize() push_pickbox(&cinp, name, pstr.null(), map[i].name, on, enabled, pstr.null()) name:free() end end cinp:lpush('</div></details>') end if co.who.id ~= uid and co.who.rights.powers.purge() then var purgeconf: lib.str.acc purgeconf:init(48) var purgestrs = array( 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'eta', 'nu', 'kappa', 'emerald', 'carnelian', 'sapphire', 'ruby', 'amethyst', 'glory', 'hope', 'grace', 'pearl', 'carnation', 'rose', 'peony', 'poppy' ) for i=0,3 do purgeconf:push(purgestrs[lib.crypt.random(intptr,0,[purgestrs.type.N])],0) if i ~= 2 then purgeconf:lpush('-') end end cinp:lpush('<details><summary>purge account</summary><p>you have the authority to destroy this account and all its associated content irreversibly and irretrievably. if you really wish to apply such an extreme sanction, enter the confirmation string <strong style="user-select:none">'):push(purgeconf.buf,purgeconf.sz):lpush('</strong> below and press the “alter” button to begin the process.</p><div class="elem"><label for="purge">purge confirmation string</label><input type="text" id="purge" name="purgekey"></div><input type="hidden" name="purgestr" value="'):push(purgeconf.buf,purgeconf.sz):lpush('"></details>') purgeconf:free() end -- TODO black mark system? e.g. resolution option for badthink reports -- adds a black mark to the offending user; they can be automatically banned -- or brought up for review after a certain number of offenses; possibly lower -- set of default privs for marked users var cinpp = cinp:finalize() defer cinpp:free() var unym: lib.str.acc unym:init(64) unym:lpush('<a href="/') if user(0).origin ~= 0 then unym:lpush('@') end do var sanxid = lib.html.sanitize(user(0).xid, true) unym:ppush(sanxid) sanxid:free() end unym:lpush('" class="id">') lib.render.nym(user.ptr,0,&unym,false) unym:lpush('</a>') var ctlbox = data.view.conf_user_ctl { name = unym:finalize(); inputcontent = cinpp; btns = pstr{'',0}; } if co.who.id ~= uid and co.who.rights.powers.cred() then ctlbox.btns = lib.str.acc{}:compose('<a class="button" href="/conf/users/',path(2),'/cred">security & credentials</a>'):finalize() end var pg: lib.str.acc pg:init(512) ctlbox:append(&pg) ctlbox.name:free() if ctlbox.btns.ct > 0 then ctlbox.btns:free() end return pg:finalize() end else var modes = array(P'local', P'remote', P'staff', P'titled', P'peons', P'all') var idbuf: int8[lib.math.shorthand.maxlen] var ulst: lib.str.acc ulst:init(256) var mode: uint8 = mode_local var modestr = co:pgetv('show') ulst:lpush('<div style="text-align: right"><em>showing ') for i=0,[modes.type.N] do if modestr:ref() and modes[i]:cmp(modestr) then mode = i end end for i=0,[modes.type.N] do |
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
|
-- FIXME allow xids as well, for manual queries if not user then goto e404 end defer user:free() if not co.who:overpowers(user.ptr) then goto e403 end if path.ct == 4 then if path(3):cmp(lib.str.lit'cred') then var pg = co:stra(1024) pg:lpush('<div class="context">editing credentials for user <a href="/conf/users/'):rpush(path(2)):lpush('">'):push(user(0).xid,0):lpush('</a></div>') var credmgr = lib.render.conf.sec(co, uid) pg:ppush(credmgr) --credmgr:free() return pg:finalize() else goto e404 end elseif path.ct == 3 then var cinp = co:stra(256) cinp:lpush('<div class="elem-group">') if user.ptr.rights.rank > 0 and (co.who.rights.powers.elevate() or co.who.rights.powers.demote()) then var max = co.who.rights.rank if not co.who.rights.powers.elevate() then max = user.ptr.rights.rank end var min = co.srv.cfg.nranks if not co.who.rights.powers.demote() then min = user.ptr.rights.rank end push_num_field(cinp, 'rank', 'rank', max, min, user.ptr.rights.rank, user.ptr.id == co.who.id) end if co.who.rights.powers.herald() then var sanitized: pstr if user.ptr.epithet == nil then sanitized = pstr {ptr='', ct=0} else sanitized = lib.html.sanitize(&co.srv.pool,cs(user.ptr.epithet),true) end cinp:lpush('<div class="elem"><label for="epithet">epithet</label><input type="text" id="epithet" name="epithet" value="'):ppush(sanitized):lpush('"></div>') --if user.ptr.epithet ~= nil then sanitized:free() end end if co.who.rights.powers.invite() or co.who.rights.powers.discipline() then var min: uint32 = 0 if not (co.who.rights.powers.discipline() or co.who.rights.powers.demote() and co.who.rights.powers.invite()) then min = user.ptr.rights.invites end var max: uint32 = co.srv.cfg.maxinvites ................................................................................ var map = array([lib.store.powmap]) cinp:lpush('<details><summary>powers</summary><div class="pick-list">') for i=0, [map.type.N] do if (co.who.rights.powers and map[i].val):sz() > 0 then var on = (user.ptr.rights.powers and map[i].val):sz() > 0 var enabled = ( on and co.who.rights.powers.demote() ) or ((not on) and co.who.rights.powers.elevate()) var namea: lib.str.acc namea:pcompose(&co.srv.pool,'power-', map[i].name) var name = namea:finalize() push_pickbox(&cinp, name, pstr.null(), map[i].name, on, enabled, pstr.null()) --name:free() end end cinp:lpush('</div></details>') end if co.who.id ~= uid and co.who.rights.powers.purge() then var purgeconf = co:stra(48) var purgestrs = array( 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'eta', 'nu', 'kappa', 'emerald', 'carnelian', 'sapphire', 'ruby', 'amethyst', 'glory', 'hope', 'grace', 'pearl', 'carnation', 'rose', 'peony', 'poppy' ) for i=0,3 do purgeconf:push(purgestrs[lib.crypt.random(intptr,0,[purgestrs.type.N])],0) if i ~= 2 then purgeconf:lpush('-') end end cinp:lpush('<details><summary>purge account</summary><p>you have the authority to destroy this account and all its associated content irreversibly and irretrievably. if you really wish to apply such an extreme sanction, enter the confirmation string <strong style="user-select:none">'):push(purgeconf.buf,purgeconf.sz):lpush('</strong> below and press the “alter” button to begin the process.</p><div class="elem"><label for="purge">purge confirmation string</label><input type="text" id="purge" name="purgekey"></div><input type="hidden" name="purgestr" value="'):push(purgeconf.buf,purgeconf.sz):lpush('"></details>') --purgeconf:free() end -- TODO black mark system? e.g. resolution option for badthink reports -- adds a black mark to the offending user; they can be automatically banned -- or brought up for review after a certain number of offenses; possibly lower -- set of default privs for marked users var cinpp = cinp:finalize() --defer cinpp:free() var unym = co:stra(64) unym:lpush('<a href="/') if user(0).origin ~= 0 then unym:lpush('@') end do var sanxid = lib.html.sanitize(&co.srv.pool,user(0).xid, true) unym:ppush(sanxid) --sanxid:free() end unym:lpush('" class="id">') lib.render.nym(user.ptr,0,&unym,false) unym:lpush('</a>') var ctlbox = data.view.conf_user_ctl { name = unym:finalize(); inputcontent = cinpp; btns = pstr{'',0}; } if co.who.id ~= uid and co.who.rights.powers.cred() then ctlbox.btns = lib.str.acc{}:pcompose(&co.srv.pool,'<a class="button" href="/conf/users/',path(2),'/cred">security & credentials</a>'):finalize() end var pg = co:stra(512) ctlbox:append(&pg) --ctlbox.name:free() --if ctlbox.btns.ct > 0 then ctlbox.btns:free() end return pg:finalize() end else var modes = array(P'local', P'remote', P'staff', P'titled', P'peons', P'all') var idbuf: int8[lib.math.shorthand.maxlen] var ulst = co:stra(256) var mode: uint8 = mode_local var modestr = co:pgetv('show') ulst:lpush('<div style="text-align: right"><em>showing ') for i=0,[modes.type.N] do if modestr:ref() and modes[i]:cmp(modestr) then mode = i end end for i=0,[modes.type.N] do |
Modified render/media-gallery.t from [da27a31f83] to [5c4e9df122].
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 .. 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 ... 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 ... 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 ... 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
var owner = false if co.aid ~= 0 and co.who.id == uid then owner = true end var ou = co.srv:actor_fetch_uid(uid) if not ou then goto e404 end do defer ou:free() var pfx = pstr.null() if not owner then var pa: lib.str.acc pa:init(32) pa:lpush('/') if ou(0).origin ~= 0 then pa:lpush('@') end pa:push(ou(0).xid,0) pfx = pa:finalize() end if path.ct >= 3 and path(1):cmp(lib.str.lit'a') then ................................................................................ var art = co.srv:artifact_fetch(uid, id) if not art then goto e404 end if path.ct == 3 then -- sniff out the artifact type and display the appropriate viewer var artid = cs(art(0).url) var btns: lib.str.acc if owner then btns:compose('<a class="neg button" href="',pfx,'/media/a/',artid,'/del">delete</a><a class="button" href="',pfx,'/media/a/',artid,'/edit">alter</a>') else btns:compose('<a class="pos button" href="',pfx,'/media/a/',artid,'/collect">collect</a>') end var btntxt = btns:finalize() defer btntxt:free() var desc = lib.smackdown.html(pstr{art(0).desc,0}, true) defer desc:free() var viewerprops = { pfx = pfx, desc = desc; id = artid; btns = btntxt; } if lib.str.ncmp(art(0).mime, 'image/', 6) == 0 then var view = data.view.media_image(viewerprops) var pg = view:tostr() co:stdpage([lib.srv.convo.page] { title = lib.str.plit'media :: image'; class = lib.str.plit'media viewer img'; cache = false, body = pg; }) pg:free() elseif lib.str.cmp(art(0).mime, 'text/markdown') == 0 then var view = data.view.media_text(viewerprops) var text, mime = co.srv:artifact_load(id) mime:free() view.text = lib.smackdown.html(pstr{[rawstring](text.ptr),text.ct}, false) text:free() var pg = view:tostr() view.text:free() co:stdpage([lib.srv.convo.page] { title = lib.str.plit'media :: text'; class = lib.str.plit'media viewer text'; cache = false, body = pg; }) pg:free() elseif lib.str.ncmp(art(0).mime, 'text/', 5) == 0 or lib.str.cmp(art(0).mime, 'application/x-perl') == 0 or lib.str.cmp(art(0).mime, 'application/sql') == 0 -- and so on (we need a mimelib at some point) -- then var view = data.view.media_text(viewerprops) var text, mime = co.srv:artifact_load(id) mime:free() var san = lib.html.sanitize(pstr{[rawstring](text.ptr),text.ct}, false) text:free() view.text = lib.str.acc{}:compose('<pre>',san,'</pre>'):finalize() san:free() var pg = view:tostr() view.text:free() co:stdpage([lib.srv.convo.page] { title = lib.str.plit'media :: text'; ................................................................................ folders = pstr{'',0}; directory = pstr{'',0}; images = pstr{'',0}; pfx = pfx; } if folders.ct > 0 then var fa: lib.str.acc fa:init(128) var fldr = co:pgetv('folder') for i=0,folders.ct do var ule = lib.html.urlenc(folders(i), true) defer ule:free() var san = lib.html.sanitize(folders(i), true) defer san:free() fa:lpush('<a href="'):ppush(pfx):lpush('/media?folder='):ppush(ule) :lpush('">'):ppush(san):lpush('</a>') lib.dbg('checking folder ',{fldr.ptr,fldr.ct},' against ',{folders(i).ptr,folders(i).ct}) if fldr:ref() and folders(i):cmp(fldr) then folder = folders(i) lib.dbg('folder match ',{fldr.ptr,fldr.ct}) else folders(i):free() end ................................................................................ end if owner then view.menu = P'<a class="pos" href="/media/upload">upload</a><hr>' end var md = co.srv:artifact_enum_uid(uid, folder) var gallery: lib.str.acc gallery:init(256) var files: lib.str.acc files:init(256) for i=0,md.ct do var desc = lib.smackdown.html(pstr{md(i)(0).desc,0}, true) defer desc:free() if lib.str.ncmp(md(i)(0).mime, 'image/', 6) == 0 then gallery:lpush('<a class="thumb" href="'):ppush(pfx):lpush('/media/a/') :push(md(i)(0).url,0):lpush('"><img src="/file/'):push(md(i)(0).url,0) :lpush('"><div class="caption">'):ppush(desc) :lpush('</div></a>') else var mime = lib.html.sanitize(pstr{md(i)(0).mime,0}, true) defer mime:free() --just in case files:lpush('<a class="file" href="'):ppush(pfx):lpush('/media/a/') :push(md(i)(0).url,0):lpush('"><span class="label">'):ppush(desc) :lpush('</span> <span class="mime">'):ppush(mime) :lpush('</span></a>') end md(i):free() end ................................................................................ view.images = gallery:finalize() view.directory = files:finalize() if acc ~= nil then view:append(acc) else lib.dbg('emitting page') var pg = view:tostr() defer pg:free() lib.dbg('compiled page') co:stdpage([lib.srv.convo.page] { title = P'media'; class = P'media manager'; cache = false; body = pg; }) lib.dbg('sent page') end view.images:free() view.directory:free() if view.folders.ct > 0 then view.folders:free() end if folder.ct > 0 then folder:free() end if md:ref() then md:free() end end if not owner then pfx:free() end return end ::e404:: co:complain(404,'media not found','no such media exists on this server') end return render_media_gallery |
| | | | | | | | | | | | | | | | | | | | < < < | | | | |
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 .. 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 ... 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 ... 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 ... 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
var owner = false if co.aid ~= 0 and co.who.id == uid then owner = true end var ou = co.srv:actor_fetch_uid(uid) if not ou then goto e404 end do defer ou:free() var pfx = pstr.null() if not owner then var pa = co:stra(32) pa:lpush('/') if ou(0).origin ~= 0 then pa:lpush('@') end pa:push(ou(0).xid,0) pfx = pa:finalize() end if path.ct >= 3 and path(1):cmp(lib.str.lit'a') then ................................................................................ var art = co.srv:artifact_fetch(uid, id) if not art then goto e404 end if path.ct == 3 then -- sniff out the artifact type and display the appropriate viewer var artid = cs(art(0).url) var btns: lib.str.acc if owner then btns:pcompose(&co.srv.pool,'<a class="neg button" href="',pfx,'/media/a/',artid,'/del">delete</a><a class="button" href="',pfx,'/media/a/',artid,'/edit">alter</a>') else btns:pcompose(&co.srv.pool,'<a class="pos button" href="',pfx,'/media/a/',artid,'/collect">collect</a>') end var btntxt = btns:finalize() -- defer btntxt:free() var desc = lib.smackdown.html(&co.srv.pool, pstr{art(0).desc,0}, true) -- defer desc:free() var viewerprops = { pfx = pfx, desc = desc; id = artid; btns = btntxt; } if lib.str.ncmp(art(0).mime, 'image/', 6) == 0 then var view = data.view.media_image(viewerprops) var pg = view:poolstr(&co.srv.pool) co:stdpage([lib.srv.convo.page] { title = lib.str.plit'media :: image'; class = lib.str.plit'media viewer img'; cache = false, body = pg; }) --pg:free() elseif lib.str.cmp(art(0).mime, 'text/markdown') == 0 then var view = data.view.media_text(viewerprops) var text, mime = co.srv:artifact_load(id) mime:free() view.text = lib.smackdown.html(&co.srv.pool, pstr{[rawstring](text.ptr),text.ct}, false) text:free() var pg = view:poolstr(&co.srv.pool) --view.text:free() co:stdpage([lib.srv.convo.page] { title = lib.str.plit'media :: text'; class = lib.str.plit'media viewer text'; cache = false, body = pg; }) --pg:free() elseif lib.str.ncmp(art(0).mime, 'text/', 5) == 0 or lib.str.cmp(art(0).mime, 'application/x-perl') == 0 or lib.str.cmp(art(0).mime, 'application/sql') == 0 -- and so on (we need a mimelib at some point) -- then var view = data.view.media_text(viewerprops) var text, mime = co.srv:artifact_load(id) mime:free() var san = lib.html.sanitize(&co.srv.pool,pstr{[rawstring](text.ptr),text.ct}, false) text:free() view.text = lib.str.acc{}:compose('<pre>',san,'</pre>'):finalize() san:free() var pg = view:tostr() view.text:free() co:stdpage([lib.srv.convo.page] { title = lib.str.plit'media :: text'; ................................................................................ folders = pstr{'',0}; directory = pstr{'',0}; images = pstr{'',0}; pfx = pfx; } if folders.ct > 0 then var fa: lib.str.acc fa:pool(&co.srv.pool,128) var fldr = co:pgetv('folder') for i=0,folders.ct do var ule = lib.html.urlenc(&co.srv.pool,folders(i), true) -- defer ule:free() var san = lib.html.sanitize(&co.srv.pool,folders(i), true) -- defer san:free() fa:lpush('<a href="'):ppush(pfx):lpush('/media?folder='):ppush(ule) :lpush('">'):ppush(san):lpush('</a>') lib.dbg('checking folder ',{fldr.ptr,fldr.ct},' against ',{folders(i).ptr,folders(i).ct}) if fldr:ref() and folders(i):cmp(fldr) then folder = folders(i) lib.dbg('folder match ',{fldr.ptr,fldr.ct}) else folders(i):free() end ................................................................................ end if owner then view.menu = P'<a class="pos" href="/media/upload">upload</a><hr>' end var md = co.srv:artifact_enum_uid(uid, folder) var gallery: lib.str.acc gallery:pool(&co.srv.pool,256) var files: lib.str.acc files:pool(&co.srv.pool,256) for i=0,md.ct do var desc = lib.smackdown.html(&co.srv.pool,pstr{md(i)(0).desc,0}, true) --defer desc:free() if lib.str.ncmp(md(i)(0).mime, 'image/', 6) == 0 then gallery:lpush('<a class="thumb" href="'):ppush(pfx):lpush('/media/a/') :push(md(i)(0).url,0):lpush('"><img src="/file/'):push(md(i)(0).url,0) :lpush('"><div class="caption">'):ppush(desc) :lpush('</div></a>') else var mime = lib.html.sanitize(&co.srv.pool,pstr{md(i)(0).mime,0}, true) --defer mime:free() --just in case files:lpush('<a class="file" href="'):ppush(pfx):lpush('/media/a/') :push(md(i)(0).url,0):lpush('"><span class="label">'):ppush(desc) :lpush('</span> <span class="mime">'):ppush(mime) :lpush('</span></a>') end md(i):free() end ................................................................................ view.images = gallery:finalize() view.directory = files:finalize() if acc ~= nil then view:append(acc) else var pg = view:poolstr(&co.srv.pool) -- defer pg:free() co:stdpage([lib.srv.convo.page] { title = P'media'; class = P'media manager'; cache = false; body = pg; }) end --view.images:free() --view.directory:free() --if view.folders.ct > 0 then view.folders:free() end if folder.ct > 0 then folder:free() end if md:ref() then md:free() end end --if not owner then pfx:free() end return end ::e404:: co:complain(404,'media not found','no such media exists on this server') end return render_media_gallery |
Modified render/nav.t from [0fd87c81ae] to [9f2c55cf5b].
1 2 3 4 5 6 7 8 9 10 11 |
-- vim: ft=terra
local terra
render_nav(co: &lib.srv.convo)
var t: lib.str.acc t:init(64)
if co.who ~= nil or co.srv.cfg.pol_sec == lib.srv.secmode.public then
t:lpush(' <a accesskey="t" href="/">timeline</a>')
end
if co.who ~= nil then
t:lpush(' <a accesskey="c" href="/compose">compose</a> <a accesskey="p" href="/'):push(co.who.xid,0)
t:lpush('">profile</a> <a accesskey="m" href="/media">media</a> <a accesskey="o" href="/conf">configure</a> <a accesskey="d" href="/doc">docs</a> <div class="ident">@')
t:push(co.who.handle,0)
|
| |
1 2 3 4 5 6 7 8 9 10 11 |
-- vim: ft=terra
local terra
render_nav(co: &lib.srv.convo)
var t = co:stra(64)
if co.who ~= nil or co.srv.cfg.pol_sec == lib.srv.secmode.public then
t:lpush(' <a accesskey="t" href="/">timeline</a>')
end
if co.who ~= nil then
t:lpush(' <a accesskey="c" href="/compose">compose</a> <a accesskey="p" href="/'):push(co.who.xid,0)
t:lpush('">profile</a> <a accesskey="m" href="/media">media</a> <a accesskey="o" href="/conf">configure</a> <a accesskey="d" href="/doc">docs</a> <div class="ident">@')
t:push(co.who.handle,0)
|
Modified render/notices.t from [99b348e685] to [745afb2f25].
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 .. 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 .. 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
if notes.ct == 0 then co:complain(200,'no news is good news',"you don't have any notices to review") return end defer notes:free() var pg: lib.str.acc pg:init(512) defer pg:free() var pflink: lib.str.acc pflink:init(64) var body: lib.str.acc body:init(256) var latest: lib.store.timepoint = 0 for i=0,notes.ct do if notes(i).when > latest then latest = notes(i).when end var who = co.srv:actor_fetch_uid(notes(i).who) defer who:free() if not who then lib.bail('schema integrity violation: nonexistent actor referenced in notification, this is almost certainly an SQL error or bug in the backend implementation') end pflink:cue(lib.str.sz(who(0).xid) + 4) if who(0).origin == 0 then pflink:lpush('/') ................................................................................ n.kind = P'reply' n.act = P'replied to your post' notweet = false end else goto skip end do var idbuf: int8[lib.math.shorthand.maxlen] var idlen = lib.math.shorthand.gen(notes(i).what, idbuf) var b = lib.smackdown.html(pstr {ptr=what(0).body,ct=0},true) defer b:free() body:lpush(' <a class="quote" href="/post/'):push(&idbuf[0],idlen):lpush('">'):ppush(b):lpush('</a>') end if not notweet then var reply = co.srv:post_fetch(notes(i).reply) lib.render.tweet(co,reply.ptr,&body) reply:free() end ................................................................................ n.ref = pstr {ptr = body.buf, ct = body.sz} n:append(&pg) ::skip:: n.nym:free() pflink:reset() body:reset() end pflink:free() pg:lpush('<form method="post"><button name="act" value="clear">clear all notices</button></form>') co:livepage([lib.srv.convo.page] { title = P'notices', class = P'notices'; body = pstr {ptr = pg.buf, ct = pg.sz}; cache = false; }, latest) end return render_notices |
| | | | | |
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 .. 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 .. 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
if notes.ct == 0 then co:complain(200,'no news is good news',"you don't have any notices to review") return end defer notes:free() var pg = co:stra(512) -- defer pg:free() var pflink = co:stra(64) var body = co:stra(256) var latest: lib.store.timepoint = 0 for i=0,notes.ct do if notes(i).when > latest then latest = notes(i).when end var who = co.srv:actor_fetch_uid(notes(i).who) defer who:free() if not who then lib.bail('schema integrity violation: nonexistent actor referenced in notification, this is almost certainly an SQL error or bug in the backend implementation') end pflink:cue(lib.str.sz(who(0).xid) + 4) if who(0).origin == 0 then pflink:lpush('/') ................................................................................ n.kind = P'reply' n.act = P'replied to your post' notweet = false end else goto skip end do var idbuf: int8[lib.math.shorthand.maxlen] var idlen = lib.math.shorthand.gen(notes(i).what, idbuf) var b = lib.smackdown.html(&co.srv.pool, pstr {ptr=what(0).body,ct=0},true) --defer b:free() body:lpush(' <a class="quote" href="/post/'):push(&idbuf[0],idlen):lpush('">'):ppush(b):lpush('</a>') end if not notweet then var reply = co.srv:post_fetch(notes(i).reply) lib.render.tweet(co,reply.ptr,&body) reply:free() end ................................................................................ n.ref = pstr {ptr = body.buf, ct = body.sz} n:append(&pg) ::skip:: n.nym:free() pflink:reset() body:reset() end --pflink:free() pg:lpush('<form method="post"><button name="act" value="clear">clear all notices</button></form>') co:livepage([lib.srv.convo.page] { title = P'notices', class = P'notices'; body = pstr {ptr = pg.buf, ct = pg.sz}; cache = false; }, latest) end return render_notices |
Modified render/nym.t from [ea921b8ffe] to [c2ab22760a].
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
render_nym(who: &lib.store.actor, scope: uint64, tgt: &lib.str.acc, minimal: bool)
var acc: lib.str.acc
var n: &lib.str.acc
if tgt ~= nil then n = tgt else
n = &acc
n:init(128)
end
var xidsan = lib.html.sanitize(cs(who.xid),false)
if who.nym ~= nil and who.nym[0] ~= 0 then
var nymsan = lib.html.sanitize(cs(who.nym),false)
n:lpush('<span class="nym">'):ppush(nymsan)
:lpush('</span> [<span class="handle">'):ppush(xidsan)
:lpush('</span>]')
nymsan:free()
else n:lpush('<span class="handle">'):ppush(xidsan):lpush('</span>') end
xidsan:free()
if not minimal then
if who.epithet ~= nil then
var episan = lib.html.sanitize(cs(who.epithet),false)
n:lpush('<span class="epithet">'):ppush(episan):lpush('</span>')
episan:free()
end
end
-- TODO: if scope == chat room then lookup titles in room member db
if tgt == nil then
return n:finalize()
else return pstr.null() end
end
return render_nym
|
> > > > > > > > > > | | | | | | > |
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
render_nym(who: &lib.store.actor, scope: uint64, tgt: &lib.str.acc, minimal: bool) var acc: lib.str.acc var n: &lib.str.acc if tgt ~= nil then n = tgt else n = &acc n:init(128) end var pool_obj: lib.mem.pool var pool: &lib.mem.pool if tgt ~= nil and tgt.pool ~= nil then pool = tgt.pool else pool_obj:init(128) pool = &pool_obj end var xidsan = lib.html.sanitize(pool,cs(who.xid),false) if who.nym ~= nil and who.nym[0] ~= 0 then var nymsan = lib.html.sanitize(pool,cs(who.nym),false) n:lpush('<span class="nym">'):ppush(nymsan) :lpush('</span> [<span class="handle">'):ppush(xidsan) :lpush('</span>]') --nymsan:free() else n:lpush('<span class="handle">'):ppush(xidsan):lpush('</span>') end --xidsan:free() if not minimal then if who.epithet ~= nil then var episan = lib.html.sanitize(pool,cs(who.epithet),false) n:lpush('<span class="epithet">'):ppush(episan):lpush('</span>') --episan:free() end end if pool == &pool_obj then pool:free() end -- TODO: if scope == chat room then lookup titles in room member db if tgt == nil then return n:finalize() else return pstr.null() end end return render_nym |
Modified render/profile.t from [3525ca58bc] to [a033243372].
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
..
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
co: &lib.srv.convo,
actor: &lib.store.actor,
relationship: &lib.store.relationship
): pstr
var aux: lib.str.acc
var followed = false -- FIXME
if co.aid ~= 0 and co.who.id == actor.id then
aux:compose('<a accesskey="a" class="button" href="/conf/profile?go=/@',actor.handle,'">alter</a>')
elseif co.aid ~= 0 then
if not relationship.rel.follow() then
aux:compose('<button accesskey="f" method="post" class="pos" name="act" value="follow">follow</button>')
elseif relationship.rel.follow() then
aux:compose('<button accesskey="f" method="post" class="neg" name="act" value="unfollow">unfollow</button>')
end
aux:lpush('<a accesskey="h" class="button" href="/'):push(actor.xid,0):lpush('/chat">chat</a>')
if co.who.rights.powers:affect_users() and co.who:overpowers(actor) then
aux:lpush('<a accesskey="n" class="button" href="/'):push(actor.xid,0):lpush('/ctl">control</a>')
end
else
aux:compose('<a accesskey="f" class="button" href="/', actor.xid, '/follow">remote follow</a>')
end
var auxp = aux:finalize()
var timestr: int8[26] lib.osclock.ctime_r(&actor.knownsince, ×tr[0])
var strfbuf: int8[28*4]
var stats = co.srv:actor_stats(actor.id)
var sn_posts = cs(lib.math.decstr_friendly(stats.posts, &strfbuf[ [strfbuf.type.N - 1] ]))
var sn_follows = cs(lib.math.decstr_friendly(stats.follows, sn_posts.ptr - 1))
var sn_followers = cs(lib.math.decstr_friendly(stats.followers, sn_follows.ptr - 1))
var sn_mutuals = cs(lib.math.decstr_friendly(stats.mutuals, sn_followers.ptr - 1))
var bio = lib.str.plit '<em style="opacity:0.6">tall, dark, and mysterious</em>'
if actor.bio ~= nil then
bio = lib.smackdown.html(cs(actor.bio),false)
end
var fullname = lib.render.nym(actor,0,nil,false) defer fullname:free()
var comments: lib.str.acc comments:init(64)
if co.srv.cfg.master == actor.id then
var foundertxt = lib.str.plit 'founder'
if co.srv.cfg.ui_cue_founder:ref() then
if co.srv.cfg.ui_cue_founder.ct == 0 -- empty string, suppress field
then foundertxt = pstr.null()
else foundertxt = co.srv.cfg.ui_cue_founder
................................................................................
remarks = '';
auxbtn = auxp;
}
if comments.sz > 0 then profile.remarks = comments:finalize() end
var ret = profile:tostr()
auxp:free()
if actor.bio ~= nil then bio:free() end
if comments.sz > 0 then profile.remarks:free() end
return ret
end
return render_profile
|
|
|
|
|
|
|
|
|
|
|
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
..
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
co: &lib.srv.convo, actor: &lib.store.actor, relationship: &lib.store.relationship ): pstr var aux: lib.str.acc var followed = false -- FIXME if co.aid ~= 0 and co.who.id == actor.id then aux:pcompose(&co.srv.pool,'<a accesskey="a" class="button" href="/conf/profile?go=/@',actor.handle,'">alter</a>') elseif co.aid ~= 0 then if not relationship.rel.follow() then aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="pos" name="act" value="follow">follow</button>') elseif relationship.rel.follow() then aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="neg" name="act" value="unfollow">unfollow</button>') end aux:lpush('<a accesskey="h" class="button" href="/'):push(actor.xid,0):lpush('/chat">chat</a>') if co.who.rights.powers:affect_users() and co.who:overpowers(actor) then aux:lpush('<a accesskey="n" class="button" href="/'):push(actor.xid,0):lpush('/ctl">control</a>') end else aux:pcompose(&co.srv.pool,'<a accesskey="f" class="button" href="/', actor.xid, '/follow">remote follow</a>') end var auxp = aux:finalize() var timestr: int8[26] lib.osclock.ctime_r(&actor.knownsince, ×tr[0]) var strfbuf: int8[28*4] var stats = co.srv:actor_stats(actor.id) var sn_posts = cs(lib.math.decstr_friendly(stats.posts, &strfbuf[ [strfbuf.type.N - 1] ])) var sn_follows = cs(lib.math.decstr_friendly(stats.follows, sn_posts.ptr - 1)) var sn_followers = cs(lib.math.decstr_friendly(stats.followers, sn_follows.ptr - 1)) var sn_mutuals = cs(lib.math.decstr_friendly(stats.mutuals, sn_followers.ptr - 1)) var bio = lib.str.plit '<em style="opacity:0.6">tall, dark, and mysterious</em>' if actor.bio ~= nil then bio = lib.smackdown.html(&co.srv.pool,cs(actor.bio),false) end var fullname = lib.render.nym(actor,0,nil,false) defer fullname:free() var comments: lib.str.acc comments:pool(&co.srv.pool,64) if co.srv.cfg.master == actor.id then var foundertxt = lib.str.plit 'founder' if co.srv.cfg.ui_cue_founder:ref() then if co.srv.cfg.ui_cue_founder.ct == 0 -- empty string, suppress field then foundertxt = pstr.null() else foundertxt = co.srv.cfg.ui_cue_founder ................................................................................ remarks = ''; auxbtn = auxp; } if comments.sz > 0 then profile.remarks = comments:finalize() end var ret = profile:poolstr(&co.srv.pool) -- auxp:free() --if actor.bio ~= nil then bio:free() end if comments.sz > 0 then profile.remarks:free() end return ret end return render_profile |
Modified render/timeline.t from [ab5808172b] to [7375f87c90].
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
..
41
42
43
44
45
46
47
48
49
50
|
from_time = stoptime; to_idx = 64; }) elseif mode == modes.fediglobal then elseif mode == modes.circle then end var acc: lib.str.acc acc:init(1024) acc:lpush('<div id="tl" data-live="10">') var newest: lib.store.timepoint = 0 for i = 0, posts.sz do lib.render.tweet(co, posts(i).ptr, &acc) var t = lib.math.biggest(lib.math.biggest(posts(i).ptr.posted, posts(i).ptr.discovered),posts(i).ptr.edited) if t > newest then newest = t end posts(i):free() ................................................................................ var doc = [lib.srv.convo.page] { title = lib.str.plit'timeline'; body = acc:finalize(); class = lib.str.plit'timeline'; cache = false; } co:livepage(doc,newest) doc.body:free() end return render_timeline |
|
|
|
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
..
41
42
43
44
45
46
47
48
49
50
|
from_time = stoptime; to_idx = 64; }) elseif mode == modes.fediglobal then elseif mode == modes.circle then end var acc: lib.str.acc acc:pool(&co.srv.pool,1024) acc:lpush('<div id="tl" data-live="10">') var newest: lib.store.timepoint = 0 for i = 0, posts.sz do lib.render.tweet(co, posts(i).ptr, &acc) var t = lib.math.biggest(lib.math.biggest(posts(i).ptr.posted, posts(i).ptr.discovered),posts(i).ptr.edited) if t > newest then newest = t end posts(i):free() ................................................................................ var doc = [lib.srv.convo.page] { title = lib.str.plit'timeline'; body = acc:finalize(); class = lib.str.plit'timeline'; cache = false; } co:livepage(doc,newest) --doc.body:free() end return render_timeline |
Modified render/tweet-page.t from [c0b864229b] to [304c6c3aff].
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
render_tweet_page(
co: &lib.srv.convo,
path: lib.mem.ptr(pref),
p: &lib.store.post
): {}
var livetime = co.srv:thread_latest_arrival_calc(p.id)
var pg: lib.str.acc pg:init(256)
pg:lpush('<div data-live="10">') -- make the OP refresh too
lib.render.tweet(co, p, &pg)
pg:lpush('</div>')
if co.aid ~= 0 then
pg:lpush('<form class="action-bar" method="post">')
if not co.srv:post_liked_uid(co.who.id, p.id)
................................................................................
render_tweet_replies(co, &pg, p.id)
pg:lpush('</div>')
if co.aid ~= 0 and co.who.rights.powers.post() then
lib.render.compose(co, nil, &pg)
end
var ppg = pg:finalize() defer ppg:free()
co:livepage([lib.srv.convo.page] {
title = lib.str.plit 'post'; cache = false;
class = lib.str.plit 'post'; body = ppg;
}, livetime)
-- TODO display conversation
-- perhaps display descendant nodes here, and have a link to the top of the whole tree?
end
return render_tweet_page
|
|
|
|
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
render_tweet_page(
co: &lib.srv.convo,
path: lib.mem.ptr(pref),
p: &lib.store.post
): {}
var livetime = co.srv:thread_latest_arrival_calc(p.id)
var pg = co:stra(256)
pg:lpush('<div data-live="10">') -- make the OP refresh too
lib.render.tweet(co, p, &pg)
pg:lpush('</div>')
if co.aid ~= 0 then
pg:lpush('<form class="action-bar" method="post">')
if not co.srv:post_liked_uid(co.who.id, p.id)
................................................................................
render_tweet_replies(co, &pg, p.id)
pg:lpush('</div>')
if co.aid ~= 0 and co.who.rights.powers.post() then
lib.render.compose(co, nil, &pg)
end
var ppg = pg:finalize() --defer ppg:free()
co:livepage([lib.srv.convo.page] {
title = lib.str.plit 'post'; cache = false;
class = lib.str.plit 'post'; body = ppg;
}, livetime)
-- TODO display conversation
-- perhaps display descendant nodes here, and have a link to the top of the whole tree?
end
return render_tweet_page
|
Modified render/tweet.t from [83917dbbe9] to [57f4f6bb5e].
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 .. 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 .. 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
retweeter = co.actorcache:insert(co.srv:actor_fetch_uid(p.rtdby)).ptr
end
::foundauth::
var timestr: int8[26] lib.osclock.ctime_r(&p.posted, ×tr[0])
for i=0,26 do if timestr[i] == @'\n' then timestr[i] = 0 break end end -- 🙄
var bhtml = lib.smackdown.html([lib.mem.ptr(int8)] {ptr=p.body,ct=0},false)
defer bhtml:free()
var idbuf: int8[lib.math.shorthand.maxlen]
var idlen = lib.math.shorthand.gen(p.id, idbuf)
var permalink: lib.str.acc permalink:compose('/post/',{idbuf,idlen})
var fullname = lib.render.nym(author,0,nil, false) defer fullname:free()
var tpl = data.view.tweet {
text = bhtml;
subject = cs(lib.coalesce(p.subject,''));
nym = fullname;
when = cs(×tr[0]);
avatar = cs(author.avatar);
................................................................................
var parent = co.srv:post_fetch(p.parent) defer parent:free()
if not parent then
lib.bail('schema integrity violation - could not match post to parent')
end
var pauth = co.srv:actor_fetch_uid(parent(0).author) defer pauth:free()
var pidbuf: int8[lib.math.shorthand.maxlen]
var pidlen = lib.math.shorthand.gen(p.parent, pidbuf)
var pa: lib.str.acc pa:init(128)
pa:lpush('<small>in reply to <a class="username" href="/post/'):push(&pidbuf[0],pidlen):lpush('">')
lib.render.nym(pauth.ptr,0,&pa,true)
pa:lpush('</a></small>')
tpl.extra = pa:finalize()
end
if p.rts + p.likes > 0 then
var s: lib.str.acc s:init(128)
s:lpush('<div class="stats">')
if p.rts > 0 then s:lpush('<div class="rt">' ):dpush(p.rts ):lpush('</div>') end
if p.likes > 0 then s:lpush('<div class="like">'):dpush(p.likes):lpush('</div>') end
s:lpush('</div>')
tpl.stats = s:finalize()
end
................................................................................
attrcur = lib.str.cpy(attrcur, '"')
end
if co.aid ~= 0 and p.author == co.who.id then attrcur = lib.str.cpy(attrcur, ' data-own') end
if retweeter ~= nil then attrcur = lib.str.cpy(attrcur, ' data-rt') end
if attrcur ~= &attrbuf[0] then tpl.attr = &attrbuf[0] end
defer tpl.permalink:free()
if acc ~= nil then
if retweeter ~= nil then push_promo_header(co, acc, retweeter, p.rtact) end
tpl:append(acc)
if retweeter ~= nil then acc:lpush('</div>') end
if p.rts + p.likes > 0 then tpl.stats:free() end
if tpl.extra.ct > 0 then tpl.extra:free() end
return [lib.mem.ptr(int8)]{ptr=nil,ct=0}
end
if retweeter ~= nil then
var rta: lib.str.acc rta:init(512)
push_promo_header(co, &rta, retweeter, p.rtact)
tpl:append(&rta) rta:lpush('</div>')
if tpl.extra.ct > 0 then tpl.extra:free() end
return rta:finalize()
else
var txt = tpl:tostr()
if tpl.extra.ct > 0 then tpl.extra:free() end
if p.rts + p.likes > 0 then tpl.stats:free() end
return txt
end
end
return render_tweet
|
| | | | | | | | | | | | | |
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 .. 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 .. 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
retweeter = co.actorcache:insert(co.srv:actor_fetch_uid(p.rtdby)).ptr end ::foundauth:: var timestr: int8[26] lib.osclock.ctime_r(&p.posted, ×tr[0]) for i=0,26 do if timestr[i] == @'\n' then timestr[i] = 0 break end end -- 🙄 var bhtml = lib.smackdown.html(&co.srv.pool, [lib.mem.ptr(int8)] {ptr=p.body,ct=0},false) --defer bhtml:free() var idbuf: int8[lib.math.shorthand.maxlen] var idlen = lib.math.shorthand.gen(p.id, idbuf) var permalink: lib.str.acc permalink:pool(&co.srv.pool, 7+idlen):lpush('/post/'):push(idbuf,idlen) var fullname = lib.render.nym(author,0,nil, false) defer fullname:free() var tpl = data.view.tweet { text = bhtml; subject = cs(lib.coalesce(p.subject,'')); nym = fullname; when = cs(×tr[0]); avatar = cs(author.avatar); ................................................................................ var parent = co.srv:post_fetch(p.parent) defer parent:free() if not parent then lib.bail('schema integrity violation - could not match post to parent') end var pauth = co.srv:actor_fetch_uid(parent(0).author) defer pauth:free() var pidbuf: int8[lib.math.shorthand.maxlen] var pidlen = lib.math.shorthand.gen(p.parent, pidbuf) var pa: lib.str.acc pa:pool(&co.srv.pool, 128) pa:lpush('<small>in reply to <a class="username" href="/post/'):push(&pidbuf[0],pidlen):lpush('">') lib.render.nym(pauth.ptr,0,&pa,true) pa:lpush('</a></small>') tpl.extra = pa:finalize() end if p.rts + p.likes > 0 then var s: lib.str.acc s:pool(&co.srv.pool,128) s:lpush('<div class="stats">') if p.rts > 0 then s:lpush('<div class="rt">' ):dpush(p.rts ):lpush('</div>') end if p.likes > 0 then s:lpush('<div class="like">'):dpush(p.likes):lpush('</div>') end s:lpush('</div>') tpl.stats = s:finalize() end ................................................................................ attrcur = lib.str.cpy(attrcur, '"') end if co.aid ~= 0 and p.author == co.who.id then attrcur = lib.str.cpy(attrcur, ' data-own') end if retweeter ~= nil then attrcur = lib.str.cpy(attrcur, ' data-rt') end if attrcur ~= &attrbuf[0] then tpl.attr = &attrbuf[0] end --defer tpl.permalink:free() if acc ~= nil then if retweeter ~= nil then push_promo_header(co, acc, retweeter, p.rtact) end tpl:append(acc) if retweeter ~= nil then acc:lpush('</div>') end --if p.rts + p.likes > 0 then tpl.stats:free() end --if tpl.extra.ct > 0 then tpl.extra:free() end return [lib.mem.ptr(int8)]{ptr=nil,ct=0} end if retweeter ~= nil then var rta: lib.str.acc rta:pool(&co.srv.pool,512) push_promo_header(co, &rta, retweeter, p.rtact) tpl:append(&rta) rta:lpush('</div>') --if tpl.extra.ct > 0 then tpl.extra:free() end return rta:finalize() else var txt = tpl:poolstr(&co.srv.pool) --if tpl.extra.ct > 0 then tpl.extra:free() end --if p.rts + p.likes > 0 then tpl.stats:free() end return txt end end return render_tweet |
Modified render/user-page.t from [e4691ec838] to [be37fdb666].
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
39
40
41
42
43
44
45
46
47
48
49
|
if co.aid ~= 0 and co.who.id == actor.id then
ti:compose('my profile')
else
ti:compose('profile :: ', actor.handle)
end
var tiptr = ti:finalize()
var acc: lib.str.acc acc:init(1024)
var pftxt = lib.render.profile(co,actor,relationship) defer pftxt:free()
acc:ppush(pftxt)
var stoptime = lib.osclock.time(nil)
var posts = co.srv:post_enum_author_uid(actor.id, lib.store.range {
mode = 1; -- T->I
from_time = stoptime;
to_idx = 64;
................................................................................
co:livepage([lib.srv.convo.page] {
title = tiptr; body = bdf;
class = lib.str.plit 'profile';
cache = false;
}, newest)
tiptr:free()
bdf:free()
end
return render_userpage
|
|
|
|
|
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
39
40
41
42
43
44
45
46
47
48
49
|
if co.aid ~= 0 and co.who.id == actor.id then
ti:compose('my profile')
else
ti:compose('profile :: ', actor.handle)
end
var tiptr = ti:finalize()
var acc: lib.str.acc acc:pool(&co.srv.pool, 1024)
var pftxt = lib.render.profile(co,actor,relationship) --defer pftxt:free()
acc:ppush(pftxt)
var stoptime = lib.osclock.time(nil)
var posts = co.srv:post_enum_author_uid(actor.id, lib.store.range {
mode = 1; -- T->I
from_time = stoptime;
to_idx = 64;
................................................................................
co:livepage([lib.srv.convo.page] {
title = tiptr; body = bdf;
class = lib.str.plit 'profile';
cache = false;
}, newest)
tiptr:free()
--bdf:free()
end
return render_userpage
|
Modified route.t from [2b1fe64d41] to [a232000d86].
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
...
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
|
else
conf = data.view.confirm {
title = lib.str.plit 'cancel retweet';
query = lib.str.plit 'are you sure you want to undo this retweet?';
cancel = lib.str.plit'/';
}
end
var body = conf:tostr() defer body:free()
co:stdpage([lib.srv.convo.page] {
title = lib.str.plit 'post :: delete';
class = lib.str.plit 'query';
body = body; cache = false;
})
return
elseif meth == method.post then
var act = co:ppostv('act')
if act:cmp(lib.str.plit 'confirm') then
if post:ref() then
post(0).source:post_destroy(post(0).id)
elseif rt.kind ~= 0 then
................................................................................
terra http.media_manager(co: &lib.srv.convo, path: hpath, meth: method.t, uid: uint64)
if co.aid ~= 0 and co.who.id == uid and path.ct == 2 and path(1):cmp(lib.str.lit'upload') and co.who.rights.powers.artifact() then
if meth == method.get then
var view = data.view.media_upload {
folders = ''
}
var pg = view:tostr() defer pg:free()
co:stdpage([lib.srv.convo.page] {
title = lib.str.plit'media :: upload';
class = lib.str.plit'media upload';
cache = false; body = pg;
})
elseif meth == method.post_file then
var desc = pstring.null()
|
|
>
>
|
|
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
...
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
|
else
conf = data.view.confirm {
title = lib.str.plit 'cancel retweet';
query = lib.str.plit 'are you sure you want to undo this retweet?';
cancel = lib.str.plit'/';
}
end
var fr = co.srv.pool:frame()
var body = conf:poolstr(&co.srv.pool) --defer body:free()
co:stdpage([lib.srv.convo.page] {
title = lib.str.plit 'post :: delete';
class = lib.str.plit 'query';
body = body; cache = false;
})
co.srv.pool:reset(fr)
return
elseif meth == method.post then
var act = co:ppostv('act')
if act:cmp(lib.str.plit 'confirm') then
if post:ref() then
post(0).source:post_destroy(post(0).id)
elseif rt.kind ~= 0 then
................................................................................
terra http.media_manager(co: &lib.srv.convo, path: hpath, meth: method.t, uid: uint64)
if co.aid ~= 0 and co.who.id == uid and path.ct == 2 and path(1):cmp(lib.str.lit'upload') and co.who.rights.powers.artifact() then
if meth == method.get then
var view = data.view.media_upload {
folders = ''
}
var pg = view:poolstr(&co.srv.pool) -- defer pg:free()
co:stdpage([lib.srv.convo.page] {
title = lib.str.plit'media :: upload';
class = lib.str.plit'media upload';
cache = false; body = pg;
})
elseif meth == method.post_file then
var desc = pstring.null()
|
Modified smackdown.t from [e99ea3e622] to [ad4d039b1c].
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
local terra scanline_wordend(l: rawstring, max: intptr, n: rawstring, nc: intptr) var sl = scanline(l,max,n,nc) if sl == nil then return nil else sl = sl + nc end if sl >= l+max or not isws(@(sl-1)) then return sl-nc end return nil end terra m.html(input: pstr, firstline: bool) if input.ptr == nil then return pstr.null() end if input.ct == 0 then input.ct = lib.str.sz(input.ptr) end var md = lib.html.sanitize(input,false) var styled: lib.str.acc styled:init(md.ct) do var i = 0 while i < md.ct do --var wordstart = (i == 0 or isws(md.ptr[i-1])) --var wordend = (i == md.ct - 1 or isws(md.ptr[i+1])) var wordstart = (i + 1 < md.ct and not isws(md.ptr[i+1])) var wordend = (i == md.ct - 1 or not isws(md.ptr[i-1])) ................................................................................ goto skip end end ::fallback::styled:push(here,1) -- :/ i = i + 1 ::skip::end end md:free() -- we make two passes: the first detects and transforms inline elements, -- the second carries out block-level organization var html: lib.str.acc html:init(styled.sz) var s = state { segt = segt.none; bqlvl = 0; curpos = md.ptr; blockstart = nil; } while s.curpos < md.ptr + md.ct do s.curpos = s.curpos + 1 end html:free() -- JUST FOR NOW return styled:finalize() end return m |
|
|
|
|
|
|
|
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
local terra scanline_wordend(l: rawstring, max: intptr, n: rawstring, nc: intptr) var sl = scanline(l,max,n,nc) if sl == nil then return nil else sl = sl + nc end if sl >= l+max or not isws(@(sl-1)) then return sl-nc end return nil end terra m.html(pool: &lib.mem.pool, input: pstr, firstline: bool) if input.ptr == nil then return pstr.null() end if input.ct == 0 then input.ct = lib.str.sz(input.ptr) end var md = lib.html.sanitize(pool,input,false) var styled: lib.str.acc styled:pool(pool,md.ct) do var i = 0 while i < md.ct do --var wordstart = (i == 0 or isws(md.ptr[i-1])) --var wordend = (i == md.ct - 1 or isws(md.ptr[i+1])) var wordstart = (i + 1 < md.ct and not isws(md.ptr[i+1])) var wordend = (i == md.ct - 1 or not isws(md.ptr[i-1])) ................................................................................ goto skip end end ::fallback::styled:push(here,1) -- :/ i = i + 1 ::skip::end end --md:free() -- we make two passes: the first detects and transforms inline elements, -- the second carries out block-level organization var html: lib.str.acc html:pool(pool,styled.sz) var s = state { segt = segt.none; bqlvl = 0; curpos = md.ptr; blockstart = nil; } while s.curpos < md.ptr + md.ct do s.curpos = s.curpos + 1 end --html:free() -- JUST FOR NOW return styled:finalize() end return m |
Modified srv.t from [80adbc5ad3] to [854410a8ca].
5 6 7 8 9 10 11 12 13 14 15 16 17 18 .. 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ... 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 ... 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 ... 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 ... 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 ... 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 ... 853 854 855 856 857 858 859 860 861 862 863 864 865 866 ... 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 ... 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 ... 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 |
local struct srv
local struct cfgcache {
secret: pstring
pol_sec: secmode.t
pol_reg: bool
credmgd: bool
maxupsz: intptr
instance: pstring
overlord: &srv
ui_cue_staff: pstring
ui_cue_founder: pstring
ui_hue: uint16
nranks: uint16
maxinvites: uint16
................................................................................
}
local struct srv {
sources: lib.mem.ptr(lib.store.source)
webmgr: lib.net.mg_mgr
webcon: &lib.net.mg_connection
cfg: cfgcache
id: rawstring
}
terra cfgcache:free() -- :/
self.secret:free()
self.instance:free()
self.ui_cue_staff:free()
self.ui_cue_founder:free()
................................................................................
terra convo:confirm(title: pstring, msg: pstring, cancel: pstring)
var conf = data.view.confirm {
title = title;
query = msg;
cancel = cancel;
}
var ti: lib.str.acc ti:compose('confirm :: ', title)
var body = conf:tostr() defer body:free()
var cf = [convo.page] {
title = ti:finalize();
class = lib.str.plit 'query';
body = body; cache = false;
}
self:stdpage(cf)
cf.title:free()
end
convo.methods.assertpow = macro(function(self, pow)
return quote
var ok = true
if self.aid == 0 or self.who.rights.powers.[pow:asvalue()]() == false then
ok = false
................................................................................
end
in ok end
end)
-- CALL ONLY ONCE PER VAR
terra convo:postv(name: rawstring)
if self.varbuf.ptr == nil then
self.varbuf = lib.mem.heapa(int8, self.msg.body.len + self.msg.query.len)
self.vbofs = self.varbuf.ptr
end
var o = lib.net.mg_http_get_var(&self.msg.body, name, self.vbofs, self.varbuf.ct - (self.vbofs - self.varbuf.ptr))
if o > 0 then
var r = self.vbofs
self.vbofs = self.vbofs + o + 1
@(self.vbofs - 1) = 0
................................................................................
terra convo:ppostv(name: rawstring)
var s,l = self:postv(name)
return pstring { ptr = s, ct = l }
end
terra convo:getv(name: rawstring)
if self.varbuf.ptr == nil then
self.varbuf = lib.mem.heapa(int8, self.msg.query.len + self.msg.body.len)
self.vbofs = self.varbuf.ptr
end
var o = lib.net.mg_http_get_var(&self.msg.query, name, self.vbofs, self.varbuf.ct - (self.vbofs - self.varbuf.ptr))
if o > 0 then
var r = self.vbofs
self.vbofs = self.vbofs + o + 1
@(self.vbofs - 1) = 0
................................................................................
var livelast_p = lib.http.findheader(msg, 'X-Live-Last-Arrival')
if livelast_p ~= nil and livelast_p.ptr ~= nil then
var ll, ok = lib.math.decparse(pstring{ptr = livelast_p.ptr, ct = livelast_p.ct - 1})
if ok then co.live_last = ll end
end
var uridec = lib.mem.heapa(int8, msg.uri.len) defer uridec:free()
var urideclen = lib.net.mg_url_decode(msg.uri.ptr, msg.uri.len, uridec.ptr, uridec.ct, 1)
var uri = uridec
if urideclen == -1 then
for i = 0,msg.uri.len do
if msg.uri.ptr[i] == @'+'
then uri.ptr[i] = @' '
................................................................................
bsr:free()
upmap:free()
end
end
end
route.dispatch_http(&co, uri, co.method)
if co.uploads.run > 0 then
for i=0,co.uploads.sz do
co.uploads(i).filename:free()
co.uploads(i).field:free()
end
co.uploads:free()
end
::fail::
if co.aid ~= 0 then lib.mem.heapf(co.who) end
if co.varbuf.ptr ~= nil then co.varbuf:free() end
if co.navbar.ptr ~= nil then co.navbar:free() end
co.actorcache:free()
end
end
end;
}
local terra cfg(s: &srv, befile: rawstring)
lib.report('configuring backends from ', befile)
................................................................................
lib.bail('could not connect to any data sources!')
end
end
terra srv:start(iname: rawstring)
self:conprep(lib.store.prepmode.full)
self.cfg:init(self)
var dbbind = self:conf_get('bind')
if iname == nil then iname = lib.proc.getenv('parsav_instance') end
if iname == nil then
self.id = self.cfg.instance.ptr;
-- let this leak -- it'll be needed for the lifetime of the process anyway
else self.id = iname end
................................................................................
terra srv:shutdown()
lib.net.mg_mgr_free(&self.webmgr)
for i=0,self.sources.ct do var src = self.sources.ptr + i
lib.report('closing data source ', src.id.ptr, '(', src.backend.id, ')')
src:close()
end
self.sources:free()
end
terra cfgcache:cfint(name: rawstring, default: intptr)
var str = self.overlord:conf_get(name)
if str.ptr ~= nil then
var i,ok = lib.math.decparse(str)
if ok then default = i else
lib.warn('invalid configuration setting ',name,'="',{str.ptr,str.ct},'", expected integer; using default value instead')
end
str:free()
end
return default
end
terra cfgcache:cfbool(name: rawstring, default: bool)
var str = self.overlord:conf_get(name)
if str.ptr ~= nil then
................................................................................
if lib.str.cmp(sreg.ptr, 'managed') == 0
then self.credmgd = true
else self.credmgd = false
end
sreg:free()
end end
do self.maxupsz = [1024 * 100] -- 100 kilobyte default
var sreg = self.overlord:conf_get('maximum-artifact-size')
if sreg:ref() then
var sz, ok = lib.math.fsz_parse(sreg)
if ok then self.maxupsz = sz else
lib.warn('invalid configuration value for maximum-artifact-size; keeping default 100K upload limit')
end
sreg:free() end
end
self.pol_sec = secmode.lockdown
var smode = self.overlord:conf_get('policy-security')
if smode.ptr ~= nil then
if lib.str.cmp(smode.ptr, 'public') == 0 then
self.pol_sec = secmode.public
elseif lib.str.cmp(smode.ptr, 'private') == 0 then
................................................................................
self.nranks = self:cfint('user-ranks',10)
self.maxinvites = self:cfint('max-invites',64)
var webmaster = self.overlord:conf_get('master')
if webmaster:ref() then defer webmaster:free()
var wma = self.overlord:actor_fetch_xid(webmaster)
if not wma then
lib.warn('the webmaster specified in the configuration store does not seem to exist or is not known to this instance; preceding as if no master defined. if the master is a remote user, you can rectify this with the `actor ',{webmaster.ptr,webmaster.ct},' instantiate` and `conf refresh` commands')
else
self.master = wma(0).id
wma:free()
end
end
self.ui_cue_staff = self.overlord:conf_get('ui-profile-cue-staff')
|
> > | | | > > > > > > | | | > > < | | > > > > > > > > > > > > > > > | | < < < < < < < | |
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 .. 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 ... 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 ... 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 ... 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 ... 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 ... 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 ... 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 ... 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 ... 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 ... 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 |
local struct srv
local struct cfgcache {
secret: pstring
pol_sec: secmode.t
pol_reg: bool
credmgd: bool
maxupsz: intptr
poolinitsz: intptr
instance: pstring
overlord: &srv
ui_cue_staff: pstring
ui_cue_founder: pstring
ui_hue: uint16
nranks: uint16
maxinvites: uint16
................................................................................
}
local struct srv {
sources: lib.mem.ptr(lib.store.source)
webmgr: lib.net.mg_mgr
webcon: &lib.net.mg_connection
cfg: cfgcache
id: rawstring
pool: lib.mem.pool
}
terra cfgcache:free() -- :/
self.secret:free()
self.instance:free()
self.ui_cue_staff:free()
self.ui_cue_founder:free()
................................................................................
terra convo:confirm(title: pstring, msg: pstring, cancel: pstring)
var conf = data.view.confirm {
title = title;
query = msg;
cancel = cancel;
}
var ti: lib.str.acc ti:pcompose(&self.srv.pool,'confirm :: ', title)
var body = conf:poolstr(&self.srv.pool) -- defer body:free()
var cf = [convo.page] {
title = ti:finalize();
class = lib.str.plit 'query';
body = body; cache = false;
}
self:stdpage(cf)
--cf.title:free()
end
terra convo:stra(sz: intptr) -- convenience function
var s: lib.str.acc
s:pool(&self.srv.pool,sz)
return s
end
convo.methods.assertpow = macro(function(self, pow)
return quote
var ok = true
if self.aid == 0 or self.who.rights.powers.[pow:asvalue()]() == false then
ok = false
................................................................................
end
in ok end
end)
-- CALL ONLY ONCE PER VAR
terra convo:postv(name: rawstring)
if self.varbuf.ptr == nil then
self.varbuf = self.srv.pool:alloc(int8, self.msg.body.len + self.msg.query.len)
self.vbofs = self.varbuf.ptr
end
var o = lib.net.mg_http_get_var(&self.msg.body, name, self.vbofs, self.varbuf.ct - (self.vbofs - self.varbuf.ptr))
if o > 0 then
var r = self.vbofs
self.vbofs = self.vbofs + o + 1
@(self.vbofs - 1) = 0
................................................................................
terra convo:ppostv(name: rawstring)
var s,l = self:postv(name)
return pstring { ptr = s, ct = l }
end
terra convo:getv(name: rawstring)
if self.varbuf.ptr == nil then
self.varbuf = self.srv.pool:alloc(int8, self.msg.query.len + self.msg.body.len)
self.vbofs = self.varbuf.ptr
end
var o = lib.net.mg_http_get_var(&self.msg.query, name, self.vbofs, self.varbuf.ct - (self.vbofs - self.varbuf.ptr))
if o > 0 then
var r = self.vbofs
self.vbofs = self.vbofs + o + 1
@(self.vbofs - 1) = 0
................................................................................
var livelast_p = lib.http.findheader(msg, 'X-Live-Last-Arrival')
if livelast_p ~= nil and livelast_p.ptr ~= nil then
var ll, ok = lib.math.decparse(pstring{ptr = livelast_p.ptr, ct = livelast_p.ct - 1})
if ok then co.live_last = ll end
end
var uridec = server.pool:alloc(int8, msg.uri.len)
var urideclen = lib.net.mg_url_decode(msg.uri.ptr, msg.uri.len, uridec.ptr, uridec.ct, 1)
var uri = uridec
if urideclen == -1 then
for i = 0,msg.uri.len do
if msg.uri.ptr[i] == @'+'
then uri.ptr[i] = @' '
................................................................................
bsr:free()
upmap:free()
end
end
end
route.dispatch_http(&co, uri, co.method)
::fail::
if co.uploads.run > 0 then
for i=0,co.uploads.sz do
co.uploads(i).filename:free()
co.uploads(i).field:free()
end
co.uploads:free()
end
if co.aid ~= 0 then lib.mem.heapf(co.who) end
-- if co.varbuf.ptr ~= nil then co.varbuf:free() end
-- if co.navbar.ptr ~= nil then co.navbar:free() end
co.actorcache:free()
server.pool:clear()
end
end
end;
}
local terra cfg(s: &srv, befile: rawstring)
lib.report('configuring backends from ', befile)
................................................................................
lib.bail('could not connect to any data sources!')
end
end
terra srv:start(iname: rawstring)
self:conprep(lib.store.prepmode.full)
self.cfg:init(self)
self.pool:init(self.cfg.poolinitsz)
var dbbind = self:conf_get('bind')
if iname == nil then iname = lib.proc.getenv('parsav_instance') end
if iname == nil then
self.id = self.cfg.instance.ptr;
-- let this leak -- it'll be needed for the lifetime of the process anyway
else self.id = iname end
................................................................................
terra srv:shutdown()
lib.net.mg_mgr_free(&self.webmgr)
for i=0,self.sources.ct do var src = self.sources.ptr + i
lib.report('closing data source ', src.id.ptr, '(', src.backend.id, ')')
src:close()
end
self.sources:free()
self.pool:free()
end
terra cfgcache:cfint(name: rawstring, default: intptr)
var str = self.overlord:conf_get(name)
if str.ptr ~= nil then
var i,ok = lib.math.decparse(str)
if ok then default = i else
lib.warn('invalid configuration setting ',name,'="',{str.ptr,str.ct},'", expected integer; using default value instead')
end
str:free()
end
return default
end
terra cfgcache:cffsz(name: rawstring, default: intptr)
var str = self.overlord:conf_get(name)
if str:ref() then
var sz, ok = lib.math.fsz_parse(str)
if ok then default = sz else
lib.warn('invalid configuration setting ',name,'="',{str.ptr,str.ct},'", expected byte length; using default value instead')
end
str:free()
end
return default
end
terra cfgcache:cfbool(name: rawstring, default: bool)
var str = self.overlord:conf_get(name)
if str.ptr ~= nil then
................................................................................
if lib.str.cmp(sreg.ptr, 'managed') == 0
then self.credmgd = true
else self.credmgd = false
end
sreg:free()
end end
self.maxupsz = self:cffsz('maximum-artifact-size', [1024 * 100]) -- 100 kilobyte default
self.poolinitsz = self:cffsz('server-pool-size-initial', [1024 * 10]) -- 10 kilobyte default
self.pol_sec = secmode.lockdown
var smode = self.overlord:conf_get('policy-security')
if smode.ptr ~= nil then
if lib.str.cmp(smode.ptr, 'public') == 0 then
self.pol_sec = secmode.public
elseif lib.str.cmp(smode.ptr, 'private') == 0 then
................................................................................
self.nranks = self:cfint('user-ranks',10)
self.maxinvites = self:cfint('max-invites',64)
var webmaster = self.overlord:conf_get('master')
if webmaster:ref() then defer webmaster:free()
var wma = self.overlord:actor_fetch_xid(webmaster)
if not wma then
lib.warn('the webmaster specified in the configuration store does not seem to exist or is not known to this instance; preceding as if no master defined. if the master is a remote user, you can rectify this with the `actor "',{webmaster.ptr,webmaster.ct},'" instantiate` and `conf refresh` commands')
else
self.master = wma(0).id
wma:free()
end
end
self.ui_cue_staff = self.overlord:conf_get('ui-profile-cue-staff')
|
Modified str.t from [d98a573fe7] to [89921fa130].
107 108 109 110 111 112 113 114 115 116 117 118 119 120 ... 127 128 129 130 131 132 133 134 135 136 137 138 139 140 ... 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 ... 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 ... 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 ... 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 ... 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
end
struct m.acc {
buf: rawstring
sz: intptr
run: intptr
space: intptr
}
terra m.cdowncase(c: int8)
if c >= @'A' and c <= @'Z' then
return c + (@'a' - @'A')
else return c end
end
................................................................................
local terra biggest(a: intptr, b: intptr)
if a > b then return a else return b end
end
terra m.acc:init(run: intptr)
--lib.dbg('initializing string accumulator')
if run == 0 then
lib.warn('attempted to allocate zero-length string accumulator')
self.buf = nil
else
self.buf = [rawstring](lib.mem.heapa_raw(run))
if self.buf == nil then
lib.warn('string buffer allocation failed, very little memory availble')
................................................................................
end
end
self.run = lib.trn(self.buf == nil, 0, run)
self.space = self.run
self.sz = 0
return self
end;
terra m.acc:free()
--lib.dbg('freeing string accumulator')
if self.buf ~= nil and self.space > 0 then
lib.mem.heapf(self.buf)
end
end;
terra m.acc:crush()
--lib.dbg('crushing string accumulator')
self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.sz))
self.space = self.sz
return self
end;
terra m.acc:finalize()
--lib.dbg('finalizing string accumulator')
................................................................................
self.buf = nil
self.sz = 0
return pt
end;
terra m.acc:cue(sz: intptr)
if sz <= self.run then return end
self.run = sz
if self.space - self.sz < self.run then
self.space = self.sz + self.run
self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space))
end
end
terra m.acc:reset() -- semantic convenience function
self.sz = 0
end
................................................................................
if str == nil then return self end
--if str[len - 1] == 0xA then llen = llen - 1 end -- don't display newlines in debug output
-- lib.dbg('pushing "',{str,llen},'" onto accumulator')
if self.buf == nil then self:init(self.run) end
if self.buf == nil then lib.warn('attempted to push string onto unallocated accumulator') return self end
if len == 0 then len = m.sz(str) end
if len >= self.space - self.sz then
self.space = self.space + biggest(self.run,len + 1)
self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space))
end
lib.mem.cpy(self.buf + self.sz, str, len)
self.sz = self.sz + len
self.buf[self.sz] = 0
return self
end;
................................................................................
return `self:push([str:asvalue()], [#(str:asvalue())]) end)
m.acc.methods.ppush = terra(self: &m.acc, str: lib.mem.ptr(int8))
self:push(str.ptr, str.ct) return self end;
m.acc.methods.rpush = terra(self: &m.acc, str: lib.mem.ref(int8))
self:push(str.ptr, str.ct) return self end;
m.acc.methods.merge = terra(self: &m.acc, str: lib.mem.ptr(int8))
self:push(str.ptr, str.ct) str:free() return self end;
m.acc.methods.compose = macro(function(self, ...)
local minlen = 0
local pstrs = {}
for i,v in ipairs{...} do
if type(v) == 'table' then
local gl = 16 -- guess wildly
if v.tree and v.tree.type.convertible == 'tuple' then
pstrs[#pstrs+1] = {str = `v._0, len = `v._1}
................................................................................
else pstrs[#pstrs+1] = {str = v, len = 0} end
minlen = minlen + gl
elseif type(v) == 'string' then
pstrs[#pstrs+1] = {str = v, len = #v}
minlen = minlen + #v + 1
else error('invalid type in compose expression') end
end
local call = `self:init(minlen)
for i,v in ipairs(pstrs) do
call = `[call]:push([v.str],[v.len])
end
return call
end)
m.acc.metamethods.__lshift = terralib.overloadedfunction('(<<)', {
terra(self: &m.acc, str: rawstring) return self: push(str,0) end;
terra(self: &m.acc, str: lib.mem.ptr(int8)) return self:ppush(str ) end;
})
m.box = terralib.memoize(function(ty)
local b = struct {
|
> > > > > > > > > > > > > > > > > > > > | > > | | | | | > > > > > > > |
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 ... 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 ... 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 ... 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 ... 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 ... 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 ... 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
end
struct m.acc {
buf: rawstring
sz: intptr
run: intptr
space: intptr
pool: &lib.mem.pool
}
terra m.cdowncase(c: int8)
if c >= @'A' and c <= @'Z' then
return c + (@'a' - @'A')
else return c end
end
................................................................................
local terra biggest(a: intptr, b: intptr)
if a > b then return a else return b end
end
terra m.acc:init(run: intptr)
--lib.dbg('initializing string accumulator')
self.pool = nil
if run == 0 then
lib.warn('attempted to allocate zero-length string accumulator')
self.buf = nil
else
self.buf = [rawstring](lib.mem.heapa_raw(run))
if self.buf == nil then
lib.warn('string buffer allocation failed, very little memory availble')
................................................................................
end
end
self.run = lib.trn(self.buf == nil, 0, run)
self.space = self.run
self.sz = 0
return self
end;
terra m.acc:pool(pool: &lib.mem.pool, run: intptr)
self.buf = [&int8](pool:alloc_bytes(run))
self.pool = pool
self.run = run
self.space = self.run
self.sz = 0
return self
end
terra m.acc:free()
--lib.dbg('freeing string accumulator')
if self.pool ~= nil then
lib.dbg('attempted to free pooled string accumulator; use frame-reset instead')
return
end
if self.buf ~= nil and self.space > 0 then
lib.mem.heapf(self.buf)
end
end;
terra m.acc:crush()
--lib.dbg('crushing string accumulator')
if self.pool ~= nil then return self end -- no point unless at end of buffer
self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.sz))
self.space = self.sz
return self
end;
terra m.acc:finalize()
--lib.dbg('finalizing string accumulator')
................................................................................
self.buf = nil
self.sz = 0
return pt
end;
terra m.acc:cue(sz: intptr)
if sz <= self.run then return end
var curspace = self.space
self.run = sz
if self.space - self.sz < self.run then
self.space = self.sz + self.run
if self.pool ~= nil then
self.buf = [&int8](self.pool:realloc_bytes(self.buf, curspace, self.space))
else
self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space))
end
end
end
terra m.acc:reset() -- semantic convenience function
self.sz = 0
end
................................................................................
if str == nil then return self end
--if str[len - 1] == 0xA then llen = llen - 1 end -- don't display newlines in debug output
-- lib.dbg('pushing "',{str,llen},'" onto accumulator')
if self.buf == nil then self:init(self.run) end
if self.buf == nil then lib.warn('attempted to push string onto unallocated accumulator') return self end
if len == 0 then len = m.sz(str) end
if len >= self.space - self.sz then
self:cue(self.space + biggest(self.run,len + 1))
--self.space = self.space + biggest(self.run,len + 1)
--self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space))
end
lib.mem.cpy(self.buf + self.sz, str, len)
self.sz = self.sz + len
self.buf[self.sz] = 0
return self
end;
................................................................................
return `self:push([str:asvalue()], [#(str:asvalue())]) end)
m.acc.methods.ppush = terra(self: &m.acc, str: lib.mem.ptr(int8))
self:push(str.ptr, str.ct) return self end;
m.acc.methods.rpush = terra(self: &m.acc, str: lib.mem.ref(int8))
self:push(str.ptr, str.ct) return self end;
m.acc.methods.merge = terra(self: &m.acc, str: lib.mem.ptr(int8))
self:push(str.ptr, str.ct) str:free() return self end;
local composefn = function(call, ...)
local minlen = 0
local pstrs = {}
for i,v in ipairs{...} do
if type(v) == 'table' then
local gl = 16 -- guess wildly
if v.tree and v.tree.type.convertible == 'tuple' then
pstrs[#pstrs+1] = {str = `v._0, len = `v._1}
................................................................................
else pstrs[#pstrs+1] = {str = v, len = 0} end
minlen = minlen + gl
elseif type(v) == 'string' then
pstrs[#pstrs+1] = {str = v, len = #v}
minlen = minlen + #v + 1
else error('invalid type in compose expression') end
end
call = call(minlen) --`self:init(minlen)
for i,v in ipairs(pstrs) do
call = `[call]:push([v.str],[v.len])
end
return call
end
m.acc.methods.compose = macro(function(self, ...)
return composefn(function(minlen) return `self:init(minlen) end, ...)
end)
m.acc.methods.pcompose = macro(function(self, pool, ...)
return composefn(function(minlen) return `self:pool(pool,minlen) end, ...)
end)
m.acc.metamethods.__lshift = terralib.overloadedfunction('(<<)', {
terra(self: &m.acc, str: rawstring) return self: push(str,0) end;
terra(self: &m.acc, str: lib.mem.ptr(int8)) return self:ppush(str ) end;
})
m.box = terralib.memoize(function(ty)
local b = struct {
|
Modified tpl.t from [9f68e11c52] to [db48a650e7].
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
end
local copiers = {}
local senders = {}
local appenders = {}
local symtxt = symbol(lib.mem.ptr(int8))
local cpypos = symbol(&opaque)
local accumulator = symbol(&lib.str.acc)
local destcon = symbol(&lib.net.mg_connection)
for idx, seg in ipairs(segs) do
copiers[#copiers+1] = quote [cpypos] = lib.mem.cpy([cpypos], [&opaque]([seg]), [#seg]) end
senders[#senders+1] = quote lib.net.mg_send([destcon], [seg], [#seg]) end
appenders[#appenders+1] = quote [accumulator]:push([seg], [#seg]) end
if fields[idx] and fields[idx].mode then
local f = fields[idx]
local fp = `symself.[f.key]
copiers[#copiers+1] = quote
if fp.ct > 0 then
var san = lib.html.sanitize(fp, [f.mode == ':'])
[cpypos] = lib.mem.cpy([cpypos], [&opaque](san.ptr), san.ct)
--san:free()
end
end
senders[#senders+1] = quote
if fp.ct > 0 then
var san = lib.html.sanitize(fp, [f.mode == ':'])
lib.net.mg_send([destcon], san.ptr, san.ct)
--san:free()
end
end
appenders[#appenders+1] = quote
if fp.ct > 0 then
var san = lib.html.sanitize(fp, [f.mode == ':'])
[accumulator]:ppush(san)
--san:free()
end
end
elseif fields[idx] then
local f = fields[idx]
local fp = `symself.[f.key]
................................................................................
appenders[#appenders+1] = quote
if fp.ct > 0 then [accumulator]:ppush(fp) end
end
end
end
local tid = tplspec.id or '<anonymous>'
rec.methods.tostr = terra([symself])
lib.dbg(['compiling template ' .. tid])
[tallyup]
var [symtxt] = lib.mem.heapa(int8, [runningtally])
var [cpypos] = [&opaque](symtxt.ptr)
[copiers]
@[&int8](cpypos) = 0
symtxt.ct = [&int8](cpypos) - symtxt.ptr
return symtxt
end
rec.methods.append = terra([symself], [accumulator])
lib.dbg(['appending template ' .. tid])
[tallyup]
accumulator:cue([runningtally])
[appenders]
return accumulator
end
rec.methods.head = terra([symself], [destcon], code: uint16, hd: lib.mem.ptr(lib.http.header))
lib.dbg(['transmitting template headers ' .. tid])
[tallyup]
lib.net.mg_printf([destcon], 'HTTP/1.1 %s', lib.http.codestr(code))
for i = 0, hd.ct do
lib.net.mg_printf([destcon], '%s: %s\r\n', hd.ptr[i].key, hd.ptr[i].value)
end
lib.net.mg_printf([destcon],'Content-Length: %llu\r\n\r\n', [runningtally] + 1)
end
rec.methods.send = terra([symself], [destcon], code: uint16, hd: lib.mem.ptr(lib.http.header))
lib.dbg(['transmitting template ' .. tid])
symself:head(destcon,code,hd)
[senders]
lib.net.mg_send([destcon],'\r\n',2)
end
rec.methods.sz = terra([symself])
lib.dbg(['tallying template ' .. tid])
[tallyup]
return [runningtally] + 1
end
return rec
end
return m
|
>
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
end
local copiers = {}
local senders = {}
local appenders = {}
local symtxt = symbol(lib.mem.ptr(int8))
local cpypos = symbol(&opaque)
local pool = symbol(&lib.mem.pool)
local accumulator = symbol(&lib.str.acc)
local destcon = symbol(&lib.net.mg_connection)
for idx, seg in ipairs(segs) do
copiers[#copiers+1] = quote [cpypos] = lib.mem.cpy([cpypos], [&opaque]([seg]), [#seg]) end
senders[#senders+1] = quote lib.net.mg_send([destcon], [seg], [#seg]) end
appenders[#appenders+1] = quote [accumulator]:push([seg], [#seg]) end
if fields[idx] and fields[idx].mode then
local f = fields[idx]
local fp = `symself.[f.key]
copiers[#copiers+1] = quote
if fp.ct > 0 then
var san = lib.html.sanitize(pool, fp, [f.mode == ':'])
[cpypos] = lib.mem.cpy([cpypos], [&opaque](san.ptr), san.ct)
--san:free()
end
end
senders[#senders+1] = quote
if fp.ct > 0 then
var san = lib.html.sanitize(pool, fp, [f.mode == ':'])
lib.net.mg_send([destcon], san.ptr, san.ct)
--san:free()
end
end
appenders[#appenders+1] = quote
if fp.ct > 0 then
var san = lib.html.sanitize(pool, fp, [f.mode == ':'])
[accumulator]:ppush(san)
--san:free()
end
end
elseif fields[idx] then
local f = fields[idx]
local fp = `symself.[f.key]
................................................................................
appenders[#appenders+1] = quote
if fp.ct > 0 then [accumulator]:ppush(fp) end
end
end
end
local tid = tplspec.id or '<anonymous>'
rec.methods.poolstr = terra([symself],[pool])
lib.dbg(['pooling template ' .. tid])
[tallyup]
var [symtxt] = pool:alloc(int8, [runningtally])
var [cpypos] = [&opaque](symtxt.ptr)
[copiers]
@[&int8](cpypos) = 0
symtxt.ct = [&int8](cpypos) - symtxt.ptr
return symtxt
end
rec.methods.tostr = terra([symself])
lib.dbg(['compiling template ' .. tid])
[tallyup]
var [symtxt] = lib.mem.heapa(int8, [runningtally])
var [cpypos] = [&opaque](symtxt.ptr)
var p: lib.mem.pool p:init(128)
var [pool] = &p
[copiers]
@[&int8](cpypos) = 0
symtxt.ct = [&int8](cpypos) - symtxt.ptr
pool:free()
return symtxt
end
rec.methods.append = terra([symself], [accumulator])
var [pool]
var p: lib.mem.pool
if [accumulator].pool == nil then
p:init(128)
pool = &p
else pool = [accumulator].pool end
lib.dbg(['appending template ' .. tid])
[tallyup]
accumulator:cue([runningtally])
[appenders]
if [accumulator].pool == nil then p:free() end
return accumulator
end
rec.methods.head = terra([symself], [destcon], code: uint16, hd: lib.mem.ptr(lib.http.header))
var p: lib.mem.pool p:init(128) -- FIXME
var [pool] = &p
lib.dbg(['transmitting template headers ' .. tid])
[tallyup]
lib.net.mg_printf([destcon], 'HTTP/1.1 %s', lib.http.codestr(code))
for i = 0, hd.ct do
lib.net.mg_printf([destcon], '%s: %s\r\n', hd.ptr[i].key, hd.ptr[i].value)
end
lib.net.mg_printf([destcon],'Content-Length: %llu\r\n\r\n', [runningtally] + 1)
p:free()
end
rec.methods.send = terra([symself], [destcon], code: uint16, hd: lib.mem.ptr(lib.http.header))
var p: lib.mem.pool p:init(128) -- FIXME
var [pool] = &p
lib.dbg(['transmitting template ' .. tid])
symself:head(destcon,code,hd)
[senders]
lib.net.mg_send([destcon],'\r\n',2)
p:free()
end
rec.methods.sz = terra([symself])
lib.dbg(['tallying template ' .. tid])
[tallyup]
return [runningtally] + 1
end
return rec
end
return m
|