Jozsef Hocza

Sync Electron+Vue.js ToDo App with Lumen Part 1

The Quest

So now that I set up a simple API that would allow users to sign up and log in, I started to build a Desktop Application with Electron+Vue.js.

The beginning - Persisted State

I made a simple UI, you can add new tasks that will store in the “memory”. But once you hit CMD+R the webkit refreshes and loses all data. Well not a big deal, we are using Chromium with electron, so let’s install vuex-persistedstate (for the localstorage) and we are good to go! :)

Ok now my Electron App is capable of storing data locally.

Now what?

Well we should be able to interact with the API, but first… I have to plan it.

Checking how other App handle the Synchronization

Since this project should be a cross platform project syncing is essential. But how should I do that? I quickly hit up my favourite todo app manager that lately got acquired by Microsoft.

I did some real life scenarios, like:

  1. I created a task: “Conquer the world today” on my Mac. It “instantly” synced to my phone and tablet.
  2. Time to go dark: Offline mode on all three devices.
  3. Let’s edit it on the Mac: “Conquer the world tomorrow”
  4. On Phone: “Conquer the world oneday”
  5. On Tablet: “Conquer the world immediately” - At this point I guess all of us would think that the last change would be seen on all other devices. I was wrong.
  6. Briging online the: Tablet, it says: “Conquer the world immediately” - obviously.
  7. Now the Phone - Strange thing happened, it now says: “Conquer the world oneday” on both devices
  8. Now the Mac - Now you can guess, on all three devices the task changed to: “Conquer the world tomorrow”

After doing some other more It seems that they do not store the time, just the change, then call the API with the modifications made while it was offline.

My Plan for Synchronization

Well I wanted to do the same that this App did I checked. But It sounded a bit off for me, sounded a bit too easy… but it seems it is a viable sync option for a task management app. I made it bold, because it is suitable for these kind of apps, not for everything.

Let’s sketch the plan, shall we?

We will see if I was wrong in the Part 2 once I start to code it.

So my plan is to create a simple array of objects, and an “inSync” variable.

var inSync = false;
var queue = [];

Obviously when I start the App for the first time, create my user and log in, it should try to get the /api/tasks from the API. When it does, the inSync will be set as true.

If I close the app, and start again, on start up, it should check if it is still in Sync or not.

I am thinking of creating an easy “inSync” check. I came up with several simple ideas.

  1. First one is to compare hashes. Like: return $user->tasks->toJson() then hash the store.state.tasks.tasks and compare them.
  2. Or I could create a counter on the user, that how many times he modified his data. I could put this into a REDIS in-memory DB, since it is a simple integer. In this case if the Application hits the API it wouldn’t need to hit the DB and return all of the user’s tasks format it JSON make a hash and then return the value.
  3. I could store all the changes made in a task_revisions table, and check which revision he had and pushing all the missing ones. Well, this would hit performance badly, I guess it would be also an overkill for this project. :)

Anyway I guess I will choose something if I not come up with a better idea.

While the Apps are online I am planning to make a socket.io websocket where they can receive and apply any change made to any task. Well maybe for mobile apps I have to implement something else, maybe push messages, I will see. However the websocket would give me a quick feedback if the connection times out.

The array

In the queue array I will store almost every change that need to be committed to the API. I wrote almost because I wouldn’t want to send 2 requests if I changed the same tasks name twice. So everytime I made a change in offline mode I should be able to go thru the queue and see If I already have an awaiting “edit” on that task.

The structure of the queue object

<script>
// If I change the name of the Task with ID #5
{
	route: '/tasks/5'
	method: 'patch'
	data: {
		name: "My task's new name"
	} 
}

So in that case if I edit Task with ID #5’s name again, I would need to check queue if it has a /tasks/5 route with PATCH method. If it does, then I just simply need to:

queue[index].data.name = "My New Value"

By doing so I will be able to add more changes to a single Task. Let’s say I am still in offline mode and I would like to change the due_date.

queue[index].data.date_due = "2017-01-22"

I can also edit the description:

queue[index].data.description = "So this is the new description"

Now my object in the queue array will look like this:

<script>
// If I change the name of the Task with ID #5
{
	route: '/tasks/5',
	method: 'patch',
	data: {
		name: "My New Value",
		date_due: "2017-01-22",
		description: "So this is the new description"
		} 
}

I will only make one call, instead of 4. How cool is that? :)

Execution of the Plan

A plan is as good as it works. Now I will need to take some time to implement these stuff and see If the plan is right.

I will need to add some more functions to my Lumen API (yeeeaah more tests!)

Oh one more thing. I have to drop Auto increment for Tasks if I want to support Offline Task Creation. I am already looking into GUID to achieve this.

No Lumen for today

Sorry for the lack of Lumen TDD in this post. Part 2 will not be like this, fingers crossed!


Share this:

SUBSCRIBE
Subscribe to my e-mail list.
You can unsubscribe anytime.