Differences From
Artifact [afa0417e30]:
16 16 cfg: cfgcache
17 17 }
18 18
19 19 terra cfgcache:free() -- :/
20 20 self.secret:free()
21 21 self.instance:free()
22 22 end
23 +
24 +terra srv:instance_timeline_fetch(r: lib.store.range): lib.mem.vec(lib.mem.ptr(lib.store.post))
25 + var all: lib.mem.vec(lib.mem.ptr(lib.store.post)) all:init(64)
26 + for i=0,self.sources.ct do var src = self.sources.ptr + i
27 + if src.handle ~= nil and src.backend.instance_timeline_fetch ~= nil then
28 + var lst = src:instance_timeline_fetch(r)
29 + all:assure(all.sz + lst.ct)
30 + for j=0, lst.ct do all:push(lst.ptr[j]) end
31 + lst:free()
32 + end
33 + end
34 + return all
35 +end
23 36
24 37 srv.metamethods.__methodmissing = macro(function(meth, self, ...)
25 38 local primary, ptr, stat, simple, oid = 0,1,2,3,4
26 39 local tk, rt = primary
27 40 local expr = {...}
28 41 for _,f in pairs(lib.store.backend.entries) do
29 42 local fn = f.field or f[1]
................................................................................
34 47 elseif rt.type == 'integer' then tk = oid
35 48 elseif rt.stat_basetype then tk = stat
36 49 elseif rt.ptr_basetype then tk = ptr end
37 50 break
38 51 end
39 52 end
40 53
54 + local r = symbol(rt)
41 55 if tk == primary then
42 - return `self.sources.ptr[0]:[meth]([expr])
56 + return quote
57 + var [r]
58 + for i=0,self.sources.ct do var src = self.sources.ptr + i
59 + if src.handle ~= nil and src.backend.[meth] ~= nil then
60 + r = src:[meth]([expr])
61 + goto success
62 + end
63 + end
64 + lib.bail(['no active backends provide critical capability ' .. meth .. '!'])
65 + ::success::;
66 + in r end
43 67 else local ok, empty
44 - local r = symbol(rt)
45 68 if tk == ptr then
46 69 ok = `r.ptr ~= nil
47 70 empty = `[rt]{ptr=nil,ct=0}
48 71 elseif tk == stat then
49 72 ok = `r.ok == true
50 73 empty = `[rt]{ok=false,error=1}
51 74 elseif tk == simple then
................................................................................
54 77 elseif tk == oid then
55 78 ok = `r ~= 0
56 79 empty = `0
57 80 end
58 81 return quote
59 82 var [r] = empty
60 83 for i=0,self.sources.ct do var src = self.sources.ptr + i
61 - if src.handle ~= nil then
84 + if src.handle ~= nil and src.backend.[meth] ~= nil then
62 85 r = src:[meth]([expr])
63 86 if [ok] then break
64 87 else r = empty end
65 88 end
66 89 end
67 90 in r end
68 91 end
................................................................................
74 97 msg: &lib.net.mg_http_message
75 98 aid: uint64 -- 0 if logged out
76 99 who: &lib.store.actor -- who we're logged in as, if aid ~= 0
77 100 peer: lib.store.inet
78 101 reqtype: lib.http.mime.t -- negotiated content type
79 102 -- cache
80 103 navbar: lib.mem.ptr(int8)
104 + actorcache: lib.mem.cache(lib.mem.ptr(lib.store.actor),32) -- naive cache to avoid unnecessary queries
81 105 -- private
82 106 varbuf: lib.mem.ptr(int8)
83 107 vbofs: &int8
84 108 }
85 109
86 110 -- this is unfortunately necessary to work around a terra bug
87 111 -- it can't seem to handle forward-declarations of structs in C
................................................................................
118 142 end
119 143
120 144 terra convo:reroute(dest: rawstring) self:reroute_cookie(dest,nil) end
121 145
122 146 terra convo:complain(code: uint16, title: rawstring, msg: rawstring)
123 147 var hdrs = array(lib.http.header { key = 'Content-Type', value = 'text/html; charset=UTF-8' })
124 148
125 - var ti: lib.str.acc ti:compose('error :: ', title) defer ti:free()
126 - 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()
149 + var ti: lib.str.acc ti:compose('error :: ', title)
150 + var bo: lib.str.acc bo:compose('<div class="message"><img class="icon" src="/s/warn.webp"><h1>',title,'</h1><p>',msg,'</p></div>')
127 151 var body = data.view.docskel {
128 - instance = self.srv.cfg.instance.ptr;
129 - title = ti.buf;
130 - body = bo.buf;
131 - class = 'error';
132 - navlinks = lib.coalesce(self.navbar.ptr, '');
152 + instance = self.srv.cfg.instance;
153 + title = ti:finalize();
154 + body = bo:finalize();
155 + class = lib.str.plit 'error';
156 + navlinks = lib.coalesce(self.navbar, [lib.mem.ptr(int8)]{ptr='',ct=0});
133 157 }
134 158
135 - if body.body == nil then
136 - body.body = "i'm sorry, dave. i can't let you do that"
159 + if body.body.ptr == nil then
160 + body.body = lib.str.plit"i'm sorry, dave. i can't let you do that"
137 161 end
138 162
139 163 body:send(self.con, code, [lib.mem.ptr(lib.http.header)] {
140 164 ptr = &hdrs[0], ct = [hdrs.type.N]
141 165 })
166 +
167 + body.title:free()
168 + body.body:free()
142 169 end
143 170
144 171 -- CALL ONLY ONCE PER VAR
145 172 terra convo:postv(name: rawstring)
146 173 if self.varbuf.ptr == nil then
147 174 self.varbuf = lib.mem.heapa(int8, self.msg.body.len + self.msg.query.len)
148 175 self.vbofs = self.varbuf.ptr
149 176 end
150 177 var o = lib.net.mg_http_get_var(&self.msg.body, name, self.vbofs, self.varbuf.ct - (self.vbofs - self.varbuf.ptr))
151 178 if o > 0 then
152 179 var r = self.vbofs
153 - self.vbofs = self.vbofs + o
154 - return r, o
180 + self.vbofs = self.vbofs + o + 1
181 + @(self.vbofs - 1) = 0
182 + var norm = lib.str.normalize([lib.mem.ptr(int8)]{ptr = r, ct = o})
183 + return norm.ptr, norm.ct
155 184 else return nil, 0 end
156 185 end
157 186
158 187 terra convo:getv(name: rawstring)
159 188 if self.varbuf.ptr == nil then
160 189 self.varbuf = lib.mem.heapa(int8, self.msg.query.len + self.msg.body.len)
161 190 self.vbofs = self.varbuf.ptr
162 191 end
163 192 var o = lib.net.mg_http_get_var(&self.msg.query, name, self.vbofs, self.varbuf.ct - (self.vbofs - self.varbuf.ptr))
164 193 if o > 0 then
165 194 var r = self.vbofs
166 - self.vbofs = self.vbofs + o
167 - return r, o
195 + self.vbofs = self.vbofs + o + 1
196 + @(self.vbofs - 1) = 0
197 + var norm = lib.str.normalize([lib.mem.ptr(int8)]{ptr = r, ct = o})
198 + return norm.ptr, norm.ct
168 199 else return nil, 0 end
169 200 end
170 201
171 202 local urimatch = macro(function(uri, ptn)
172 203 return `lib.net.mg_globmatch(ptn, [#ptn], uri.ptr, uri.ct+1)
173 204 end)
174 205
................................................................................
223 254 var msg = [&lib.net.mg_http_message](p)
224 255 var co = convo {
225 256 con = con, srv = server, msg = msg;
226 257 aid = 0, who = nil, peer = peer;
227 258 reqtype = lib.http.mime.none;
228 259 } co.varbuf.ptr = nil
229 260 co.navbar.ptr = nil
261 + co.actorcache.top = 0
262 + co.actorcache.cur = 0
230 263
231 264 -- first, check for an accept header. if it's there, we need to
232 265 -- iterate over the values and pick the highest-priority one
233 266 do var acc = lib.http.findheader(msg, 'Accept')
234 267 -- TODO handle q-value
235 268 if acc.ptr ~= nil then
236 269 var [mimevar] = [lib.mem.ref(int8)] { ptr = acc.ptr }
................................................................................
344 377 else
345 378 co:complain(400,'unknown method','you have submitted an invalid http request')
346 379 end
347 380
348 381 if co.aid ~= 0 then lib.mem.heapf(co.who) end
349 382 if co.varbuf.ptr ~= nil then co.varbuf:free() end
350 383 if co.navbar.ptr ~= nil then co.navbar:free() end
384 + co.actorcache:free()
351 385 end
352 386 end
353 387 end;
354 388 }
355 389
356 390 local terra cfg(s: &srv, befile: rawstring)
357 391 lib.report('configuring backends from ', befile)