parsav  Diff

Differences From Artifact [afa0417e30]:

To Artifact [d14bb4b6ce]:


    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)