Blog
All Blog Posts | Next Post | Previous PostRevisiting persisting app settings in the cloud
Tuesday, May 3, 2016
Back in 2013, I wrote a blog on persisting application settings in the cloud like Google Chrome for example does. The solution presented at that time was using the DropBox cloud service. The technique was quite simple. Persist settings in an INI file and automatically store and retrieve this INI file from a DropBox account.Now, 3 years later, I wanted to revisit this technique and present a new solution that is more flexible and fine-grained and can be used from apps on Windows, Mac OSX, iOS, Android and Linux. The new technique will use the TMS structured data cloud storage service myCloudData.net.
As a brief introduction to myCloudData, think of it as configurable tables in the cloud, accessible with a REST API and using OAUTH 2 for authentication & authorization. If you want to learn more about myCloudData.net, check its API doc or another blog article written about it.
Time to get down to the nitty gritties! As an example, a VCL app was created with a left and right aligned panel and inbetween a memo. The user can customize the left panel and right panel width with a splitter control and by right-clicking the panel, the panel color can be changed. Further, there is a checkbox for both panels to toggle the visibility of the panel. This is a typical and basic skeleton of what many user configurable apps could be.
We'll now use the myCloudData.net service to store not only how the user configures this left and right panel, but also the last form's size and position on the screen. Whenever the user restarts the app, it will bring back the app as he originally left it on whatever machine the user starts this app. He will always find it back as he left it.
We'll drop a TAdvmyCloudData component on the form and in the form's constructor, we'll initialize it with the application key & secret obtained to use the myCloudData.net service. Further, this component is initialized to persist its application token & secret and finally, the call to AdvmyCloudData.Connect will test validity of possible existing tokens or will perform a new authentication & authorization when no valid tokens are found.
procedure TmCDDemo.FormCreate(Sender: TObject); begin FConnected := false; AdvMyCloudData1.App.Key := MYCLOUDDATAKEY; AdvMyCloudData1.App.Secret := MYCLOUDDATASECRET; AdvMyCloudData1.App.CallBackPort := 8888; AdvMyCloudData1.App.CallBackURL := 'http://127.0.0.1:8888'; AdvMyCloudData1.PersistTokens.Location := plIniFile; AdvMyCloudData1.PersistTokens.Key := '.myCloudData.ini'; AdvMyCloudData1.PersistTokens.Section := 'tokens'; AdvMyCloudData1.Connect; end;
In the ReadSettings method, it is checked whether the table to hold the settings exists for the user account on the service or not. When found, the first record from the table is read to retrieve the settings. When not found, the metadata for the table is created. Of course when the new table is created with its metadata, it's not yet possible to retrieve stored settings. This table will only be used the first time then when the user closes the app.
procedure TmCDDemo.ReadSettings; var table: TMyCloudDataTable; begin table := AdvMyCloudData1.TableByName('SETTINGS'); if not Assigned(table) then begin table := AdvMyCloudData1.CreateTable('SETTINGS'); table.MetaData.Add('PNLVISL', ftBoolean); table.MetaData.Add('PNLVISR', ftBoolean); table.MetaData.Add('PNLWL', ftInteger); table.MetaData.Add('PNLWR', ftInteger); table.MetaData.Add('PNLCLRL', ftInteger); table.MetaData.Add('PNLCLRR', ftInteger); table.MetaData.Add('FORMW', ftInteger); table.MetaData.Add('FORMH', ftInteger); table.MetaData.Add('FORML', ftInteger); table.MetaData.Add('FORMT', ftInteger); table.SetMetaData; end else begin table.Query; if table.Entities.Count > 0 then begin Self.Left := table.Entities[0].Value['FORML']; Self.Top := table.Entities[0].Value['FORMT']; Self.Width := table.Entities[0].Value['FORMW']; Self.Height := table.Entities[0].Value['FORMH']; LeftPanel.Visible := table.Entities[0].Value['PNLVISL']; RightPanel.Visible := table.Entities[0].Value['PNLVISR']; LeftPanel.Width := table.Entities[0].Value['PNLWL']; RightPanel.Width := table.Entities[0].Value['PNLWR']; LeftPanel.Color := TColor(table.Entities[0].Value['PNLCLRL']); RightPanel.Color := TColor(table.Entities[0].Value['PNLCLRR']); LeftCheckBox.Checked := LeftPanel.Visible; RightCheckBox.Checked := RightPanel.Visible; end; end; end;
To store the settings, all we need to do is call WriteSettings from the form's OnClose event. This of course is only done when TAdvmyCloudData was able to succesfully connect to an account on the service:
procedure TmCDDemo.FormClose(Sender: TObject; var Action: TCloseAction); begin if FConnected then WriteSettings; end;
procedure TmCDDemo.WriteSettings; var table: TMyCloudDataTable; entity: TMyCloudDataEntity; ins: boolean; begin table := AdvMyCloudData1.TableByName('SETTINGS'); table.Query; ins := table.Entities.Count = 0; if not ins then entity := table.Entities[0] else entity := table.Entities.Add; entity.Value['FORML'] := Self.Left; entity.Value['FORMT'] := Self.Top; entity.Value['FORMW'] := Self.Width; entity.Value['FORMH'] := Self.Height; entity.Value['PNLVISL'] := LeftPanel.Visible; entity.Value['PNLVISR'] := RightPanel.Visible; entity.Value['PNLWL'] := LeftPanel.Width; entity.Value['PNLCLRL'] := integer(LeftPanel.Color); entity.Value['PNLWR'] := RightPanel.Width; entity.Value['PNLCLRR'] := integer(RightPanel.Color); if not ins then entity.Update else entity.Insert; end;
I hope this serves as a small example of uses for the myCloudData.net service and actually only scratches the surface of possibilities. The use of myCloudData.net for the functionality demonstrated here is completely free, as in free beer. Only when using large amounts of data or blob fields, a subscription to myCloudData.net is required.
Our TMS Cloud Pack component TAdvmyCloudData makes it completely abstract and dead-simple to use the underlying REST API from the service for VCL applications and this component is also available with exactly the same interface for FireMonkey applications and Lazarus applications.
We are eager to learn about your creative and innovative applications using these components and service and in what further directions this can be developed to satisfy your needs!
The full source code of this sample application can be downloaded here.
Bruno Fierens
This blog post has not received any comments yet.
All Blog Posts | Next Post | Previous Post