我正在構建一個用作基於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:文件不可用」