parsav  Check-in [a4b4af5ca4]

Overview
Comment:begin work on circles
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a4b4af5ca4157d4716100e593c53b6427f46222b2a9d48f4c4c791c6774b767d
User & Date: lexi on 2021-01-13 15:01:13
Other Links: manifest | tags
Context
2021-01-14
01:11
more work on UI and circles check-in: 03ea3dffe7 user: lexi tags: trunk
2021-01-13
15:01
begin work on circles check-in: a4b4af5ca4 user: lexi tags: trunk
13:57
implement some sanctions check-in: 60040f3ca3 user: lexi tags: trunk
Changes

Modified backend/pgsql.t from [bd352a7166] to [96ec125a09].

282
283
284
285
286
287
288
























289
290
291
292
293
294
295
....
2035
2036
2037
2038
2039
2040
2041
2042








































2043
2044
2045
2046

	actor_notice_enum = {
		params = {uint64}, sql = [[
			select (notice).* from pg_temp.parsavpg_notices
			where rcpt = $1::bigint
		]];
	};

























	auth_sigtime_user_fetch = {
		params = {uint64}, sql = [[
			select authtime::bigint
			from parsav_actors where id = $1::bigint
		]];
	};
................................................................................
			end
			return 0, false
		end];
	actor_conf_int_set = [terra(src: &lib.store.source, uid: uint64, key: rawstring, value: uint64): {}
			queries.actor_conf_int_set.exec(src,uid,key,value) end];
	actor_conf_int_reset = [terra(src: &lib.store.source, uid: uint64, key: rawstring): {}
			queries.actor_conf_int_reset.exec(src,uid,key) end];









































	actor_auth_register_uid = nil; -- TODO better support non-view based auth
}

return b







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
....
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110

	actor_notice_enum = {
		params = {uint64}, sql = [[
			select (notice).* from pg_temp.parsavpg_notices
			where rcpt = $1::bigint
		]];
	};

	circle_search = {
		params = {uint64,uint64}, sql = [[
			select name, id, owner, array_length(members,1) from parsav_circles where
				($1::bigint = 0 or $1::bigint = owner) and
				($2::bigint = 0 or $2::bigint = id)
		]];
	};

	circle_members_fetch_cid = {
		params = {uint64, uint64}, sql = [[
			select unnest(members) from parsav_circles where
				($1::bigint = 0 or owner = $1::bigint) and
				id = $2::bigint
		]];
	};

	circle_members_fetch_name = {
		params = {uint64, pstring}, sql = [[
			select unnest(members) from parsav_circles where
				($1::bigint = 0 or owner = $1::bigint) and
				name = $2::text
		]];
	};

	auth_sigtime_user_fetch = {
		params = {uint64}, sql = [[
			select authtime::bigint
			from parsav_actors where id = $1::bigint
		]];
	};
................................................................................
			end
			return 0, false
		end];
	actor_conf_int_set = [terra(src: &lib.store.source, uid: uint64, key: rawstring, value: uint64): {}
			queries.actor_conf_int_set.exec(src,uid,key,value) end];
	actor_conf_int_reset = [terra(src: &lib.store.source, uid: uint64, key: rawstring): {}
			queries.actor_conf_int_reset.exec(src,uid,key) end];
	
	circle_search = [terra(
		src: &lib.store.source,
		pool:&lib.mem.pool,
		uid: uint64,
		cid: uint64
	): lib.mem.ptr(lib.store.circle)
		var res = queries.circle_search.exec(src, uid, cid)
		if res.sz == 0 then return [lib.mem.ptr(lib.store.circle)].null() end
		defer res:free()

		var rt = pool:alloc(lib.store.circle, res.sz)
		for i = 0, res.sz do
			var name = res:_string(i,0)
			rt(i) = lib.store.circle {
				name = name:pdup(pool);
				cid = res:int(uint64,i,1);
				owner = res:int(uint64,i,2);
				memcount = res:int(uint64,i,3);
			}
		end

		return rt
	end];

	circle_members_fetch_cid = [terra(
		src: &lib.store.source,
		pool:&lib.mem.pool,
		uid: uint64,
		cid: uint64
	): lib.mem.ptr(uint64)
		var res = queries.circle_members_fetch_cid.exec(src,uid,cid)
		if res.sz == 0 then return [lib.mem.ptr(uint64)].null() end
		defer res:free()

		var rt = pool:alloc(uint64, res.sz)
		for i = 0, res.sz do rt(i) = res:int(uint64,i,0) end

		return rt
	end];

	actor_auth_register_uid = nil; -- TODO better support non-view based auth
}

return b

Modified mem.t from [05a21ff4d9] to [a251bec86e].

105
106
107
108
109
110
111
112



113
114
115
116
117
118
119
		self.ptr = self.ptr + n
		self.ct = self.ct - n
		return self.ptr
	end
	terra t.methods.null(): t return t { ptr = nil, ct = 0 } end -- maybe should be a macro?
	terra t:ref() return self.ptr ~= nil end
	t.metamethods.__not = macro(function(self) return `not self:ref() end)
	t.metamethods.__apply = macro(function(self,idx) return `self.ptr[idx] end)



	if not ty:isstruct() then
		terra t:cmp_raw(other: &ty)
			for i=0, self.ct do
				if self.ptr[i] ~= other[i] then return false end
			end
			return true
		end







|
>
>
>







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
		self.ptr = self.ptr + n
		self.ct = self.ct - n
		return self.ptr
	end
	terra t.methods.null(): t return t { ptr = nil, ct = 0 } end -- maybe should be a macro?
	terra t:ref() return self.ptr ~= nil end
	t.metamethods.__not = macro(function(self) return `not self:ref() end)
	t.metamethods.__apply = macro(function(self,idx) return `self.ptr[ [idx or 0] ] end)
	t.metamethods.__update = macro(function(self,idx,rhs)
		return quote self.ptr[idx] = rhs end end)

	if not ty:isstruct() then
		terra t:cmp_raw(other: &ty)
			for i=0, self.ct do
				if self.ptr[i] ~= other[i] then return false end
			end
			return true
		end

Modified render/timeline.t from [dac341c838] to [900216dd8b].

5
6
7
8
9
10
11
12






13
14

15
16
17
18

19
20
21
22
23
24
25
..
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
requires_login(m: modes.t): bool
	return m == modes.follow
	    or m == modes.mutual
	    or m == modes.circle
end

local terra 
render_timeline(co: &lib.srv.convo, modestr: lib.mem.ref(int8))






	var mode = modes.follow
	var circle: uint64 = 0

	if     modestr:cmp('local') then mode = [modes['local']]
	elseif modestr:cmp('mutual') then mode = modes.mutual
	elseif modestr:cmp('fedi') then mode = modes.fedi
	elseif modestr:cmp('circle') then mode = modes.circle

	end
	if requires_login(mode) and co.aid == 0 then mode = [modes['local']] end


	var stoptime = lib.osclock.time(nil)

	var posts = [lib.mem.vec(lib.mem.ptr(lib.store.post))] { 
................................................................................
	var acc = co:stra(1024)
	var modelabels = arrayof(pstr, 'followed', 'mutuals', 'local instance', 'fediverse', 'circle')
	var modelinks = arrayof(pstr, [modes.members])
	acc:lpush('<div style="text-align: right"><em>showing ')
	for i=0, [modelabels.type.N] do
		if co.aid ~= 0 or not requires_login(i) then
			if i > 0 then acc:lpush(' · ') end
			if i == mode then
				acc:lpush('<strong>'):ppush(modelabels[i]):lpush('</strong>')
			else
				acc:lpush('<a href="/tl/'):ppush(modelinks[i]):lpush('">'):ppush(modelabels[i]):lpush('</a>')
			end
		end
	end
	acc:lpush('</em></div>')
	acc:lpush('<div id="tl" data-live="10">')
	var newest: lib.store.timepoint = 0














	for i = 0, posts.sz do
		var author = co:uid2actor(posts(i).ptr.author)
		if mode == modes.mutual and posts(i).ptr.author ~= co.who.id then
			if not author.relationship.recip.follow() then goto skip end
		end
		if author.relationship.rel.mute() or 
		   author.relationship.rel.avoid() or 
		   author.relationship.recip.exclude() then goto skip end
		lib.render.tweet(co, posts(i).ptr, &acc)
		var t = lib.math.biggest(lib.math.biggest(posts(i).ptr.posted, posts(i).ptr.discovered),posts(i).ptr.edited)
		if t > newest then newest = t end
		::skip:: posts(i):free()
	end
	if posts.run > 0 then posts:free() end
	acc:lpush('</div>')


	var doc = [lib.srv.convo.page] {
		title = 'timeline';
		body = acc:finalize();
		class = 'timeline';
		cache = false;
	}

	co:livepage(doc,newest)


	--doc.body:free()
end
return render_timeline







|
>
>
>
>
>
>


>
|
|
|
|
>







 







|







<

>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>







>
|
>
>



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
..
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
requires_login(m: modes.t): bool
	return m == modes.follow
	    or m == modes.mutual
	    or m == modes.circle
end

local terra 
render_timeline(co: &lib.srv.convo, hpath: lib.mem.ptr(lib.mem.ref(int8)))
	var modestr = lib.str.ref.null()
	var spec    = lib.str.ref.null()
	if hpath.ct >= 2 then
		modestr = hpath(1)
		if hpath.ct >= 3 then spec = hpath(2) end
	end
	var mode = modes.follow
	var circle: uint64 = 0
	if modestr:ref() then
		if     modestr:cmp('local' ) then mode = [modes['local']]
		elseif modestr:cmp('mutual') then mode = modes.mutual
		elseif modestr:cmp('fedi'  ) then mode = modes.fedi
		elseif modestr:cmp('circle') then mode = modes.circle
		end
	end
	if requires_login(mode) and co.aid == 0 then mode = [modes['local']] end


	var stoptime = lib.osclock.time(nil)

	var posts = [lib.mem.vec(lib.mem.ptr(lib.store.post))] { 
................................................................................
	var acc = co:stra(1024)
	var modelabels = arrayof(pstr, 'followed', 'mutuals', 'local instance', 'fediverse', 'circle')
	var modelinks = arrayof(pstr, [modes.members])
	acc:lpush('<div style="text-align: right"><em>showing ')
	for i=0, [modelabels.type.N] do
		if co.aid ~= 0 or not requires_login(i) then
			if i > 0 then acc:lpush(' · ') end
			if i == mode and not (mode == modes.circle and spec:ref()) then
				acc:lpush('<strong>'):ppush(modelabels[i]):lpush('</strong>')
			else
				acc:lpush('<a href="/tl/'):ppush(modelinks[i]):lpush('">'):ppush(modelabels[i]):lpush('</a>')
			end
		end
	end
	acc:lpush('</em></div>')

	var newest: lib.store.timepoint = 0
	if mode == modes.circle and not spec then
		var circles = co.srv:circle_search(&co.srv.pool, co.who.id, 0)
		acc:lpush '<menu class="circles">'
		for i:intptr = 0, circles.ct do
			acc:lpush '<li><a href="/tl/circle/'
			   :shpush(circles(i).cid)
			   :lpush '">'
			   :ppush(circles(i).name)
			   :lpush '</a></li>'
		end
		-- TODO list circles
		acc:lpush '</menu>'
	else
		acc:lpush('<div id="tl" data-live="10">')
		for i = 0, posts.sz do
			var author = co:uid2actor(posts(i).ptr.author)
			if mode == modes.mutual and posts(i).ptr.author ~= co.who.id then
				if not author.relationship.recip.follow() then goto skip end
			end
			if author.relationship.rel.mute() or 
			   author.relationship.rel.avoid() or 
			   author.relationship.recip.exclude() then goto skip end
			lib.render.tweet(co, posts(i).ptr, &acc)
			var t = lib.math.biggest(lib.math.biggest(posts(i).ptr.posted, posts(i).ptr.discovered),posts(i).ptr.edited)
			if t > newest then newest = t end
			::skip:: posts(i):free()
		end
		if posts.run > 0 then posts:free() end
		acc:lpush('</div>')
	end

	var doc = [lib.srv.convo.page] {
		title = 'timeline';
		body = acc:finalize();
		class = 'timeline';
		cache = false;
	}
	if newest ~= 0
		then co:livepage(doc,newest)
		else co:stdpage(doc)
	end
	--doc.body:free()
end
return render_timeline

Modified route.t from [cc19a11396] to [bb5bfba2ee].

218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
		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]))
end

terra http.documentation(co: &lib.srv.convo, path: hpath)
	if path.ct == 2 then
		lib.render.docpage(co,path(1))
	elseif path.ct == 1 then
		lib.render.docpage(co, rstring.null())







|







218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
		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,mode)
end

terra http.documentation(co: &lib.srv.convo, path: hpath)
	if path.ct == 2 then
		lib.render.docpage(co,path(1))
	elseif path.ct == 1 then
		lib.render.docpage(co, rstring.null())

Modified store.t from [303dfd42c8] to [8e00371af1].

236
237
238
239
240
241
242








243
244
245
246
247
248
249
...
461
462
463
464
465
466
467








468
469
470
471
472
473
474
	rtdby: uint64 -- 0 if not rt
	rtact: uint64 -- 0 if not rt, id of rt action otherwise
	isreply: bool
	source: &m.source

	-- save :: bool -> {} (defined in acl.t due to dep. hell)
}









struct m.artifact {
	rid: uint64
	owner: uint64
	desc: str
	folder: str
	mime: str
................................................................................
			-- undo: bool
	post_react: {&m.source, uint64, uint64, pstring} -> {}
			-- emoji: pstring (null to delete previous reaction, otherwise adds/changes)
	post_act_cancel: {&m.source, uint64} -> {}
	post_liked_uid: {&m.source, uint64, uint64} -> bool
	post_reacted_uid: {&m.source, uint64, uint64} -> bool
	post_act_fetch_notice: {&m.source, uint64} -> m.notice









	thread_latest_arrival_calc: {&m.source, uint64} -> m.timepoint

	artifact_instantiate: {&m.source, lib.mem.ptr(uint8), lib.mem.ptr(int8)} -> uint64
		-- instantiate an artifact in the database, either installing a new
		-- artifact or returning the id of an existing artifact with the same hash
			-- artifact: bytea







>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>







236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
...
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
	rtdby: uint64 -- 0 if not rt
	rtact: uint64 -- 0 if not rt, id of rt action otherwise
	isreply: bool
	source: &m.source

	-- save :: bool -> {} (defined in acl.t due to dep. hell)
}

struct m.circle {
	cid: uint64
	owner: uint64
	name: lib.str.t
-- ephemera
	memcount: intptr
}

struct m.artifact {
	rid: uint64
	owner: uint64
	desc: str
	folder: str
	mime: str
................................................................................
			-- undo: bool
	post_react: {&m.source, uint64, uint64, pstring} -> {}
			-- emoji: pstring (null to delete previous reaction, otherwise adds/changes)
	post_act_cancel: {&m.source, uint64} -> {}
	post_liked_uid: {&m.source, uint64, uint64} -> bool
	post_reacted_uid: {&m.source, uint64, uint64} -> bool
	post_act_fetch_notice: {&m.source, uint64} -> m.notice

	circle_search:  {&m.source, &lib.mem.pool, uint64, uint64} -> lib.mem.ptr(m.circle)
	circle_create: {&m.source, uint64, pstring} -> {}
	circle_destroy: {&m.source, uint64, uint64} -> {}
	circle_members_fetch_cid:  {&m.source, &lib.mem.pool, uint64, uint64} -> lib.mem.ptr(uint64)
	circle_members_fetch_name: {&m.source, &lib.mem.pool, uint64, pstring} -> lib.mem.ptr(uint64)
	circle_members_add_uid: {&m.source, uint64, uint64} -> {}
	circle_members_del_uid: {&m.source, uint64, uint64} -> {}

	thread_latest_arrival_calc: {&m.source, uint64} -> m.timepoint

	artifact_instantiate: {&m.source, lib.mem.ptr(uint8), lib.mem.ptr(int8)} -> uint64
		-- instantiate an artifact in the database, either installing a new
		-- artifact or returning the id of an existing artifact with the same hash
			-- artifact: bytea

Modified str.t from [ee5af81e76] to [0c9ba1d780].

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
	      (@str == @' ' or @str == @'\t' or @str == @'\n') do
		str = str + 1
		maxlen = maxlen - 1
	end
	return str
end


do local strptr = (lib.mem.ptr(int8))
	local strref = (lib.mem.ref(int8))
	local byteptr = (lib.mem.ptr(uint8))
	local function install_funcs(ty)
		ty.metamethods.__cast = function(from,to,e)
			local v = e:asvalue()
			if type(v) == 'string' then
				return `ty {ptr = v, ct = [#v]}
			elseif from == &int8 then
				return `ty {ptr = e, ct = m.sz(e)}
			elseif to == &int8 then
				return e.ptr
			end







		end
		terra ty:cmp(other: ty)
			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







<













>
>
>
>
>
>
>







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
	      (@str == @' ' or @str == @'\t' or @str == @'\n') do
		str = str + 1
		maxlen = maxlen - 1
	end
	return str
end


do local strptr = (lib.mem.ptr(int8))
	local strref = (lib.mem.ref(int8))
	local byteptr = (lib.mem.ptr(uint8))
	local function install_funcs(ty)
		ty.metamethods.__cast = function(from,to,e)
			local v = e:asvalue()
			if type(v) == 'string' then
				return `ty {ptr = v, ct = [#v]}
			elseif from == &int8 then
				return `ty {ptr = e, ct = m.sz(e)}
			elseif to == &int8 then
				return e.ptr
			end
		end
		terra ty:pdup(p: &lib.mem.pool): strptr
			if not @self then return strptr.null() end
			if self.ct == 0 then self.ct = m.sz(self.ptr) end
			var newstr = p:alloc(int8, self.ct)
			lib.mem.cpy(newstr.ptr, self.ptr, self.ct)
			return newstr
		end
		terra ty:cmp(other: ty)
			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