| Comment: | iteration and important api adjustments |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
f9559a83fc2d82b62dc5aed0a13e9802 |
| User & Date: | lexi on 2020-12-25 23:37:28 |
| Other Links: | manifest | tags |
|
2020-12-27
| ||
| 02:31 | permissions work now check-in: bbfea467bf user: lexi tags: trunk | |
|
2020-12-25
| ||
| 23:37 | iteration and important api adjustments check-in: f9559a83fc user: lexi tags: trunk | |
| 03:59 | big ol iteration check-in: 5b3a03ad34 user: lexi tags: trunk | |
Added acl.t version [3939510d0a].
> |
1 |
-- vim: ft=terra
|
Modified backend/pgsql.t from [0ea1a47601] to [1740166796].
1 2 3 4 5 6 7 8 .. 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 .. 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 .. 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 ... 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 ... 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 ... 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 ... 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 ... 550 551 552 553 554 555 556 557 558 559 |
-- vim: ft=terra
local queries = {
conf_get = {
params = {rawstring}, sql = [[
select value from parsav_config
where key = $1::text limit 1
]];
};
................................................................................
delete from parsav_config where
key = $1::text
]];
};
actor_fetch_uid = {
params = {uint64}, sql = [[
select
id, nym, handle, origin, bio,
avataruri, rank, quota, key,
extract(epoch from knownsince)::bigint
from parsav_actors
where id = $1::bigint
]];
};
actor_fetch_xid = {
params = {lib.mem.ptr(int8)}, sql = [[
select a.id, a.nym, a.handle, a.origin, a.bio,
a.avataruri, a.rank, a.quota, a.key,
extract(epoch from knownsince)::bigint,
coalesce(a.handle || '@' || s.domain,
'@' || a.handle) as xid,
coalesce(s.domain,
(select value from parsav_config
where key='domain' limit 1)) as domain
................................................................................
(a.origin is null and
$1::text = a.handle or
$1::text = ('@' || a.handle))
]];
};
actor_auth_pw = {
params = {lib.mem.ptr(int8),rawstring,lib.mem.ptr(int8),lib.store.inet}, sql = [[
select a.aid from parsav_auth as a
left join parsav_actors as u on u.id = a.uid
where (a.uid is null or u.handle = $1::text or (
a.uid = 0 and a.name = $1::text
)) and
(a.kind = 'trust' or (a.kind = $2::text and a.cred = $3::bytea)) and
(a.netmask is null or a.netmask >> $4::inet)
................................................................................
]];
};
actor_enum = {
params = {}, sql = [[
select a.id, a.nym, a.handle, a.origin, a.bio,
a.avataruri, a.rank, a.quota, a.key,
extract(epoch from knownsince)::bigint,
coalesce(a.handle || '@' || s.domain,
'@' || a.handle) as xid
from parsav_actors a
left join parsav_servers s on s.id = a.origin
]];
};
................................................................................
]]; -- cheat
};
actor_session_fetch = {
params = {uint64, lib.store.inet}, sql = [[
select a.id, a.nym, a.handle, a.origin, a.bio,
a.avataruri, a.rank, a.quota, a.key,
extract(epoch from knownsince)::bigint,
coalesce(a.handle || '@' || s.domain,
'@' || a.handle) as xid,
au.restrict,
array['post' ] <@ au.restrict as can_post,
array['edit' ] <@ au.restrict as can_edit,
array['acct' ] <@ au.restrict as can_acct,
................................................................................
left join parsav_actors a on au.uid = a.id
left join parsav_servers s on a.origin = s.id
where au.aid = $1::bigint and au.blacklist = false and
(au.netmask is null or au.netmask >> $2::inet)
]];
};
}
local struct pqr {
sz: intptr
res: &lib.pq.PGresult
}
terra pqr:free() if self.sz > 0 then lib.pq.PQclear(self.res) end end
terra pqr:null(row: intptr, col: intptr)
................................................................................
;[pqt[lib.store.inet](false)]([args[i]], [&uint8](&ipbuf))
in &ipbuf[0] end
dumpers[#dumpers+1] = `lib.io.fmt([tostring(i)..'. got inet\n'])
elseif ty.ptr_basetype == int8 or ty.ptr_basetype == uint8 then
counters[i] = `[args[i]].ct
casts[i] = `[&int8]([args[i]].ptr)
dumpers[#dumpers+1] = `lib.io.fmt([tostring(i)..'. got ptr %llu %.*s\n'], [args[i]].ct, [args[i]].ct, [args[i]].ptr)
elseif ty:isintegral() then
counters[i] = ty.bytes
casts[i] = `[&int8](&[args[i]])
dumpers[#dumpers+1] = `lib.io.fmt([tostring(i)..'. got int %llu\n'], [args[i]])
fixers[#fixers + 1] = quote
--lib.io.fmt('uid=%llu(%llx)\n',[args[i]],[args[i]])
[args[i]] = lib.math.netswap(ty, [args[i]])
end
end
end
terra q.exec(src: &lib.store.source, [args])
var params = arrayof([&int8], [casts])
................................................................................
return pqr {0, nil}
else
return pqr {ct, res}
end
end
end
local terra row_to_actor(r: &pqr, row: intptr): lib.mem.ptr(lib.store.actor)
var a: lib.mem.ptr(lib.store.actor)
if r:cols() >= 9 then
a = [ lib.str.encapsulate(lib.store.actor, {
nym = {`r:string(row,1), `r:len(row,1)+1};
bio = {`r:string(row,4), `r:len(row,4)+1};
avatar = {`r:string(row,5), `r:len(row,5)+1};
handle = {`r:string(row, 2); `r:len(row,2) + 1};
xid = {`r:string(row, 10); `r:len(row,10) + 1};
}) ]
else
a = [ lib.str.encapsulate(lib.store.actor, {
nym = {`r:string(row,1), `r:len(row,1)+1};
bio = {`r:string(row,4), `r:len(row,4)+1};
avatar = {`r:string(row,5), `r:len(row,5)+1};
handle = {`r:string(row, 2); `r:len(row,2) + 1};
}) ]
a.ptr.xid = nil
end
a.ptr.id = r:int(uint64, row, 0);
a.ptr.rights = lib.store.rights_default();
a.ptr.rights.rank = r:int(uint16, row, 6);
a.ptr.rights.quota = r:int(uint32, row, 7);
a.ptr.knownsince = r:int(int64,row, 9);
if r:null(row,8) then
a.ptr.key.ct = 0 a.ptr.key.ptr = nil
................................................................................
return au, a
end
::fail:: return [lib.stat (lib.store.auth) ] { ok = false },
[lib.mem.ptr(lib.store.actor)] { ptr = nil, ct = 0 }
end];
}
return b
|
> > | | < | > > | > > | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | | < > | > > > > | < > | | < < > | < > > > > > > > > > > > > > | > > > > | > > > | > > > | > > > > > > | > | < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 .. 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 .. 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 .. 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 ... 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 ... 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 ... 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 ... 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 ... 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 |
-- vim: ft=terra local pstring = lib.mem.ptr(int8) local binblob = lib.mem.ptr(uint8) local queries = { conf_get = { params = {rawstring}, sql = [[ select value from parsav_config where key = $1::text limit 1 ]]; }; ................................................................................ delete from parsav_config where key = $1::text ]]; }; actor_fetch_uid = { params = {uint64}, sql = [[ select a.id, a.nym, a.handle, a.origin, a.bio, a.avataruri, a.rank, a.quota, a.key, extract(epoch from a.knownsince)::bigint, coalesce(a.handle || '@' || s.domain, '@' || a.handle) as xid from parsav_actors as a left join parsav_servers as s on a.origin = s.id where a.id = $1::bigint ]]; }; actor_fetch_xid = { params = {pstring}, sql = [[ select a.id, a.nym, a.handle, a.origin, a.bio, a.avataruri, a.rank, a.quota, a.key, extract(epoch from a.knownsince)::bigint, coalesce(a.handle || '@' || s.domain, '@' || a.handle) as xid, coalesce(s.domain, (select value from parsav_config where key='domain' limit 1)) as domain ................................................................................ (a.origin is null and $1::text = a.handle or $1::text = ('@' || a.handle)) ]]; }; actor_auth_pw = { params = {pstring,rawstring,pstring,lib.store.inet}, sql = [[ select a.aid from parsav_auth as a left join parsav_actors as u on u.id = a.uid where (a.uid is null or u.handle = $1::text or ( a.uid = 0 and a.name = $1::text )) and (a.kind = 'trust' or (a.kind = $2::text and a.cred = $3::bytea)) and (a.netmask is null or a.netmask >> $4::inet) ................................................................................ ]]; }; actor_enum = { params = {}, sql = [[ select a.id, a.nym, a.handle, a.origin, a.bio, a.avataruri, a.rank, a.quota, a.key, extract(epoch from a.knownsince)::bigint, coalesce(a.handle || '@' || s.domain, '@' || a.handle) as xid from parsav_actors a left join parsav_servers s on s.id = a.origin ]]; }; ................................................................................ ]]; -- cheat }; actor_session_fetch = { params = {uint64, lib.store.inet}, sql = [[ select a.id, a.nym, a.handle, a.origin, a.bio, a.avataruri, a.rank, a.quota, a.key, extract(epoch from a.knownsince)::bigint, coalesce(a.handle || '@' || s.domain, '@' || a.handle) as xid, au.restrict, array['post' ] <@ au.restrict as can_post, array['edit' ] <@ au.restrict as can_edit, array['acct' ] <@ au.restrict as can_acct, ................................................................................ left join parsav_actors a on au.uid = a.id left join parsav_servers s on a.origin = s.id where au.aid = $1::bigint and au.blacklist = false and (au.netmask is null or au.netmask >> $2::inet) ]]; }; post_create = { params = {uint64, rawstring, rawstring, rawstring}, sql = [[ insert into parsav_posts ( author, subject, acl, body, posted, discovered, circles, mentions ) values ( $1::bigint, case when $2::text = '' then null else $2::text end, $3::text, $4::text, now(), now(), array[]::bigint[], array[]::bigint[] ) returning id ]]; -- TODO array handling }; instance_timeline_fetch = { params = {uint64, uint64, uint64, uint64}, sql = [[ select true, p.id, p.author, p.subject, p.acl, p.body, extract(epoch from p.posted )::bigint, extract(epoch from p.discovered)::bigint, p.parent, null::text from parsav_posts as p inner join parsav_actors as a on p.author = a.id where ($1::bigint = 0 or p.posted <= to_timestamp($1::bigint)) and ($2::bigint = 0 or to_timestamp($2::bigint) < p.posted) and (a.origin is null) order by (p.posted, p.discovered) desc limit case when $3::bigint = 0 then null else $3::bigint end offset $4::bigint ]] }; } --($5::bool = false or p.parent is null) and local struct pqr { sz: intptr res: &lib.pq.PGresult } terra pqr:free() if self.sz > 0 then lib.pq.PQclear(self.res) end end terra pqr:null(row: intptr, col: intptr) ................................................................................ ;[pqt[lib.store.inet](false)]([args[i]], [&uint8](&ipbuf)) in &ipbuf[0] end dumpers[#dumpers+1] = `lib.io.fmt([tostring(i)..'. got inet\n']) elseif ty.ptr_basetype == int8 or ty.ptr_basetype == uint8 then counters[i] = `[args[i]].ct casts[i] = `[&int8]([args[i]].ptr) dumpers[#dumpers+1] = `lib.io.fmt([tostring(i)..'. got ptr %llu %.*s\n'], [args[i]].ct, [args[i]].ct, [args[i]].ptr) elseif ty.ptr_basetype == bool then counters[i] = `1 casts[i] = `[&int8]([args[i]].ptr) -- dumpers[#dumpers+1] = `lib.io.fmt([tostring(i)..'. got bool = %hhu\n'], @[args[i]].ptr) elseif ty:isintegral() then counters[i] = ty.bytes casts[i] = `[&int8](&[args[i]]) dumpers[#dumpers+1] = `lib.io.fmt([tostring(i)..'. got int %llu\n'], [args[i]]) fixers[#fixers + 1] = quote [args[i]] = lib.math.netswap(ty, [args[i]]) end end end terra q.exec(src: &lib.store.source, [args]) var params = arrayof([&int8], [casts]) ................................................................................ return pqr {0, nil} else return pqr {ct, res} end end end local terra row_to_post(r: &pqr, row: intptr): lib.mem.ptr(lib.store.post) --lib.io.fmt("body ptr %p len %llu\n", r:string(row,5), r:len(row,5)) --lib.io.fmt("acl ptr %p len %llu\n", r:string(row,4), r:len(row,4)) var subj: rawstring, sblen: intptr if r:null(row,3) then subj = nil sblen = 0 else subj = r:string(row,3) sblen = r:len(row,3)+1 end var p = [ lib.str.encapsulate(lib.store.post, { subject = { `subj, `sblen }; acl = {`r:string(row,4), `r:len(row,4)+1}; body = {`r:string(row,5), `r:len(row,5)+1}; --convoheaduri = { `nil, `0 }; --FIXME }) ] p.ptr.id = r:int(uint64,row,1) p.ptr.author = r:int(uint64,row,2) p.ptr.posted = r:int(uint64,row,6) p.ptr.discovered = r:int(uint64,row,7) if r:null(row,8) then p.ptr.parent = 0 else p.ptr.parent = r:int(uint64,row,8) end p.ptr.localpost = r:bool(row,0) return p end local terra row_to_actor(r: &pqr, row: intptr): lib.mem.ptr(lib.store.actor) var a: lib.mem.ptr(lib.store.actor) var av: rawstring, avlen: intptr var nym: rawstring, nymlen: intptr var bio: rawstring, biolen: intptr if r:null(row,5) then avlen = 0 av = nil else av = r:string(row,5) avlen = r:len(row,5)+1 end if r:null(row,1) then nymlen = 0 nym = nil else nym = r:string(row,1) nymlen = r:len(row,1)+1 end if r:null(row,4) then biolen = 0 bio = nil else bio = r:string(row,4) biolen = r:len(row,4)+1 end a = [ lib.str.encapsulate(lib.store.actor, { nym = {`nym, `nymlen}; bio = {`bio, `biolen}; avatar = {`av,`avlen}; handle = {`r:string(row, 2); `r:len(row,2) + 1}; xid = {`r:string(row, 10); `r:len(row,10) + 1}; }) ] a.ptr.id = r:int(uint64, row, 0); a.ptr.rights = lib.store.rights_default(); a.ptr.rights.rank = r:int(uint16, row, 6); a.ptr.rights.quota = r:int(uint32, row, 7); a.ptr.knownsince = r:int(int64,row, 9); if r:null(row,8) then a.ptr.key.ct = 0 a.ptr.key.ptr = nil ................................................................................ return au, a end ::fail:: return [lib.stat (lib.store.auth) ] { ok = false }, [lib.mem.ptr(lib.store.actor)] { ptr = nil, ct = 0 } end]; post_create = [terra( src: &lib.store.source, post: &lib.store.post ): uint64 var r = queries.post_create.exec(src,post.author,post.subject,post.acl,post.body) if r.sz == 0 then return 0 end defer r:free() var id = r:int(uint64,0,0) return id end]; instance_timeline_fetch = [terra(src: &lib.store.source, rg: lib.store.range) var r = pqr { sz = 0 } if rg.mode == 0 then r = queries.instance_timeline_fetch.exec(src,rg.from_time,rg.to_time,0,0) elseif rg.mode == 1 then r = queries.instance_timeline_fetch.exec(src,rg.from_time,0,rg.to_idx,0) elseif rg.mode == 2 then r = queries.instance_timeline_fetch.exec(src,0,rg.to_time,0,rg.from_idx) elseif rg.mode == 3 then r = queries.instance_timeline_fetch.exec(src,0,0,rg.to_idx,rg.from_idx) end var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz) for i=0,r.sz do ret.ptr[i] = row_to_post(&r, i) end -- MUST FREE ALL return ret end]; } return b |
Modified mem.t from [e41dd1991a] to [15de92d877].
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 .. 43 44 45 46 47 48 49 50 51 52 53 54 55 56 ... 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 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
m.heapa = macro(function(ty, sz)
local p = m.ptr(ty:astype())
return `p {
ptr = [&ty:astype()](m.heapa_raw(sizeof(ty) * sz));
ct = sz;
}
end)
local function mkptr(ty, dyn)
local t = terralib.types.newstruct(string.format('%s<%s>', dyn and 'ptr' or 'ref', ty))
t.entries = {
{'ptr', &ty};
{'ct', intptr};
}
t.ptr_basetype = ty
local recurse = false
if ty:isstruct() then
if ty.methods.free then recurse = true end
end
t.metamethods.__not = macro(function(self)
return `self.ptr
end)
if dyn then
t.methods = {
free = terra(self: &t): bool
[recurse and quote
................................................................................
m.heapf(self.ptr)
self.ct = 0
return true
end
return false
end;
init = terra(self: &t, newct: intptr): bool
var nv = [&ty](m.heapa_raw(sizeof(ty) * newct))
if nv ~= nil then
self.ptr = nv
self.ct = newct
return true
else return false end
end;
................................................................................
{field = 'storage', type = m.ptr(ty)};
{field = 'sz', type = intptr};
{field = 'run', type = intptr};
}
local terra biggest(a: intptr, b: intptr)
if a > b then return a else return b end
end
terra v:assure(n: intptr)
if self.storage.ct < n then
self.storage:resize(biggest(n, self.storage.ct + self.run))
end
end
v.methods = {
init = terra(self: &v, run: intptr): bool
if not self.storage:init(run) then return false end
self.run = run
self.sz = 0
return true
end;
new = terra(self: &v): &ty
self:assure(self.sz + 1)
self.sz = self.sz + 1
return self.storage.ptr + (self.sz - 1)
end;
push = terra(self: &v, val: ty)
self:assure(self.sz + 1)
self.storage.ptr[self.sz] = val
self.sz = self.sz + 1
end;
free = terra(self: &v) self.storage:free() end;
last = terra(self: &v, idx: intptr): &ty
if self.sz > idx then
return self.storage.ptr + (self.sz - (idx+1))
else lib.bail('vector underrun!') end
end;
crush = terra(self: &v)
self.storage:resize(self.sz)
return self.storage
end;
}
v.metamethods.__apply = terra(self: &v, idx: intptr): &ty -- no index??
if self.sz > idx then
return self.storage.ptr + idx
else lib.bail('vector overrun!') end
end
return v
end)
return m
|
> > > > > > > > > > > > > > > > > > > > > > > > > > | | | > < < < < < < | | | | | | < > > > > > > | | | | < > | | | | | | | | | | < > | | | < |
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 59 60 61 62 63 64 65 .. 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 ... 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 |
m.heapa = macro(function(ty, sz)
local p = m.ptr(ty:astype())
return `p {
ptr = [&ty:astype()](m.heapa_raw(sizeof(ty) * sz));
ct = sz;
}
end)
function m.cache(ty,sz)
sz = sz or 32
local struct c {
store: ty[sz]
top: intptr
cur: intptr
}
c.name = string.format('cache<%s,%u>', tostring(ty), sz)
terra c:insert(v: ty)
if [ty.ptr_basetype ~= nil] then
if self.cur < self.top then self.store[self.cur]:free() end
end
self.store[self.cur] = v
self.top = lib.math.biggest(self.top, self.cur + 1)
self.cur = (self.cur + 1) % sz
return v
end
c.metamethods.__apply = terra(self: &c, idx: intptr) return &self.store[idx] end
if ty.ptr_basetype then
terra c:free()
for i=0,self.top do self.store[i]:free() end
end
end
return c
end
local function mkptr(ty, dyn)
local t = terralib.types.newstruct(string.format('%s<%s>', dyn and 'ptr' or 'ref', ty))
t.entries = {
{'ptr', &ty};
{'ct', intptr};
}
t.ptr_basetype = ty
local recurse = false
--if ty:isstruct() then
--if ty.methods.free then recurse = true end
--end
t.metamethods.__not = macro(function(self)
return `self.ptr
end)
if dyn then
t.methods = {
free = terra(self: &t): bool
[recurse and quote
................................................................................
m.heapf(self.ptr)
self.ct = 0
return true
end
return false
end;
init = terra(self: &t, newct: intptr): bool
if newct == 0 then self.ct = 0 self.ptr = nil return false end
var nv = [&ty](m.heapa_raw(sizeof(ty) * newct))
if nv ~= nil then
self.ptr = nv
self.ct = newct
return true
else return false end
end;
................................................................................
{field = 'storage', type = m.ptr(ty)};
{field = 'sz', type = intptr};
{field = 'run', type = intptr};
}
local terra biggest(a: intptr, b: intptr)
if a > b then return a else return b end
end
terra v:init(run: intptr): bool
if not self.storage:init(run) then return false end
self.run = run
self.sz = 0
return true
end;
terra v:assure(n: intptr)
if self.storage.ct < n then
self.storage:resize(biggest(n, self.storage.ct + self.run))
end
end
terra v:new(): &ty
self:assure(self.sz + 1)
self.sz = self.sz + 1
return self.storage.ptr + (self.sz - 1)
end;
terra v:push(val: ty)
self:assure(self.sz + 1)
self.storage.ptr[self.sz] = val
self.sz = self.sz + 1
end;
terra v:free() self.storage:free() end;
terra v:last(idx: intptr): &ty
if self.sz > idx then
return self.storage.ptr + (self.sz - (idx+1))
else lib.bail('vector underrun!') end
end;
terra v:crush()
self.storage:resize(self.sz)
return self.storage
end;
v.metamethods.__apply = terra(self: &v, idx: intptr): &ty -- no index??
if self.sz > idx then
return self.storage.ptr + idx
else lib.bail('vector overrun!') end
end
return v
end)
return m
|
Modified parsav.t from [11ad9b3025] to [579976ae23].
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 ... 285 286 287 288 289 290 291 292 293 294 295 296 297 298 ... 324 325 326 327 328 329 330 331 332 333 334 335 336 337 ... 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
if c == true then r = i else r = e end
in r end
end);
coalesce = macro(function(...)
local args = {...}
local ty = args[1].tree.type
local val = symbol(ty)
local empty if ty.type == 'integer'
then empty = `0
else empty = `nil
end
local exp = quote val = [empty] end
for i=#args, 1, -1 do
local v = args[i]
exp = quote
if [v] ~= [empty]
then val = v
else [exp]
end
end
end
local q = quote
var [val]
[exp]
................................................................................
lib.b64 = lib.loadlib('mbedtls','mbedtls/base64.h')
lib.net = lib.loadlib('mongoose','mongoose.h')
lib.pq = lib.loadlib('libpq','libpq-fe.h')
lib.load {
'mem', 'math', 'str', 'file', 'crypt';
'http', 'session', 'tpl', 'store';
}
local be = {}
for _, b in pairs(config.backends) do
be[#be+1] = terralib.loadfile('backend/' .. b .. '.t')()
end
lib.store.backends = global(`array([be]))
................................................................................
lib.load {
'srv';
'render:nav';
'render:login';
'render:profile';
'render:userpage';
'render:compose';
'route';
}
do
local p = string.format('parsav: %s\nbuilt on %s\n', config.build.str, config.build.when)
terra version() lib.io.send(1, p, [#p]) end
end
................................................................................
if bflag('dump-config','C') then
print(util.dump(config))
os.exit(0)
end
local holler = print
local out = config.exe and 'parsav' or ('parsav.' .. config.outform)
local linkargs = {'-O4'}
if bflag('quiet','q') then holler = function() end end
if bflag('asan','s') then linkargs[#linkargs+1] = '-fsanitize=address' end
if bflag('lsan','S') then linkargs[#linkargs+1] = '-fsanitize=leak' end
if config.posix then
linkargs[#linkargs+1] = '-pthread'
|
| > | | < > | > > > > > > > | | | > > > > > | |
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 ... 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 ... 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 ... 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
if c == true then r = i else r = e end
in r end
end);
coalesce = macro(function(...)
local args = {...}
local ty = args[1].tree.type
local val = symbol(ty)
local empty
if ty.ptr_basetype then empty = `[ty]{ptr=nil,ct=0}
elseif ty.type == 'integer' then empty = `0
else empty = `nil end
local exp = quote val = [empty] end
for i=#args, 1, -1 do
local v = args[i]
if ty.ptr_basetype then
exp = quote
if [v].ptr ~= nil
then val = v
else [exp]
end
end
else
exp = quote
if [v] ~= [empty]
then val = v
else [exp]
end
end
end
end
local q = quote
var [val]
[exp]
................................................................................
lib.b64 = lib.loadlib('mbedtls','mbedtls/base64.h')
lib.net = lib.loadlib('mongoose','mongoose.h')
lib.pq = lib.loadlib('libpq','libpq-fe.h')
lib.load {
'mem', 'math', 'str', 'file', 'crypt';
'http', 'session', 'tpl', 'store';
'smackdown'; -- md-alike parser
}
local be = {}
for _, b in pairs(config.backends) do
be[#be+1] = terralib.loadfile('backend/' .. b .. '.t')()
end
lib.store.backends = global(`array([be]))
................................................................................
lib.load {
'srv';
'render:nav';
'render:login';
'render:profile';
'render:userpage';
'render:compose';
'render:tweet';
'render:timeline';
'route';
}
do
local p = string.format('parsav: %s\nbuilt on %s\n', config.build.str, config.build.when)
terra version() lib.io.send(1, p, [#p]) end
end
................................................................................
if bflag('dump-config','C') then
print(util.dump(config))
os.exit(0)
end
local holler = print
local out = config.exe and 'parsav' or ('parsav.' .. config.outform)
local linkargs = {}
if bflag('quiet','q') then holler = function() end end
if bflag('asan','s') then linkargs[#linkargs+1] = '-fsanitize=address' end
if bflag('lsan','S') then linkargs[#linkargs+1] = '-fsanitize=leak' end
if config.posix then
linkargs[#linkargs+1] = '-pthread'
|
Modified render/compose.t from [7a7e8f43ac] to [0685338a7e].
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
acl = lib.trn(target == nil, 'all', 'mentioned'); -- TODO default acl setting?
handle = co.who.handle;
}
end
var cotxt = form:tostr() defer cotxt:free()
var doc = data.view.docskel {
instance = co.srv.cfg.instance.ptr;
title = 'compose';
body = cotxt.ptr;
class = 'compose';
navlinks = co.navbar.ptr;
}
var hdrs = array(
lib.http.header { 'Content-Type', 'text/html; charset=UTF-8' }
)
doc:send(co.con,200,[lib.mem.ptr(lib.http.header)] {ct = 1, ptr = &hdrs[0]})
end
return render_compose
|
| | | | | |
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
acl = lib.trn(target == nil, 'all', 'mentioned'); -- TODO default acl setting?
handle = co.who.handle;
}
end
var cotxt = form:tostr() defer cotxt:free()
var doc = data.view.docskel {
instance = co.srv.cfg.instance;
title = lib.str.plit 'compose';
body = cotxt;
class = lib.str.plit 'compose';
navlinks = co.navbar;
}
var hdrs = array(
lib.http.header { 'Content-Type', 'text/html; charset=UTF-8' }
)
doc:send(co.con,200,[lib.mem.ptr(lib.http.header)] {ct = 1, ptr = &hdrs[0]})
end
return render_compose
|
Modified render/login.t from [0d69ec17a3] to [671b92715b].
1
2
3
4
5
6
7
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
51
52
53
54
55
56
57
58
59
60
61
62
|
-- vim: ft=terra local terra login_form(co: &lib.srv.convo, user: &lib.store.actor, creds: &lib.store.credset, msg: &int8) var doc = data.view.docskel { instance = co.srv.cfg.instance.ptr; title = 'instance logon'; class = 'login'; navlinks = co.navbar.ptr; } if user == nil then var form = data.view.login_username { loginmsg = msg; } if form.loginmsg == nil then form.loginmsg = 'identify yourself for access to this instance.' end var formtxt = form:tostr() doc.body = formtxt.ptr elseif creds:sz() == 0 then co:complain(403,'access denied','your host is not eligible to authenticate as this user') return elseif creds:sz() == 1 then if creds.trust() then -- TODO log in immediately return ................................................................................ end var ch = data.view.login_challenge { handle = user.handle; name = lib.coalesce(user.nym, user.handle); } if creds.pw() then ch.challenge = 'enter the password associated with your account' ch.label = 'password' ch.method = 'pw' elseif creds.otp() then ch.challenge = 'enter a valid one-time password for your account' ch.label = 'OTP code' ch.method = 'otp' elseif creds.challenge() then ch.challenge = 'sign the challenge token: <code>...</code>' ch.label = 'digest' ch.method = 'challenge' else co:complain(500,'login failure','unknown login method') return end doc.body = ch:tostr().ptr else -- pick a method end var hdrs = array( lib.http.header { 'Content-Type', 'text/html; charset=UTF-8' } ) doc:send(co.con,200,[lib.mem.ptr(lib.http.header)] {ct = 1, ptr = &hdrs[0]}) lib.mem.heapf(doc.body) end return login_form |
>
>
|
|
|
|
|
|
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
1
2
3
4
5
6
7
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
51
52
53
54
55
56
57
58
59
60
61
62
63
|
-- vim: ft=terra local pstr = lib.mem.ptr(int8) local P = lib.str.plit local terra login_form(co: &lib.srv.convo, user: &lib.store.actor, creds: &lib.store.credset, msg: pstr) var doc = data.view.docskel { instance = co.srv.cfg.instance; title = lib.str.plit 'instance logon'; class = lib.str.plit 'login'; navlinks = co.navbar; } if user == nil then var form = data.view.login_username { loginmsg = msg; } if form.loginmsg.ptr == nil then form.loginmsg = lib.str.plit 'identify yourself for access to this instance.' end doc.body = form:tostr() elseif creds:sz() == 0 then co:complain(403,'access denied','your host is not eligible to authenticate as this user') return elseif creds:sz() == 1 then if creds.trust() then -- TODO log in immediately return ................................................................................ end var ch = data.view.login_challenge { handle = user.handle; name = lib.coalesce(user.nym, user.handle); } if creds.pw() then ch.challenge = P'enter the password associated with your account' ch.label = P'password' ch.method = P'pw' elseif creds.otp() then ch.challenge = P'enter a valid one-time password for your account' ch.label = P'OTP code' ch.method = P'otp' elseif creds.challenge() then ch.challenge = P'sign the challenge token: <code>...</code>' ch.label = P'digest' ch.method = P'challenge' else co:complain(500,'login failure','unknown login method') return end doc.body = ch:tostr() else -- pick a method end var hdrs = array( lib.http.header { 'Content-Type', 'text/html; charset=UTF-8' } ) doc:send(co.con,200,[lib.mem.ptr(lib.http.header)] {ct = 1, ptr = &hdrs[0]}) doc.body:free() end return login_form |
Modified render/nav.t from [2d4aa38bec] to [450b73f673].
3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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 href="/">timeline</a>')
end
if co.who ~= nil then
t:lpush('<a href="/compose">compose</a> <a href="/'):push(co.who.xid,0)
t:lpush('">profile</a> <a href="/conf">configure</a> <a href="/logout">log out</a>')
else
t:lpush('<a href="/login">log in</a>')
end
return t:finalize()
end
return render_nav
|
| | |
3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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 href="/">timeline</a>')
end
if co.who ~= nil then
t:lpush('<a href="/compose">compose</a> <a href="/'):push(co.who.xid,0)
t:lpush('">profile</a> <a href="/conf">configure</a> <a href="/help">help</a> <a href="/logout">log out</a>')
else
t:lpush('<a href="/help">help</a> <a href="/login">log in</a>')
end
return t:finalize()
end
return render_nav
|
Modified render/profile.t from [ecfc7ba460] to [30c7a0b6c6].
1 2 3 4 5 6 7 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 51 |
-- vim: ft=terra local terra render_profile(co: &lib.srv.convo, actor: &lib.store.actor) var aux: lib.str.acc var auxp: rawstring if co.aid ~= 0 and co.who.id == actor.id then auxp = '<a href="/conf/profile">alter</a>' elseif co.aid ~= 0 then aux:compose('<a href="/', actor.xid, '/follow">follow</a><a href="/', actor.xid, '/chat">chat</a>') if co.who.rights.powers:affect_users() then aux:push('<a href="/',11):push(actor.xid,0):push('/ctl">control</a>',17) end auxp = aux.buf else aux:compose('<a href="/', actor.xid, '/follow">remote follow</a>') end var avistr: lib.str.acc if actor.origin == 0 then avistr:compose('/avi/',actor.handle) end 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 = lib.math.decstr_friendly(stats.posts, &strfbuf[ [strfbuf.type.N - 1] ]) var sn_follows = lib.math.decstr_friendly(stats.follows, sn_posts - 1) var sn_followers = lib.math.decstr_friendly(stats.followers, sn_follows - 1) var sn_mutuals = lib.math.decstr_friendly(stats.mutuals, sn_followers - 1) var profile = data.view.profile { nym = lib.coalesce(actor.nym, actor.handle); bio = lib.coalesce(actor.bio, "<em>tall, dark, and mysterious</em>"); xid = actor.xid; avatar = lib.trn(actor.origin == 0, avistr.buf, lib.coalesce(actor.avatar, '/s/default-avatar.webp')); nposts = sn_posts, nfollows = sn_follows; nfollowers = sn_followers, nmutuals = sn_mutuals; tweetday = timestr; timephrase = lib.trn(actor.origin == 0, 'joined', 'known since'); auxbtn = auxp; } var ret = profile:tostr() if actor.origin == 0 then avistr:free() end if not (co.aid ~= 0 and co.who.id == actor.id) then aux:free() end return ret end return render_profile |
> > > > > | | | | | | | | | | | | | | | |
1 2 3 4 5 6 7 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 51 52 53 54 55 56 |
-- vim: ft=terra local pstr = lib.mem.ptr(int8) local terra cs(s: rawstring) return pstr { ptr = s, ct = lib.str.sz(s) } end local terra render_profile(co: &lib.srv.convo, actor: &lib.store.actor) var aux: lib.str.acc var auxp: pstr if co.aid ~= 0 and co.who.id == actor.id then auxp = lib.str.plit '<a href="/conf/profile">alter</a>' elseif co.aid ~= 0 then aux:compose('<a href="/', actor.xid, '/follow">follow</a><a href="/', actor.xid, '/chat">chat</a>') if co.who.rights.powers:affect_users() then aux:push('<a href="/',11):push(actor.xid,0):push('/ctl">control</a>',17) end auxp = aux:finalize() else aux:compose('<a href="/', actor.xid, '/follow">remote follow</a>') end var avistr: lib.str.acc if actor.origin == 0 then avistr:compose('/avi/',actor.handle) end 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 profile = data.view.profile { nym = cs(lib.coalesce(actor.nym, actor.handle)); bio = cs(lib.coalesce(actor.bio, "<em>tall, dark, and mysterious</em>")); xid = cs(actor.xid); avatar = lib.trn(actor.origin == 0, pstr{ptr=avistr.buf,ct=avistr.sz}, cs(lib.coalesce(actor.avatar, '/s/default-avatar.webp'))); nposts = sn_posts, nfollows = sn_follows; nfollowers = sn_followers, nmutuals = sn_mutuals; tweetday = cs(timestr); timephrase = lib.trn(actor.origin == 0, lib.str.plit'joined', lib.str.plit'known since'); auxbtn = auxp; } var ret = profile:tostr() if actor.origin == 0 then avistr:free() end if not (co.aid ~= 0 and co.who.id == actor.id) then auxp:free() end return ret end return render_profile |
Added render/timeline.t version [e2a4558814].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 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 |
-- vim: ft=terra local modes = lib.enum {'follow','mutual','srvlocal','fediglobal','circle'} local terra render_timeline(co: &lib.srv.convo, modestr: lib.mem.ref(int8)) var mode = modes.srvlocal var circle: uint64 = 0 -- if modestr:cmpl('local') then mode = modes.srvlocal -- elseif modestr:cmpl('mutual') then mode = modes.mutual -- elseif modestr:cmpl('global') then mode = modes.fediglobal -- elseif modestr:cmpl('circle') then mode = modes.circle -- end var stoptime = lib.osclock.time(nil) var posts = [lib.mem.vec(lib.mem.ptr(lib.store.post))] { sz = 0, run = 0 } if mode == modes.follow then elseif mode == modes.srvlocal then posts = co.srv:instance_timeline_fetch(lib.store.range { mode = 1; -- T->I 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) for i = 0, posts.sz do lib.render.tweet(co, posts(i).ptr, &acc) posts(i):free() end posts:free() var doc = data.view.docskel { instance = co.srv.cfg.instance; title = lib.str.plit'timeline'; body = acc:finalize(); class = lib.str.plit'timeline'; navlinks = co.navbar; } var hdrs = array( lib.http.header { 'Content-Type', 'text/html; charset=UTF-8' } ) doc:send(co.con,200,[lib.mem.ptr(lib.http.header)] {ct = 1, ptr = &hdrs[0]}) doc.body:free() end return render_timeline |
Added render/tweet.t version [71eb9101d9].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 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 51 |
-- vim: ft=terra local pstr = lib.mem.ptr(int8) local terra cs(s: rawstring) return pstr { ptr = s, ct = lib.str.sz(s) } end local terra render_tweet(co: &lib.srv.convo, p: &lib.store.post, acc: &lib.str.acc) var author: &lib.store.actor for j = 0, co.actorcache.top do lib.io.fmt('scanning cache for author %llu (%llu/%llu)\n', p.author, j, co.actorcache.top) if p.author == co.actorcache(j).ptr.id then author = co.actorcache(j).ptr lib.io.fmt('cache hit on idx %llu, skipping db lookup\n', j) goto foundauth end end lib.io.fmt('cache miss, checking db for id %llu\n', p.author) author = co.actorcache:insert(co.srv:actor_fetch_uid(p.author)).ptr lib.io.fmt('got author %s\n', author.handle) ::foundauth:: var avistr: lib.str.acc if author.origin == 0 then avistr:compose('/avi/',author.handle) end var timestr: int8[26] lib.osclock.ctime_r(&p.posted, ×tr[0]) lib.io.fmt('got body %s\n', author.handle) var bhtml = lib.smackdown.html([lib.mem.ptr(int8)] {ptr=p.body,ct=0}) 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 tpl = data.view.tweet { text = bhtml; subject = cs(lib.coalesce(p.subject,'')); nym = cs(lib.coalesce(author.nym, author.handle)); xid = cs(author.xid); when = cs(×tr[0]); avatar = cs(lib.trn(author.origin == 0, avistr.buf, lib.coalesce(author.avatar, '/s/default-avatar.webp'))); acctlink = cs(author.xid); permalink = permalink:finalize(); } defer tpl.permalink:free() if acc ~= nil then tpl:append(acc) return [lib.mem.ptr(int8)]{ptr=nil,ct=0} end var txt = tpl:tostr() return txt end return render_tweet |
Modified render/userpage.t from [cdf1e65d22] to [7b79f9904c].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
-- vim: ft=terra local terra render_userpage(co: &lib.srv.convo, actor: &lib.store.actor) var ti: lib.str.acc defer ti:free() if co.aid ~= 0 and co.who.id == actor.id then ti:compose('my profile') else ti:compose('profile :: ', actor.handle) end var pftxt = lib.render.profile(co,actor) defer pftxt:free() var doc = data.view.docskel { instance = co.srv.cfg.instance.ptr; title = ti.buf; body = pftxt.ptr; class = 'profile'; navlinks = co.navbar.ptr; } var hdrs = array( lib.http.header { 'Content-Type', 'text/html; charset=UTF-8' } ) doc:send(co.con,200,[lib.mem.ptr(lib.http.header)] {ct = 1, ptr = &hdrs[0]}) end return render_userpage |
| | | | | | > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
-- vim: ft=terra
local terra
render_userpage(co: &lib.srv.convo, actor: &lib.store.actor)
var ti: lib.str.acc
if co.aid ~= 0 and co.who.id == actor.id then
ti:compose('my profile')
else
ti:compose('profile :: ', actor.handle)
end
var pftxt = lib.render.profile(co,actor) defer pftxt:free()
var doc = data.view.docskel {
instance = co.srv.cfg.instance;
title = ti:finalize();
body = pftxt;
class = lib.str.plit 'profile';
navlinks = co.navbar;
}
var hdrs = array(
lib.http.header { 'Content-Type', 'text/html; charset=UTF-8' }
)
doc:send(co.con,200,[lib.mem.ptr(lib.http.header)] {ct = 1, ptr = &hdrs[0]})
doc.title:free()
end
return render_userpage
|
Modified route.t from [d7d680b0a3] to [4d69f275c0].
1 2 3 4 5 6 7 8 9 10 .. 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 .. 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 ... 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 ... 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 ... 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
-- vim: ft=terra
local r = lib.srv.route
local method = lib.http.method
local http = {}
terra http.actor_profile_xid(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t)
var handle = [lib.mem.ptr(int8)] { ptr = &uri.ptr[2], ct = 0 }
for i=2,uri.ct do
if uri.ptr[i] == @'/' or uri.ptr[i] == 0 then handle.ct = i - 2 break end
end
................................................................................
lib.render.userpage(co, actor.ptr)
end
terra http.login_form(co: &lib.srv.convo, meth: method.t)
if meth == method.get then
-- request a username
lib.render.login(co, nil, nil, nil)
elseif meth == method.post then
var usn, usnl = co:postv('user')
lib.dbg('got name ',{usn,usnl})
lib.io.fmt('name len %llu\n',usnl)
var am, aml = co:postv('authmethod')
var chrs, chrsl = co:postv('response')
var cs, authok = co.srv:actor_auth_how(co.peer, usn)
var act = co.srv:actor_fetch_xid([lib.mem.ptr(int8)] {
ptr = usn, ct = usnl
})
if authok == false then
lib.render.login(co, nil, nil, 'access denied')
return
end
var fakeact = false
var fakeactor: lib.store.actor
if act.ptr == nil then
-- the user is known to us but has not yet claimed an
-- account on the server. create a template for the
................................................................................
}
act.ct = 1
act.ptr = &fakeactor
act.ptr.rights = lib.store.rights_default()
end
if am == nil then
-- pick an auth method
lib.render.login(co, act.ptr, &cs, nil)
else var aid: uint64 = 0
lib.dbg('authentication attempt beginning')
-- attempt login with provided method
if lib.str.ncmp('pw', am, lib.math.biggest(2,aml)) == 0 and chrs ~= nil then
aid = co.srv:actor_auth_pw(co.peer,
[lib.mem.ptr(int8)]{ptr=usn,ct=usnl},
[lib.mem.ptr(int8)]{ptr=chrs,ct=chrsl})
................................................................................
elseif lib.str.ncmp('otp', am, lib.math.biggest(2,aml)) == 0 and chrs ~= nil then
lib.dbg('using otp auth')
-- ··· --
else
lib.dbg('invalid auth method')
end
lib.io.fmt('login got aid = %llu\n', aid)
-- error out
if aid == 0 then
lib.render.login(co, nil, nil, 'authentication failure')
else
var sesskey: int8[lib.session.maxlen + #lib.session.cookiename + #"=; Path=/" + 1]
do var p = &sesskey[0]
p = lib.str.ncpy(p, [lib.session.cookiename .. '='], [#lib.session.cookiename + 1])
p = p + lib.session.cookie_gen(co.srv.cfg.secret, aid, lib.osclock.time(nil), p)
lib.dbg('sending cookie',&sesskey[0])
p = lib.str.ncpy(p, '; Path=/', 9)
................................................................................
terra http.post_compose(co: &lib.srv.convo, meth: method.t)
if meth == method.get then
lib.render.compose(co, nil)
elseif meth == method.post then
if co.who.rights.powers.post() == false then
co:complain(401,'insufficient privileges','you lack the <strong>post</strong> power and cannot perform this action') return
end
end
end
do local branches = quote end
local filename, flen = symbol(&int8), symbol(intptr)
local page = symbol(lib.http.page)
local send = label()
local storage = data.stmap
for i,e in ipairs(config.embeds) do local id,mime = e[1],e[2]
................................................................................
co:reroute('/s/default-avatar.webp')
end
-- entry points
terra r.dispatch_http(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t)
lib.dbg('handling URI of form ', {uri.ptr,uri.ct})
co.navbar = lib.render.nav(co)
-- some routes are non-hierarchical, and can be resolved with a simple strcmp
-- we run through those first before giving up and parsing the URI
if uri.ptr[0] ~= @'/' then
co:complain(404, 'what the hell', 'how did you do that')
return
elseif uri.ct == 1 then -- root
lib.io.fmt('root directory, aid is %llu\n', co.aid)
if (co.srv.cfg.pol_sec == lib.srv.secmode.private or
co.srv.cfg.pol_sec == lib.srv.secmode.lockdown) and co.aid == 0 then
http.login_form(co, meth)
else
-- FIXME display home screen
goto notfound
end
return
elseif uri.ptr[1] == @'@' then
http.actor_profile_xid(co, uri, meth)
return
elseif uri.ptr[1] == @'s' and uri.ptr[2] == @'/' and uri.ct > 3 then
................................................................................
else co:reroute_cookie('/','auth=; Path=/')
end
return
else -- hierarchical routes
var path = lib.http.hier(uri) defer path:free()
if path.ptr[0]:cmp(lib.str.lit('user')) then
http.actor_profile_uid(co, path, meth)
else goto notfound end
return
end
::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end
::notfound:: co:complain(404, 'not found', 'no such resource available') do return end
end
|
> > > | < < | | < | > > > > > > > > > > > > > > > > > > > > > > > > < > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 .. 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 .. 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 ... 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 ... 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 ... 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
-- vim: ft=terra local r = lib.srv.route local method = lib.http.method local pstring = lib.mem.ptr(int8) local rstring = lib.mem.ref(int8) local hpath = lib.mem.ptr(rstring) local http = {} terra http.actor_profile_xid(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t) var handle = [lib.mem.ptr(int8)] { ptr = &uri.ptr[2], ct = 0 } for i=2,uri.ct do if uri.ptr[i] == @'/' or uri.ptr[i] == 0 then handle.ct = i - 2 break end end ................................................................................ lib.render.userpage(co, actor.ptr) end terra http.login_form(co: &lib.srv.convo, meth: method.t) if meth == method.get then -- request a username lib.render.login(co, nil, nil, lib.str.plit(nil)) elseif meth == method.post then var usn, usnl = co:postv('user') var am, aml = co:postv('authmethod') var chrs, chrsl = co:postv('response') var cs, authok = co.srv:actor_auth_how(co.peer, usn) var act = co.srv:actor_fetch_xid([lib.mem.ptr(int8)] { ptr = usn, ct = usnl }) if authok == false then lib.render.login(co, nil, nil, lib.str.plit'access denied') return end var fakeact = false var fakeactor: lib.store.actor if act.ptr == nil then -- the user is known to us but has not yet claimed an -- account on the server. create a template for the ................................................................................ } act.ct = 1 act.ptr = &fakeactor act.ptr.rights = lib.store.rights_default() end if am == nil then -- pick an auth method lib.render.login(co, act.ptr, &cs, lib.str.plit(nil)) else var aid: uint64 = 0 lib.dbg('authentication attempt beginning') -- attempt login with provided method if lib.str.ncmp('pw', am, lib.math.biggest(2,aml)) == 0 and chrs ~= nil then aid = co.srv:actor_auth_pw(co.peer, [lib.mem.ptr(int8)]{ptr=usn,ct=usnl}, [lib.mem.ptr(int8)]{ptr=chrs,ct=chrsl}) ................................................................................ elseif lib.str.ncmp('otp', am, lib.math.biggest(2,aml)) == 0 and chrs ~= nil then lib.dbg('using otp auth') -- ··· -- else lib.dbg('invalid auth method') end -- error out if aid == 0 then lib.render.login(co, nil, nil, lib.str.plit 'authentication failure') else var sesskey: int8[lib.session.maxlen + #lib.session.cookiename + #"=; Path=/" + 1] do var p = &sesskey[0] p = lib.str.ncpy(p, [lib.session.cookiename .. '='], [#lib.session.cookiename + 1]) p = p + lib.session.cookie_gen(co.srv.cfg.secret, aid, lib.osclock.time(nil), p) lib.dbg('sending cookie',&sesskey[0]) p = lib.str.ncpy(p, '; Path=/', 9) ................................................................................ terra http.post_compose(co: &lib.srv.convo, meth: method.t) if meth == method.get then lib.render.compose(co, nil) elseif meth == method.post then if co.who.rights.powers.post() == false then co:complain(401,'insufficient privileges','you lack the <strong>post</strong> power and cannot perform this action') return end var text, textlen = co:postv("post") var acl, acllen = co:postv("acl") var subj, subjlen = co:postv("subject") if text == nil or acl == nil then co:complain(405, 'invalid post', 'every post must have at least body text and an ACL') return end if subj == nil then subj = '' end var p = lib.store.post { author = co.who.id, acl = acl; body = text, subject = subj; } var newid = co.srv:post_create(&p) var idbuf: int8[lib.math.shorthand.maxlen] var idlen = lib.math.shorthand.gen(newid, idbuf) var redirto: lib.str.acc redirto:compose('/post/',{idbuf,idlen}) defer redirto:free() co:reroute(redirto.buf) end end terra http.timeline(co: &lib.srv.convo, mode: hpath) lib.render.timeline(co,lib.trn(mode.ptr == nil, rstring{ptr=nil}, mode.ptr[1])) return end do local branches = quote end local filename, flen = symbol(&int8), symbol(intptr) local page = symbol(lib.http.page) local send = label() local storage = data.stmap for i,e in ipairs(config.embeds) do local id,mime = e[1],e[2] ................................................................................ co:reroute('/s/default-avatar.webp') end -- entry points terra r.dispatch_http(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t) lib.dbg('handling URI of form ', {uri.ptr,uri.ct}) co.navbar = lib.render.nav(co) lib.dbg('got nav ', {co.navbar.ptr,co.navbar.ct}, "||", co.navbar.ptr) -- some routes are non-hierarchical, and can be resolved with a simple strcmp -- we run through those first before giving up and parsing the URI if uri.ptr[0] ~= @'/' then co:complain(404, 'what the hell', 'how did you do that') return elseif uri.ct == 1 then -- root if (co.srv.cfg.pol_sec == lib.srv.secmode.private or co.srv.cfg.pol_sec == lib.srv.secmode.lockdown) and co.aid == 0 then http.login_form(co, meth) else -- FIXME display home screen http.timeline(co, hpath {ptr=nil}) goto notfound end return elseif uri.ptr[1] == @'@' then http.actor_profile_xid(co, uri, meth) return elseif uri.ptr[1] == @'s' and uri.ptr[2] == @'/' and uri.ct > 3 then ................................................................................ else co:reroute_cookie('/','auth=; Path=/') end return else -- hierarchical routes var path = lib.http.hier(uri) defer path:free() if path.ptr[0]:cmp(lib.str.lit('user')) then http.actor_profile_uid(co, path, meth) elseif path.ptr[0]:cmp(lib.str.lit('tl')) then http.timeline(co, path) else goto notfound end return end ::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end ::notfound:: co:complain(404, 'not found', 'no such resource available') do return end end |
Modified schema.sql from [a3359b8b76] to [6bf306c986].
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 .. 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 ... 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 ... 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 |
-- note that valid ids should always > 0, as 0 is reserved for null -- on the client side, vastly simplifying code drop table if exists parsav_servers cascade; create table parsav_servers ( id bigint primary key default (1+random()*(2^63-1))::bigint, domain text not null, key bytea, parsav boolean -- whether to use parsav protocol extensions ); drop table if exists parsav_actors cascade; create table parsav_actors ( id bigint primary key default (1+random()*(2^63-1))::bigint, nym text, handle text not null, -- nym [@handle@origin] origin bigint references parsav_servers(id) on delete cascade, -- null origin = local actor bio text, avataruri text, -- null if local rank smallint not null default 0, quota integer not null default 1000, key bytea, -- private if localactor; public if remote title text unique (handle,origin) ); drop table if exists parsav_rights cascade; create table parsav_rights ( key text, ................................................................................ author bigint references parsav_actors(id) on delete cascade, subject text, acl text not null default 'all', -- just store the script raw 🤷 body text, posted timestamp not null, discovered timestamp not null, scope smallint not null, convo bigint, parent bigint, circles bigint[], mentions bigint[] ); drop table if exists parsav_conversations cascade; create table parsav_conversations ( id bigint primary key default (1+random()*(2^63-1))::bigint, uri text not null, discovered timestamp not null, head bigint references parsav_posts(id) ); drop table if exists parsav_rels cascade; create table parsav_rels ( relator bigint references parsav_actors(id) on delete cascade, -- e.g. follower relatee bigint references parsav_actors(id) on delete cascade, -- e.g. followed ................................................................................ ); drop table if exists parsav_circles cascade; create table parsav_circles ( id bigint primary key default (1+random()*(2^63-1))::bigint, owner bigint not null references parsav_actors(id), name text not null, members bigint[] not null default array[], unique (owner,name) ); drop table if exists parsav_rooms cascade; create table parsav_rooms ( id bigint primary key default (1+random()*(2^63-1))::bigint, ................................................................................ drop table if exists parsav_room_members cascade; create table parsav_room_members ( room bigint references parsav_rooms(id), member bigint references parsav_actors(id), rank smallint not null default 0, admin boolean not null default false, -- non-admins with rank can only moderate + invite title text -- admin-granted title like reddit flair ); drop table if exists parsav_invites cascade; create table parsav_invites ( id bigint primary key default (1+random()*(2^63-1))::bigint, -- when a user is created from an invite, the invite is deleted and the invite -- ID becomes the user ID. privileges granted on the invite ID during the invite -- process are thus inherited by the user handle text, -- admin can lock invite to specific handle rank smallint not null default 0, quota integer not null default 1000 }; drop table if exists parsav_interventions cascade; create table parsav_interventions ( id bigint primary key default (1+random()*(2^63-1))::bigint, issuer bigint references parsav_actors(id) not null, scope bigint, -- can be null or room for local actions nature smallint not null, -- silence, suspend, disemvowel, etc victim bigint not null, -- could potentially target group as well expire timestamp -- auto-expires if set ); end; |
> > | < < | | | > > > > > < < < < < < | | > > | |
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 .. 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 ... 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 ... 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 |
-- note that valid ids should always > 0, as 0 is reserved for null -- on the client side, vastly simplifying code drop table if exists parsav_servers cascade; create table parsav_servers ( id bigint primary key default (1+random()*(2^63-1))::bigint, domain text not null, key bytea, knownsince timestamp, parsav boolean -- whether to use parsav protocol extensions ); drop table if exists parsav_actors cascade; create table parsav_actors ( id bigint primary key default (1+random()*(2^63-1))::bigint, nym text, handle text not null, -- nym [@handle@origin] origin bigint references parsav_servers(id) on delete cascade, -- null origin = local actor knownsince timestamp, bio text, avataruri text, -- null if local rank smallint not null default 0, quota integer not null default 1000, key bytea, -- private if localactor; public if remote title text, unique (handle,origin) ); drop table if exists parsav_rights cascade; create table parsav_rights ( key text, ................................................................................ author bigint references parsav_actors(id) on delete cascade, subject text, acl text not null default 'all', -- just store the script raw 🤷 body text, posted timestamp not null, discovered timestamp not null, parent bigint not null default 0, circles bigint[], -- TODO at edit or creation, iterate through each circle mentions bigint[], -- a user has, check if it can see her post, and if so add convoheaduri text -- only used for tracking foreign conversations and tying them to post heads; -- local conversations are tracked directly and mapped to URIs based on the -- head's ID. null if native tweet or not the first tweet in convo ); drop table if exists parsav_conversations cascade; drop table if exists parsav_rels cascade; create table parsav_rels ( relator bigint references parsav_actors(id) on delete cascade, -- e.g. follower relatee bigint references parsav_actors(id) on delete cascade, -- e.g. followed ................................................................................ ); drop table if exists parsav_circles cascade; create table parsav_circles ( id bigint primary key default (1+random()*(2^63-1))::bigint, owner bigint not null references parsav_actors(id), name text not null, members bigint[] not null default array[]::bigint[], unique (owner,name) ); drop table if exists parsav_rooms cascade; create table parsav_rooms ( id bigint primary key default (1+random()*(2^63-1))::bigint, ................................................................................ drop table if exists parsav_room_members cascade; create table parsav_room_members ( room bigint references parsav_rooms(id), member bigint references parsav_actors(id), rank smallint not null default 0, admin boolean not null default false, -- non-admins with rank can only moderate + invite title text, -- admin-granted title like reddit flair vouchedby bigint references parsav_actors(id) ); drop table if exists parsav_invites cascade; create table parsav_invites ( id bigint primary key default (1+random()*(2^63-1))::bigint, -- when a user is created from an invite, the invite is deleted and the invite -- ID becomes the user ID. privileges granted on the invite ID during the invite -- process are thus inherited by the user issuer bigint references parsav_actors(id), handle text, -- admin can lock invite to specific handle rank smallint not null default 0, quota integer not null default 1000 ); drop table if exists parsav_interventions cascade; create table parsav_interventions ( id bigint primary key default (1+random()*(2^63-1))::bigint, issuer bigint references parsav_actors(id) not null, scope bigint, -- can be null or room for local actions nature smallint not null, -- silence, suspend, disemvowel, etc victim bigint not null, -- could potentially target group as well expire timestamp -- auto-expires if set ); end; |
Added smackdown.t version [896438e021].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 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 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 86 87 88 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 130 131 132 133 134 135 136 137 138 |
-- vim: ft=terra -- smackdown is parsav's terrible, terrible custom markdown-alike parser local m = {} local pstr = lib.mem.ptr(int8) local segt = { none = 0, para = 1, head = 2, listing = 3 } local autolink_protos = { 'https', 'http', 'ftp', 'gopher', 'gemini', 'ircs', 'irc'; 'mailto', 'about', 'sshfs', 'afp', 'smb', 'data', 'file'; 'dav', 'git', 'svn', 'cvs', 'dns', 'finger', 'pop', 'imap'; 'pops', 'imaps', 'torrent', 'magnet', 'news', 'snews', 'nfs'; 'nntp', 'sms', 'tel', 'telnet', 'vnc', 'webcal', 'ws', 'wss'; 'xmpp'; } local struct state { segt: uint bqlvl: uint curpos: rawstring blockstart: rawstring } terra state:segend(ofs: uint) -- takes a string offset and returns true if it indexes th -- end of the current block var s = self.curpos + ofs if s[0] ~= @'\n' then return false end if self.segt == segt.head then return true end -- headers can only be 1 line -- if s[1] == '#' end local terra isws(c: int8) return c == @' ' or c == @'\n' or c == @'\t' or c == @'\r' end local terra scanline(l: rawstring, max: intptr, n: rawstring, nc: intptr) if l == nil then return nil end for i=0,max do for j=0,nc do if l[i+j] == @'\n' then return nil end if l[i+j] ~= n[j] then goto nexti end end do return l+i end ::nexti::end end 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 isws(@sl) then return sl-nc end return nil end terra m.html(md: pstr) if md.ct == 0 then md.ct = lib.str.sz(md.ptr) end 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 here = md.ptr + i var rem = md.ct - i if @here == @'[' then var sep = scanline(here,rem, '](', 2) var term = scanline(sep+2,rem - ((sep+2)-here), ')', 1) if sep ~= nil and term ~= nil then styled:lpush('<a href="') :push(sep+2, term-(sep+2)) :lpush('" rel="nofollow">') :push(here+1,(sep-here) - 1) :lpush('</a>') i = (term - md.ptr) + 1 goto skip else goto fallback end end if wordstart and rem >= 7 and lib.str.ncmp('***',here,3)==0 then var term = scanline_wordend(here+4,rem-4,'***',3) if term ~= nil then styled:lpush('<strong><em>') :push(here+3, (term-here) - 3) :lpush('</strong></em>') i = (term - md.ptr) + 3 goto skip end end if wordstart and rem >= 5 and lib.str.ncmp('**',here,2)==0 then var term = scanline_wordend(here+3,rem-3,'**',2) if term ~= nil then styled:lpush('<strong>') :push(here+2, (term-here) - 2) :lpush('</strong>') i = (term - md.ptr) + 2 goto skip end end if wordstart and rem >= 3 and @here == @'*' then var term = scanline_wordend(here+2,rem-2,'*',1) if term ~= nil then styled:lpush('<em>') :push(here+1, (term-here) - 1) :lpush('</em>') i = (term - md.ptr) + 1 goto skip end end ::fallback::styled:push(here,1) -- :/ i = i + 1 ::skip::end end -- 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 |
Modified srv.t from [afa0417e30] to [d14bb4b6ce].
16 17 18 19 20 21 22 23 24 25 26 27 28 29 .. 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 .. 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 .. 74 75 76 77 78 79 80 81 82 83 84 85 86 87 ... 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 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 ... 223 224 225 226 227 228 229 230 231 232 233 234 235 236 ... 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
cfg: cfgcache
}
terra cfgcache:free() -- :/
self.secret:free()
self.instance:free()
end
srv.metamethods.__methodmissing = macro(function(meth, self, ...)
local primary, ptr, stat, simple, oid = 0,1,2,3,4
local tk, rt = primary
local expr = {...}
for _,f in pairs(lib.store.backend.entries) do
local fn = f.field or f[1]
................................................................................
elseif rt.type == 'integer' then tk = oid
elseif rt.stat_basetype then tk = stat
elseif rt.ptr_basetype then tk = ptr end
break
end
end
if tk == primary then
return `self.sources.ptr[0]:[meth]([expr])
else local ok, empty
local r = symbol(rt)
if tk == ptr then
ok = `r.ptr ~= nil
empty = `[rt]{ptr=nil,ct=0}
elseif tk == stat then
ok = `r.ok == true
empty = `[rt]{ok=false,error=1}
elseif tk == simple then
................................................................................
elseif tk == oid then
ok = `r ~= 0
empty = `0
end
return quote
var [r] = empty
for i=0,self.sources.ct do var src = self.sources.ptr + i
if src.handle ~= nil then
r = src:[meth]([expr])
if [ok] then break
else r = empty end
end
end
in r end
end
................................................................................
msg: &lib.net.mg_http_message
aid: uint64 -- 0 if logged out
who: &lib.store.actor -- who we're logged in as, if aid ~= 0
peer: lib.store.inet
reqtype: lib.http.mime.t -- negotiated content type
-- cache
navbar: lib.mem.ptr(int8)
-- private
varbuf: lib.mem.ptr(int8)
vbofs: &int8
}
-- this is unfortunately necessary to work around a terra bug
-- it can't seem to handle forward-declarations of structs in C
................................................................................
end
terra convo:reroute(dest: rawstring) self:reroute_cookie(dest,nil) end
terra convo:complain(code: uint16, title: rawstring, msg: rawstring)
var hdrs = array(lib.http.header { key = 'Content-Type', value = 'text/html; charset=UTF-8' })
var ti: lib.str.acc ti:compose('error :: ', title) defer ti:free()
var bo: lib.str.acc bo:compose('<div class="message"><img class="icon" src="/s/warn.webp"><h1>error</h1><p>',msg,'</p></div>') defer bo:free()
var body = data.view.docskel {
instance = self.srv.cfg.instance.ptr;
title = ti.buf;
body = bo.buf;
class = 'error';
navlinks = lib.coalesce(self.navbar.ptr, '');
}
if body.body == nil then
body.body = "i'm sorry, dave. i can't let you do that"
end
body:send(self.con, code, [lib.mem.ptr(lib.http.header)] {
ptr = &hdrs[0], ct = [hdrs.type.N]
})
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
return r, o
else return nil, 0 end
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
return r, o
else return nil, 0 end
end
local urimatch = macro(function(uri, ptn)
return `lib.net.mg_globmatch(ptn, [#ptn], uri.ptr, uri.ct+1)
end)
................................................................................
var msg = [&lib.net.mg_http_message](p)
var co = convo {
con = con, srv = server, msg = msg;
aid = 0, who = nil, peer = peer;
reqtype = lib.http.mime.none;
} co.varbuf.ptr = nil
co.navbar.ptr = nil
-- first, check for an accept header. if it's there, we need to
-- iterate over the values and pick the highest-priority one
do var acc = lib.http.findheader(msg, 'Accept')
-- TODO handle q-value
if acc.ptr ~= nil then
var [mimevar] = [lib.mem.ref(int8)] { ptr = acc.ptr }
................................................................................
else
co:complain(400,'unknown method','you have submitted an invalid http request')
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
end
end
end;
}
local terra cfg(s: &srv, befile: rawstring)
lib.report('configuring backends from ', befile)
|
> > > > > > > > > > > > > > > > > > | > > > > > > < | > | | | | | | | | | > > > | > > | | > > | > > > |
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 .. 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 .. 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 .. 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 ... 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 ... 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ... 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
cfg: cfgcache } terra cfgcache:free() -- :/ self.secret:free() self.instance:free() end terra srv:instance_timeline_fetch(r: lib.store.range): lib.mem.vec(lib.mem.ptr(lib.store.post)) var all: lib.mem.vec(lib.mem.ptr(lib.store.post)) all:init(64) for i=0,self.sources.ct do var src = self.sources.ptr + i if src.handle ~= nil and src.backend.instance_timeline_fetch ~= nil then var lst = src:instance_timeline_fetch(r) all:assure(all.sz + lst.ct) for j=0, lst.ct do all:push(lst.ptr[j]) end lst:free() end end return all end srv.metamethods.__methodmissing = macro(function(meth, self, ...) local primary, ptr, stat, simple, oid = 0,1,2,3,4 local tk, rt = primary local expr = {...} for _,f in pairs(lib.store.backend.entries) do local fn = f.field or f[1] ................................................................................ elseif rt.type == 'integer' then tk = oid elseif rt.stat_basetype then tk = stat elseif rt.ptr_basetype then tk = ptr end break end end local r = symbol(rt) if tk == primary then return quote var [r] for i=0,self.sources.ct do var src = self.sources.ptr + i if src.handle ~= nil and src.backend.[meth] ~= nil then r = src:[meth]([expr]) goto success end end lib.bail(['no active backends provide critical capability ' .. meth .. '!']) ::success::; in r end else local ok, empty if tk == ptr then ok = `r.ptr ~= nil empty = `[rt]{ptr=nil,ct=0} elseif tk == stat then ok = `r.ok == true empty = `[rt]{ok=false,error=1} elseif tk == simple then ................................................................................ elseif tk == oid then ok = `r ~= 0 empty = `0 end return quote var [r] = empty for i=0,self.sources.ct do var src = self.sources.ptr + i if src.handle ~= nil and src.backend.[meth] ~= nil then r = src:[meth]([expr]) if [ok] then break else r = empty end end end in r end end ................................................................................ msg: &lib.net.mg_http_message aid: uint64 -- 0 if logged out who: &lib.store.actor -- who we're logged in as, if aid ~= 0 peer: lib.store.inet reqtype: lib.http.mime.t -- negotiated content type -- cache navbar: lib.mem.ptr(int8) actorcache: lib.mem.cache(lib.mem.ptr(lib.store.actor),32) -- naive cache to avoid unnecessary queries -- private varbuf: lib.mem.ptr(int8) vbofs: &int8 } -- this is unfortunately necessary to work around a terra bug -- it can't seem to handle forward-declarations of structs in C ................................................................................ end terra convo:reroute(dest: rawstring) self:reroute_cookie(dest,nil) end terra convo:complain(code: uint16, title: rawstring, msg: rawstring) var hdrs = array(lib.http.header { key = 'Content-Type', value = 'text/html; charset=UTF-8' }) var ti: lib.str.acc ti:compose('error :: ', title) var bo: lib.str.acc bo:compose('<div class="message"><img class="icon" src="/s/warn.webp"><h1>',title,'</h1><p>',msg,'</p></div>') var body = data.view.docskel { instance = self.srv.cfg.instance; title = ti:finalize(); body = bo:finalize(); class = lib.str.plit 'error'; navlinks = lib.coalesce(self.navbar, [lib.mem.ptr(int8)]{ptr='',ct=0}); } if body.body.ptr == nil then body.body = lib.str.plit"i'm sorry, dave. i can't let you do that" end body:send(self.con, code, [lib.mem.ptr(lib.http.header)] { ptr = &hdrs[0], ct = [hdrs.type.N] }) body.title:free() body.body:free() 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 var norm = lib.str.normalize([lib.mem.ptr(int8)]{ptr = r, ct = o}) return norm.ptr, norm.ct else return nil, 0 end 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 norm = lib.str.normalize([lib.mem.ptr(int8)]{ptr = r, ct = o}) return norm.ptr, norm.ct else return nil, 0 end end local urimatch = macro(function(uri, ptn) return `lib.net.mg_globmatch(ptn, [#ptn], uri.ptr, uri.ct+1) end) ................................................................................ var msg = [&lib.net.mg_http_message](p) var co = convo { con = con, srv = server, msg = msg; aid = 0, who = nil, peer = peer; reqtype = lib.http.mime.none; } co.varbuf.ptr = nil co.navbar.ptr = nil co.actorcache.top = 0 co.actorcache.cur = 0 -- first, check for an accept header. if it's there, we need to -- iterate over the values and pick the highest-priority one do var acc = lib.http.findheader(msg, 'Accept') -- TODO handle q-value if acc.ptr ~= nil then var [mimevar] = [lib.mem.ref(int8)] { ptr = acc.ptr } ................................................................................ else co:complain(400,'unknown method','you have submitted an invalid http request') 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() end end end; } local terra cfg(s: &srv, befile: rawstring) lib.report('configuring backends from ', befile) |
Modified static/style.scss from [7905a3444d] to [1dafd96ed6].
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...
410
411
412
413
414
415
416
417
418
419
420
421
|
$color: hsl(323,100%,65%);
%sans { font-family: "Alegreya Sans", "Open Sans", sans-serif; }
%serif { font-family: Alegreya, GaramondNo8, "Garamond Premier Pro", "Adobe Garamond", Garamond, Junicode, serif; }
%teletype { font-family: "Inconsolata LGC", Inconsolata, monospace; font-size: 12pt !important; }
@function tone($pct) { @return adjust-color($color, $lightness: $pct) }
body {
@extend %sans;
background-color: adjust-color($color, $lightness: -55%);
color: adjust-color($color, $lightness: 25%);
font-size: 14pt;
margin: 0;
padding: 0;
}
a[href] {
color: adjust-color($color, $lightness: 10%);
&:hover {
color: white;
text-shadow: 0 0 15px adjust-color($color, $lightness: 20%);
}
}
a[href^="//"],
a[href^="http://"],
a[href^="https://"] { // external link
&:hover::after {
color: black;
................................................................................
padding: 0.1in;
&:hover { font-weight: bold; }
}
}
code {
@extend %teletype;
background: adjust-color($color, $lightness: -50%);
border: 1px solid adjust-color($color, $lightness: -20%);
padding: 2px 6px;
text-shadow: 2px 2px black;
}
|
|
|
|
>
|
>
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
|
$color: hsl(323,100%,65%);
%sans { font-family: "Alegreya Sans", "Open Sans", sans-serif; }
%serif { font-family: Alegreya, GaramondNo8, "Garamond Premier Pro", "Adobe Garamond", Garamond, Junicode, serif; }
%teletype { font-family: "Inconsolata LGC", Inconsolata, monospace; font-size: 12pt !important; }
@function tone($pct, $alpha: 0) { @return adjust-color($color, $lightness: $pct, $alpha: $alpha) }
body {
@extend %sans;
background-color: tone(-55%);
color: tone(25%);
font-size: 14pt;
margin: 0;
padding: 0;
}
a[href] {
color: tone(10%);
text-decoration-color: adjust-color($color, $lightness: 10%, $alpha: -0.5);
&:hover {
color: white;
text-shadow: 0 0 15px tone(20%);
text-decoration-color: adjust-color($color, $lightness: 10%, $alpha: -0.1);
}
}
a[href^="//"],
a[href^="http://"],
a[href^="https://"] { // external link
&:hover::after {
color: black;
................................................................................
padding: 0.1in;
&:hover { font-weight: bold; }
}
}
code {
@extend %teletype;
background: tone(-50%);
border: 1px solid tone(-20%);
padding: 2px 6px;
text-shadow: 2px 2px black;
}
div.post {
@extend %box;
display: grid;
grid-template-columns: 1in 1fr max-content;
grid-template-rows: 1fr max-content;
margin-bottom: 0.1in;
>.avatar {
grid-column: 1/2; grid-row: 1/2;
width: 1in;
}
>a[href].username {
display: block;
grid-column: 1/3;
grid-row: 2/3;
text-align: left;
text-decoration: none;
padding: 0.1in;
padding-left: 0.15in;
>.nym { font-weight: bold; }
color: tone(0%,-0.4);
> span.nym { color: tone(10%) }
> span.handle { color: tone(-5%) }
background: linear-gradient(to right, tone(-55%), transparent);
}
>.content {
grid-column: 2/4; grid-row: 1/2;
padding: 0.2in;
@extend %serif;
font-size: 110%;
}
> a[href].permalink {
display: block;
grid-column: 3/4; grid-row: 2/3;
font-size: 80%;
text-align: right;
padding: 0.1in;
padding-right: 0.15in;
font-style: italic;
background: linear-gradient(to left, tone(-55%,-0.5), transparent);
}
}
a[href].rawlink {
@extend %teletype;
}
|
Modified store.t from [5ad659a834] to [4782518865].
1 2 3 4 5 6 7 8 9 10 .. 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 .. 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 .. 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 ... 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
-- vim: ft=terra
local m = {
timepoint = uint64;
scope = lib.enum {
'public', 'private', 'local';
'personal', 'direct', 'circle';
};
notiftype = lib.enum {
'mention', 'like', 'rt', 'react'
};
................................................................................
struct m.actor {
id: uint64
nym: str
handle: str
origin: uint64
bio: str
avatar: str
knownsince: int64
rights: m.rights
key: lib.mem.ptr(uint8)
-- ephemera
xid: str
source: &m.source
}
................................................................................
posts: intptr
follows: intptr
followers: intptr
mutuals: intptr
}
struct m.range {
time: bool
union {
from_time: m.timepoint
from_idx: uint64
}
union {
to_time: m.timepoint
to_idx: uint64
................................................................................
}
struct m.post {
id: uint64
author: uint64
subject: str
body: str
posted: m.timepoint
discovered: m.timepoint
scope: m.scope.t
mentions: lib.mem.ptr(uint64)
circles: lib.mem.ptr(uint64) --only meaningful if scope is set to circle
convo: uint64
parent: uint64
source: &m.source
}
local cnf = terralib.memoize(function(ty,rty)
rty = rty or ty
return struct {
enum: {&opaque, uint64, rawstring} -> intptr
................................................................................
-- for determining session validity & caps
-- aid: uint64
-- origin: inet
actor_conf_str: cnf(rawstring, lib.mem.ptr(int8))
actor_conf_int: cnf(intptr, lib.stat(intptr))
post_save: {&m.source, &m.post} -> bool
post_create: {&m.source, &m.post} -> bool
actor_post_fetch_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(m.post)
convo_fetch_xid: {&m.source,rawstring} -> lib.mem.ptr(m.post)
convo_fetch_uid: {&m.source,uint64} -> lib.mem.ptr(m.post)
actor_timeline_fetch_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(m.post)
instance_timeline_fetch: {&m.source, m.range} -> lib.mem.ptr(m.post)
}
struct m.source {
backend: &m.backend
id: lib.mem.ptr(int8)
handle: &opaque
string: lib.mem.ptr(int8)
|
| | | > < | > | | | | |
1 2 3 4 5 6 7 8 9 10 .. 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 .. 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 .. 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 ... 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
-- vim: ft=terra
local m = {
timepoint = int64;
scope = lib.enum {
'public', 'private', 'local';
'personal', 'direct', 'circle';
};
notiftype = lib.enum {
'mention', 'like', 'rt', 'react'
};
................................................................................
struct m.actor {
id: uint64
nym: str
handle: str
origin: uint64
bio: str
avatar: str
knownsince: m.timepoint
rights: m.rights
key: lib.mem.ptr(uint8)
-- ephemera
xid: str
source: &m.source
}
................................................................................
posts: intptr
follows: intptr
followers: intptr
mutuals: intptr
}
struct m.range {
mode: uint8 -- 0 == I->I, 1 == T->I, 2 == I->T, 3 == T->T
union {
from_time: m.timepoint
from_idx: uint64
}
union {
to_time: m.timepoint
to_idx: uint64
................................................................................
}
struct m.post {
id: uint64
author: uint64
subject: str
body: str
acl: str
posted: m.timepoint
discovered: m.timepoint
mentions: lib.mem.ptr(uint64)
circles: lib.mem.ptr(uint64) --only meaningful if scope is set to circle
convo: uint64
parent: uint64
-- ephemera
localpost: bool
source: &m.source
}
local cnf = terralib.memoize(function(ty,rty)
rty = rty or ty
return struct {
enum: {&opaque, uint64, rawstring} -> intptr
................................................................................
-- for determining session validity & caps
-- aid: uint64
-- origin: inet
actor_conf_str: cnf(rawstring, lib.mem.ptr(int8))
actor_conf_int: cnf(intptr, lib.stat(intptr))
post_save: {&m.source, &m.post} -> {}
post_create: {&m.source, &m.post} -> uint64
actor_post_fetch_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(m.post)
convo_fetch_xid: {&m.source,rawstring} -> lib.mem.ptr(m.post)
convo_fetch_uid: {&m.source,uint64} -> lib.mem.ptr(m.post)
actor_timeline_fetch_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
instance_timeline_fetch: {&m.source, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
}
struct m.source {
backend: &m.backend
id: lib.mem.ptr(int8)
handle: &opaque
string: lib.mem.ptr(int8)
|
Modified str.t from [c8d105a016] to [c5ea2451a4].
1 2 3 4 5 6 7 8 9 10 .. 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 .. 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 ... 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 ... 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
-- vim: ft=terra
-- string.t: string classes
local util = dofile('common.lua')
local m = {
sz = terralib.externfunction('strlen', rawstring -> intptr);
cmp = terralib.externfunction('strcmp', {rawstring, rawstring} -> int);
ncmp = terralib.externfunction('strncmp', {rawstring, rawstring, intptr} -> int);
cpy = terralib.externfunction('stpcpy',{rawstring, rawstring} -> rawstring);
ncpy = terralib.externfunction('stpncpy',{rawstring, rawstring, intptr} -> rawstring);
................................................................................
terralib.types.funcpointer({&rawstring,rawstring},{int},true));
bfmt = terralib.externfunction('sprintf',
terralib.types.funcpointer({rawstring,rawstring},{int},true));
span = terralib.externfunction('strspn',{rawstring, rawstring} -> rawstring);
}
do local strptr = (lib.mem.ptr(int8))
local byteptr = (lib.mem.ptr(uint8))
strptr.metamethods.__cast = function(from,to,e)
if from == &int8 then
return `strptr {ptr = e, ct = m.sz(e)}
elseif to == &int8 then
return e.ptr
end
end
terra strptr:cmp(other: strptr)
var sz = lib.math.biggest(self.ct, other.ct)
for i = 0, sz do
if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
if self.ptr[i] ~= other.ptr[i] then return false end
end
return true
end
terra byteptr:cmp(other: byteptr)
var sz = lib.math.biggest(self.ct, other.ct)
for i = 0, sz do
if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
if self.ptr[i] ~= other.ptr[i] then return false end
end
return true
end
end
struct m.acc {
buf: rawstring
sz: intptr
run: intptr
space: intptr
}
................................................................................
--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:crush()
var pt: lib.mem.ptr(int8)
pt.ptr = self.buf
pt.ct = self.sz
self.buf = nil
self.sz = 0
return pt
................................................................................
lib.mem.cpy(self.buf + self.sz, str, len)
self.sz = self.sz + len
self.buf[self.sz] = 0
return self
end;
m.lit = macro(function(str)
return `[lib.mem.ref(int8)] {ptr = [str:asvalue()], ct = [#(str:asvalue())]}
end)
m.acc.methods.lpush = macro(function(self,str)
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.merge = terra(self: &m.acc, str: lib.mem.ptr(int8))
................................................................................
local str,sz = v[1],v[2]
if type(sz) == 'number' then
memreq_const = memreq_const + sz
elseif type(sz:asvalue()) == 'number' then
memreq_const = memreq_const + sz:asvalue()
else memreq_exp = `[sz] + [memreq_exp] end
cpy = quote [kp] ; [ptr] = [&int8](lib.mem.cpy([ptr], str, sz)) end
if ty.ptr_basetype then
cpy = quote [cpy]; [box].obj.[k].ct = sz end
end
isnull = `[str] == nil
else
memreq_exp = `(m.sz(v) + 1) + [memreq_exp] -- make room for NUL
isnull = `v == nil
|
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > > > > > > > > > > > > > | > > |
1 2 3 4 5 6 7 8 9 10 11 12 .. 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 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 86 87 88 89 90 91 92 93 94 95 96 ... 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 ... 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 ... 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
-- vim: ft=terra
-- string.t: string classes
local util = dofile('common.lua')
local pstr = lib.mem.ptr(int8)
local pref = lib.mem.ref(int8)
local m = {
sz = terralib.externfunction('strlen', rawstring -> intptr);
cmp = terralib.externfunction('strcmp', {rawstring, rawstring} -> int);
ncmp = terralib.externfunction('strncmp', {rawstring, rawstring, intptr} -> int);
cpy = terralib.externfunction('stpcpy',{rawstring, rawstring} -> rawstring);
ncpy = terralib.externfunction('stpncpy',{rawstring, rawstring, intptr} -> rawstring);
................................................................................
terralib.types.funcpointer({&rawstring,rawstring},{int},true));
bfmt = terralib.externfunction('sprintf',
terralib.types.funcpointer({rawstring,rawstring},{int},true));
span = terralib.externfunction('strspn',{rawstring, rawstring} -> rawstring);
}
do local strptr = (lib.mem.ptr(int8))
local strref = (lib.mem.ref(int8))
local byteptr = (lib.mem.ptr(uint8))
strptr.metamethods.__cast = function(from,to,e)
if from == &int8 then
return `strptr {ptr = e, ct = m.sz(e)}
elseif to == &int8 then
return e.ptr
end
end
terra strptr:cmp(other: strptr)
if self.ptr == nil and other.ptr == nil then return true end
if self.ptr == nil or other.ptr == nil then return false end
var sz = lib.math.biggest(self.ct, other.ct)
for i = 0, sz do
if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
if self.ptr[i] ~= other.ptr[i] then return false end
end
return true
end
terra strref:cmp(other: strref)
if self.ptr == nil and other.ptr == nil then return true end
if self.ptr == nil or other.ptr == nil then return false end
var sz = lib.math.biggest(self.ct, other.ct)
for i = 0, sz do
if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
if self.ptr[i] ~= other.ptr[i] then return false end
end
return true
end
strptr.methods.cmpl = macro(function(self,other)
return `self:cmp(strptr { ptr = [other:asvalue()], ct = [#(other:asvalue())] })
end)
strref.methods.cmpl = macro(function(self,other)
return `self:cmp(strref { ptr = [other:asvalue()], ct = [#(other:asvalue())] })
end)
terra byteptr:cmp(other: byteptr)
var sz = lib.math.biggest(self.ct, other.ct)
for i = 0, sz do
if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
if self.ptr[i] ~= other.ptr[i] then return false end
end
return true
end
end
terra m.normalize(s: pstr)
var c: rawstring = s.ptr
var n: rawstring = s.ptr
while n < s.ptr + s.ct do
while @n == 0 or @n == @'\r' do
n = n + 1
if n > s.ptr + s.ct then
c = c + 1 goto done
end
end
@c = @n
c = c + 1
n = n + 1
end ::done::
@c = 0
return pstr { ptr = s.ptr, ct = c - s.ptr }
end
struct m.acc {
buf: rawstring
sz: intptr
run: intptr
space: intptr
}
................................................................................
--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:crush()
var pt: lib.mem.ptr(int8)
pt.ptr = self.buf
pt.ct = self.sz
self.buf = nil
self.sz = 0
return pt
................................................................................
lib.mem.cpy(self.buf + self.sz, str, len)
self.sz = self.sz + len
self.buf[self.sz] = 0
return self
end;
m.lit = macro(function(str)
if str:asvalue() ~= nil then
return `[lib.mem.ref(int8)] {ptr = [str:asvalue()], ct = [#(str:asvalue())]}
else
return `[lib.mem.ref(int8)] {ptr = nil, ct = 0}
end
end)
m.plit = macro(function(str)
if str:asvalue() ~= nil then
return `[lib.mem.ptr(int8)] {ptr = [str:asvalue()], ct = [#(str:asvalue())]}
else
return `[lib.mem.ptr(int8)] {ptr = nil, ct = 0}
end
end)
m.acc.methods.lpush = macro(function(self,str)
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.merge = terra(self: &m.acc, str: lib.mem.ptr(int8))
................................................................................
local str,sz = v[1],v[2]
if type(sz) == 'number' then
memreq_const = memreq_const + sz
elseif type(sz:asvalue()) == 'number' then
memreq_const = memreq_const + sz:asvalue()
else memreq_exp = `[sz] + [memreq_exp] end
cpy = quote [kp] ;
--lib.io.fmt('encapsulating string %p → %p [%s] sz %llu\n', str, [ptr], str, sz)
[ptr] = [&int8](lib.mem.cpy([ptr], str, sz))
--lib.io.fmt(' :: encapsulated string %p [%s]\n', box.obj.[k],box.obj.[k])
end
if ty.ptr_basetype then
cpy = quote [cpy]; [box].obj.[k].ct = sz end
end
isnull = `[str] == nil
else
memreq_exp = `(m.sz(v) + 1) + [memreq_exp] -- make room for NUL
isnull = `v == nil
|
Modified tpl.t from [3cd51c8b03] to [3e776df34f].
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
..
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
local rec = terralib.types.newstruct(string.format('template<%s>',tplspec.id or ''))
local symself = symbol(&rec)
do local kfac = {}
for afterseg,key in pairs(fields) do
if not kfac[key] then
rec.entries[#rec.entries + 1] = {
field = key;
type = rawstring;
}
end
kfac[key] = (kfac[key] or 0) + 1
end
for key, fac in pairs(kfac) do
tallyup[#tallyup + 1] = quote
[runningtally] = [runningtally] + lib.str.sz([symself].[key])*fac
end
end
end
local copiers = {}
local senders = {}
local appenders = {}
................................................................................
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] then
copiers[#copiers+1] = quote
[cpypos] = lib.mem.cpy([cpypos],
[&opaque](symself.[fields[idx]]),
lib.str.sz(symself.[fields[idx]]))
end
senders[#senders+1] = quote
lib.net.mg_send([destcon],
symself.[fields[idx]],
lib.str.sz(symself.[fields[idx]]))
end
end
end
local tid = tplspec.id or '<anonymous>'
rec.methods.tostr = terra([symself])
lib.dbg(['compiling template ' .. tid])
|
|
|
>
>
>
|
<
<
|
<
|
>
>
|
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
..
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
local rec = terralib.types.newstruct(string.format('template<%s>',tplspec.id or ''))
local symself = symbol(&rec)
do local kfac = {}
for afterseg,key in pairs(fields) do
if not kfac[key] then
rec.entries[#rec.entries + 1] = {
field = key;
type = lib.mem.ptr(int8);
}
end
kfac[key] = (kfac[key] or 0) + 1
end
for key, fac in pairs(kfac) do
tallyup[#tallyup + 1] = quote
[runningtally] = [runningtally] + ([symself].[key].ct)*fac
end
end
end
local copiers = {}
local senders = {}
local appenders = {}
................................................................................
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] then
--local fsz = `lib.str.sz(symself.[fields[idx]])
local fval = `symself.[fields[idx]].ptr
local fsz = `symself.[fields[idx]].ct
copiers[#copiers+1] = quote
[cpypos] = lib.mem.cpy([cpypos], [&opaque]([fval]), [fsz])
end
senders[#senders+1] = quote
lib.net.mg_send([destcon], [fval], [fsz])
end
appenders[#appenders+1] = quote
[accumulator]:push([fval], [fsz])
end
end
end
local tid = tplspec.id or '<anonymous>'
rec.methods.tostr = terra([symself])
lib.dbg(['compiling template ' .. tid])
|
Modified view/tweet.tpl from [4ad2e9eaa9] to [e1b2184d52].
1 2 3 4 5 6 7 8 9 10 11 12 |
<div class="post"> <div class="detail"> <a class="username" href="@link"> <span class="nym">@nym</span> <span class="handle">[@xid]</span> </div> <div class="when">@when</div> </div> <div class="content"> <img class="avatar" src="@avatar"> <div class="text">@text</div> </div> </div> |
| | | | < < < > > |
1 2 3 4 5 6 7 8 9 10 11 |
<div class="post"> <img class="avatar" src="@avatar"> <a class="username" href="/@acctlink"> <span class="nym">@nym</span> [<span class="handle">@xid</span>] </a> <div class="content"> <div class="subject">@subject</div> <div class="text">@text</div> </div> <a class="permalink" href="@permalink">@when</a> </div> |