0

I'm building an application that serves as a web-based file editor. Users can select a file they want to edit, then that file is retrieved from the server and shown in a field. The user can then edit the file, and eventually save it.

This introduces a race-condition I'm trying to solve.

The client-side file is not always in sync with the server-side file. When a user opens a file that has already been opened and edited in another place, saving will overwrite any edits done by the other client. While this could be fixed using some form of merging, this is quite a bit outside the scope of this project.

When a user logs in on two different pc's or from two different browsers, and tries to open the same file twice, this can be detected using the session key. However, when a user opens a second tab, the session key will be identical.

Currently I periodically ping the file (say, every 2 seconds) and check if the previous ping is about 2 seconds ago. if it is less than that (minus some value accounting for lag) there might be two clients watching that file. This however breaks if a user quickly switches between a file and back, and is just plain ugly.

Is there a better, cleaner way of doing this?

I'm using a Django backend, and a frontend that relies heavily on jQuery, so any functionality based on these two would have my preference.

Some relevant code is shown below:

From the client-side, periodically dinging the file server-side:

setInterval(function(){
    opened = $('input[name=file]:checked', '#files').val();
    if(opened){
        $.post('./' + opened + '/ding').error(function(){
            alert('Something is awry.');
        });
    }
}, 2000);

From the server-side, handling these dings:

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")

The response "409: File is iffy" is returned if it seems that the file is opened twice on the same key

4

1 回答 1

0

我偶然在这里发现了你的问题。由于这个问题已经有几个月了,我不确定你是否还在等待答案。不过,我认为有一个简单的解决方案:

当用户请求文件时,不仅获取文件的内容,还获取最后修改日期。将该值存储在客户端。当用户进行一些更改并选择保存文件时,将值与新内容一起发送。在服务器端,您可以将文件的当前修改日期与用户发送的值进行比较。如果它们不匹配,则该文件同时已被另一个用户更新。

于 2013-04-28T21:06:40.400 回答