我正在构建一个用作基于Web的文件编辑器的应用程序。用户可以选择他们想要编辑的文件,然后从服务器中检索该文件并显示在一个字段中。用户可以编辑该文件并最终保存。检测会话的多个实例
这引入了我试图解决的竞争条件。
客户端文件并不总是与服务器端文件同步。当用户打开已在其他位置打开并编辑的文件时,保存将覆盖其他客户端所做的任何编辑。虽然可以使用某种形式的合并来解决这个问题,但这已经超出了本项目的范围。
当用户在两台不同的PC上或从两个不同的浏览器登录并尝试两次打开同一文件时,可以使用会话密钥检测到此情况。但是,当用户打开第二个选项卡时,会话密钥将相同。
目前我周期性地ping文件(比如说,每2秒)并检查一次前面的ping是否大约2秒前。如果它小于这个值(减去一些会计滞后的值),那么可能是是两个观察该文件的客户端。但是,如果用户在文件和背面之间快速切换,这会中断,而且很简单。
有没有更好,更干净的方式来做到这一点?
我正在使用Django后端和一个严重依赖jQuery的前端,所以基于这两者的任何功能都会有我的偏好。
一些相关代码如下所示:
从客户机侧,周期性地卧底文件服务器侧:
setInterval(function(){
opened = $('input[name=file]:checked', '#files').val();
if(opened){
$.post('./' + opened + '/ding').error(function(){
alert('Something is awry.');
});
}
}, 2000);
从服务器端,处理这些弯折:
def ding(request, user_id, project_id, file_id):
user = User.objects.get(pk=user_id)
project = Project.objects.get(pk=project_id)
file = File.objects.get(pk=file_id)
session_key = request.session.session_key
can_claim = file.last_seen_open == None or timezone.now() - file.last_seen_open > datetime.timedelta(seconds=4)
is_mine = file.last_opened_by == session_key
is_iffy = file.last_seen_open != None and timezone.now() - file.last_seen_open < datetime.timedelta(seconds=1)
if is_iffy:
return HttpResponse(status=409, content="File is iffy")
if can_claim or is_mine:
file.last_opened_by = session_key
file.last_seen_open = timezone.now()
file.save()
return HttpResponse(status=200, content="File ding'd")
else:
return HttpResponse(status=409, content="File claimed by someone else")
如果看起来该文件在相同的密钥上打开两次,则返回响应“409:文件不可用”