{"action":"created","issue":{"url":"https://api.github.com/repos/mozilla/thimble.webmaker.org/issues/916","labels_url":"https://api.github.com/repos/mozilla/thimble.webmaker.org/issues/916/labels{/name}","comments_url":"https://api.github.com/repos/mozilla/thimble.webmaker.org/issues/916/comments","events_url":"https://api.github.com/repos/mozilla/thimble.webmaker.org/issues/916/events","html_url":"https://github.com/mozilla/thimble.webmaker.org/issues/916","id":102870553,"number":916,"title":"Move away from checks that rely on time","user":{"login":"gideonthomas","id":5816130,"avatar_url":"https://avatars.githubusercontent.com/u/5816130?v=3","gravatar_id":"","url":"https://api.github.com/users/gideonthomas","html_url":"https://github.com/gideonthomas","followers_url":"https://api.github.com/users/gideonthomas/followers","following_url":"https://api.github.com/users/gideonthomas/following{/other_user}","gists_url":"https://api.github.com/users/gideonthomas/gists{/gist_id}","starred_url":"https://api.github.com/users/gideonthomas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gideonthomas/subscriptions","organizations_url":"https://api.github.com/users/gideonthomas/orgs","repos_url":"https://api.github.com/users/gideonthomas/repos","events_url":"https://api.github.com/users/gideonthomas/events{/privacy}","received_events_url":"https://api.github.com/users/gideonthomas/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/mozilla/thimble.webmaker.org/labels/bug","name":"bug","color":"fc2929"},{"url":"https://api.github.com/repos/mozilla/thimble.webmaker.org/labels/P1","name":"P1","color":"eb6420"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/mozilla/thimble.webmaker.org/milestones/8","html_url":"https://github.com/mozilla/thimble.webmaker.org/milestones/MVP","labels_url":"https://api.github.com/repos/mozilla/thimble.webmaker.org/milestones/8/labels","id":1220353,"number":8,"title":"MVP","description":"Everything we need to launch the new Thimble","creator":{"login":"humphd","id":427398,"avatar_url":"https://avatars.githubusercontent.com/u/427398?v=3","gravatar_id":"","url":"https://api.github.com/users/humphd","html_url":"https://github.com/humphd","followers_url":"https://api.github.com/users/humphd/followers","following_url":"https://api.github.com/users/humphd/following{/other_user}","gists_url":"https://api.github.com/users/humphd/gists{/gist_id}","starred_url":"https://api.github.com/users/humphd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/humphd/subscriptions","organizations_url":"https://api.github.com/users/humphd/orgs","repos_url":"https://api.github.com/users/humphd/repos","events_url":"https://api.github.com/users/humphd/events{/privacy}","received_events_url":"https://api.github.com/users/humphd/received_events","type":"User","site_admin":false},"open_issues":58,"closed_issues":57,"state":"open","created_at":"2015-07-22T14:29:55Z","updated_at":"2015-08-25T03:20:52Z","due_on":"2015-08-22T04:00:00Z","closed_at":null},"comments":1,"created_at":"2015-08-24T19:16:48Z","updated_at":"2015-08-25T03:20:56Z","closed_at":null,"body":"Our lock system on projects that indicate which project is open or not depends on each tab updating the lock stored in localStorage after a set interval.\r\n\r\nThis is a bad idea as we run into quite a number of timing issues where a project is shown as locked, but actually isn't or vice-versa.\r\n\r\nAn e.g. is right here:\r\n![time-based-checks](https://cloud.githubusercontent.com/assets/5816130/9449762/c823634e-4a72-11e5-9872-93fb6e0716b6.gif)\r\nBoth Green and Blue are incorrectly shown as unlocked, even though they are open in another tab. I can even open Blue in Thimble and make changes to it (which is bad).\r\n\r\nI don't know what the best solution out here is, but I do think we shouldn't rely on time."},"comment":{"url":"https://api.github.com/repos/mozilla/thimble.webmaker.org/issues/comments/134462854","html_url":"https://github.com/mozilla/thimble.webmaker.org/issues/916#issuecomment-134462854","issue_url":"https://api.github.com/repos/mozilla/thimble.webmaker.org/issues/916","id":134462854,"user":{"login":"humphd","id":427398,"avatar_url":"https://avatars.githubusercontent.com/u/427398?v=3","gravatar_id":"","url":"https://api.github.com/users/humphd","html_url":"https://github.com/humphd","followers_url":"https://api.github.com/users/humphd/followers","following_url":"https://api.github.com/users/humphd/following{/other_user}","gists_url":"https://api.github.com/users/humphd/gists{/gist_id}","starred_url":"https://api.github.com/users/humphd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/humphd/subscriptions","organizations_url":"https://api.github.com/users/humphd/orgs","repos_url":"https://api.github.com/users/humphd/repos","events_url":"https://api.github.com/users/humphd/events{/privacy}","received_events_url":"https://api.github.com/users/humphd/received_events","type":"User","site_admin":false},"created_at":"2015-08-25T03:20:56Z","updated_at":"2015-08-25T03:20:56Z","body":"I've been thinking about this tonight, and I think I have an answer.  We can't rely on `localStorage` for the lock, because it doesn't provide atomic operations, and you'll eventually have a race like the one above.  I've been trying to decide if we could do what we need with inter-tab communication, and everything has problems.\r\n\r\nWhat we really need is a time-delta based lock file, and we actually already have exactly what we need.  Whenever we write any data to a project, we also update the project metadata stored on the xattr of the project folder.  If we examine the `mtime` on the project root, we know roughly when the project last had any of its contents saved.  This isn't perfect, because it allows you to have a tab open to a project that just sits idle forever (no changes, no saving); I would argue that this is basically the same as not having it open at all, since Brackets will detect filesystem changes when it regains focus and you try to write something.\r\n\r\nWhat if we did this:\r\n* When you open the project folder, you first `stat` it.\r\n* If the project folder doesn't exist, then you make it, and you start using it--you're the only one using it right now (i.e., you have the \"lock\").\r\n* If the project folder does exist, you inspect `mtime`, looking to see whether it falls within some delta (we currently autosave every 5s, so that's one number to consider).\r\n* If `mtime` was last updated *within* the delta, you prompt the user and let them know that it's not wise to edit a project in multiple tabs at once (i.e., you don't get the \"lock\").\r\n* If `mtime` was last updated *outside* the delta, you assume that the \"lock\" is stale, and you go ahead and open it and start using it.\r\n\r\nI think this basically covers the most obvious cases, and does so without requiring us to build any new infrastructure--we just use the project root as a lock file, and we're done."}}