Web ベースのファイル エディターとして機能するアプリケーションを構築しています。ユーザーが編集したいファイルを選択すると、そのファイルがサーバーから取得され、フィールドに表示されます。その後、ユーザーはファイルを編集し、最終的に保存できます。
これにより、解決しようとしている競合状態が発生します。
クライアント側のファイルは、サーバー側のファイルと常に同期しているわけではありません。ユーザーが別の場所で既に開いて編集したファイルを開くと、保存すると、他のクライアントによって行われた編集が上書きされます。これは何らかの形のマージを使用して修正できますが、これはこのプロジェクトの範囲外です。
ユーザーが 2 つの異なる PC または 2 つの異なるブラウザーからログインし、同じファイルを 2 回開こうとすると、セッション キーを使用してこれを検出できます。ただし、ユーザーが 2 番目のタブを開くと、セッション キーは同じになります。
現在、ファイルに対して定期的に (たとえば、2 秒ごとに) ping を実行し、前回の ping が約 2 秒前かどうかを確認します。それよりも小さい場合 (遅延を考慮した値を差し引いた値)、2 つのクライアントがそのファイルを監視している可能性があります。ただし、ユーザーがファイルをすばやく切り替えて元に戻すと、これは機能しなくなり、単純に見苦しくなります。
これを行うためのより良い、よりクリーンな方法はありますか?
私は Django バックエンドと、jQuery に大きく依存するフロントエンドを使用しているため、これら 2 つに基づく機能は私の好みです。
関連するコードを以下に示します。
クライアント側から、ファイル サーバー側を定期的に dinging します。
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")
ファイルが同じキーで 2 回開かれていると思われる場合、"409: File is iffy" という応答が返されます。