more conflict-resistant comment storage
Until now, comments were stored in filenames with an incrementing counter. As a result, conflicts are easy; two people commenting on a post around the same time would create the same filename. Then they'd run into conflicts when merging. Now comment filenames include a random slug. A secondary consideration is filtering out comments from the file-picker screen. It's only intended for top-level posts. I had a hacky way to do this. My ideal approach would be a directory per post, but Lua+LÖVE doesn't have a portable way to create directories. Now you now have to manually create a single directory called `comments/` in the directory of articles before using pothi.love.
This commit is contained in:
parent
e0d017867b
commit
8cfc7e3e10
|
@ -2,6 +2,8 @@ load_metadata = function(filename)
|
|||
local mfile = metadata_file(filename)
|
||||
local mpath = save_dir_path(mfile)
|
||||
if not love.filesystem.getInfo(mpath) then
|
||||
-- comments will always have metadata,
|
||||
-- so we only get here for top-level posts with no parent
|
||||
return {replies={}}
|
||||
end
|
||||
return json.decode(love.filesystem.read(mpath))
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
initialize_item = function(id, depth)
|
||||
local path
|
||||
if depth == 0 then
|
||||
path = full_path(id)
|
||||
else
|
||||
path = comment_path(id)
|
||||
end
|
||||
local result = {
|
||||
type='text',
|
||||
id=id, filename=full_path(id),
|
||||
id=id, filename=path,
|
||||
width=Width, depth=depth,
|
||||
metadata=load_metadata(id),
|
||||
border=Border_color,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
initialize_file_picker = function()
|
||||
Files = love.filesystem.getDirectoryItems('data')
|
||||
for i=#Files,1,-1 do
|
||||
if (not Files[i]:match('%.md$')) or Files[i]:match('%-%d+.md$') then
|
||||
if not Files[i]:match('%.md$') then
|
||||
table.remove(Files, i)
|
||||
end
|
||||
end
|
||||
|
@ -16,4 +16,4 @@ initialize_file_picker = function()
|
|||
border={r=0.4, g=0.4, b=0.7}
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +1,14 @@
|
|||
new_comment = function(parent_id, depth)
|
||||
local id = next_comment_id(parent_id)
|
||||
local id = new_comment_id(parent_id)
|
||||
print('creating', id)
|
||||
local comment = {
|
||||
type='text',
|
||||
id=id,
|
||||
filename=full_path(id),
|
||||
filename=comment_path(id),
|
||||
data={{data=''}},
|
||||
width=Width,
|
||||
depth=depth+1,
|
||||
metadata={replies={}},
|
||||
metadata={parent=parent_id, replies={}},
|
||||
border=Border_color,
|
||||
}
|
||||
save_metadata(comment)
|
||||
|
@ -20,4 +20,4 @@ new_comment = function(parent_id, depth)
|
|||
table.insert(item_stuff.data,
|
||||
reply_button(comment.id, depth+1))
|
||||
return result, id
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
new_comment_id = function(id)
|
||||
local corename = id:gsub('%.md$', '')
|
||||
-- there'll be a collision on avarage every #Random_string_chars^(n/2) = 1296 comments
|
||||
local n = 4
|
||||
local result = ('%s-%s.md'):format(corename, random_string(4))
|
||||
if file_exists(comment_path(result)) then
|
||||
-- retry
|
||||
-- This will infinite loop every #Random_string_chars^n = 1.6M, but it'll start taking a long time by halfway as long.
|
||||
return new_comment_id(id)
|
||||
end
|
||||
return result
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
next_comment_id = function(id)
|
||||
local num_replies = #load_metadata(id).replies
|
||||
local corename = id:gsub('%.md$', '')
|
||||
return ('%s-%d.md'):format(corename, num_replies)
|
||||
end
|
|
@ -1,6 +1,11 @@
|
|||
save_metadata = function(node)
|
||||
--print('saving metadata for', node.id)
|
||||
local mfile = metadata_file(node.id)
|
||||
local mpath = save_dir_path(mfile)
|
||||
local mpath
|
||||
if node.metadata.parent then
|
||||
mpath = save_dir_path('comments/'..mfile)
|
||||
else
|
||||
mpath = save_dir_path(mfile)
|
||||
end
|
||||
love.filesystem.write(mpath, json.encode(node.metadata))
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
Random_string_chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
|
|
@ -0,0 +1,10 @@
|
|||
random_string = function(n)
|
||||
-- generate a random string of length n
|
||||
local result = {}
|
||||
local nchars = #Random_string_chars
|
||||
for i=1,n do
|
||||
local idx = math.random(1, nchars)
|
||||
table.insert(result, Random_string_chars:sub(idx, idx))
|
||||
end
|
||||
return table.concat(result)
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
comment_path = function(id)
|
||||
return full_path('comments/'..id)
|
||||
end
|
Loading…
Reference in New Issue