StrokesPlus.net
Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
lukas  
#1 Posted : Wednesday, September 23, 2020 1:11:16 AM(UTC)
lukas

Rank: Newbie

Reputation:

Groups: Approved
Joined: 5/5/2020(UTC)
Posts: 3

I'm in a slight pickle...

Before the internal sync was introduced, I used Dropbox to sync my settings between 3 machines. This would produce frequent syncing conflicts, since StrokesPlus does not recognize/reload changes to the settings file made on another machine.

Naturally, I jumped on the internal sync feature, when it was introduced! But of course I soon forgot that I had to manually import the settings on each machine after every modification, and now my machines are hopelessly out of sync...

So here are my questions:
  • Is there a way to make StrokesPlus recognize/obey changes to the settings file? (So sync works without interaction; e.g. a function that periodically checks for and reloads on a file change.)
  • Is there a way to export my settings in a human-readable format, so I can compare them and manually identify the changes made on each machine individually?

Edited by moderator Friday, September 25, 2020 6:56:06 AM(UTC)  | Reason: Updated status and added description

Rob  
#2 Posted : Wednesday, September 23, 2020 7:03:33 AM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 718
United States
Location: Tampa, FL

Thanks: 14 times
Was thanked: 163 time(s) in 141 post(s)
1. Sure, you can use the FileSystemWatcher class to watch just the settings file and trigger an event which reloads S+.

Add this script to Global Actions > Load/Unload > Load:

Code:
//Only install this watcher in the last script engine pool so it's not running multiple instances
if(__spEngineWrapper.Engine.Name == sp.EngineList().Last().Engine.Name)
{
    var configWatcher = new clr.System.IO.FileSystemWatcher();
    //Set the path to the default S+ config file location, change if needed
    configWatcher.Path = clr.System.IO.Path.Combine(clr.System.Environment.GetFolderPath(clr.System.Environment.SpecialFolder.ApplicationData), "StrokesPlus.net");
    //Only watch the S+ config file, no others in the directory
    configWatcher.Filter = "StrokesPlus.net.bin";
    //Only subscribe to file write operations
    configWatcher.NotifyFilter = clr.System.IO.NotifyFilters.LastWrite;
    //Create the event handler which is called when the file changes
    var configChangedEvent = configWatcher.Changed.connect(
        function (sender, fileChangedEvent) {
            //Create a timer when the file is changed, to wait 1 second, clean up, and reload S+
            sp.CreateTimer("ConfigReload", 
                            1000, 
                            0, 
                            `  sp.GetStoredObject("ConfigChangedEvent").disconnect(); 
                               sp.GetStoredObject("ConfigWatcher").Dispose();
                               sp.DeleteStoredObject("ConfigWatcher");
                               sp.Reload();
                            `);
        }
    );
    //Start the file watcher
    configWatcher.EnableRaisingEvents = true;
    //Store the file watcher and Changed event objects so the timer can access them
    sp.StoreObject("ConfigChangedEvent", configChangedEvent);
    sp.StoreObject("ConfigWatcher", configWatcher);
}



2. Ugh, that is a pickle. So the settings object (sp_config in scripts) is just a .NET class/object, so there's nothing proprietary going on. I put this plug-in together to export the object to JSON, it looks like the output file is complete, but I cannot guarantee it 100%

https://www.strokesplus.net/files/SettingsJSONExport.zip

NOTE: Extract this with 7-Zip or if using Windows, right-click the DLL after you extract it and uncheck the blocked or whatever box so Windows will trust/allow it to load.

Then open S+ and go to the Plug-Ins section and click Add Plug-In... under the Search Locations tab.

Finally, make a temp action to call the script below, the script below assumes the StrokesPlus.net.bin file is in the standard install location, so change as needed.
The first param is the location of the config file, the second is where to save the json file.

Note: This assumes you do not have a password set via the tray icon (Set Password...). If you do have that, clear the password (leave new password fields blank) until you finish the export.

Code:
var configFolder = clr.System.Environment.GetFolderPath(clr.System.Environment.SpecialFolder.ApplicationData) + "\\StrokesPlus.net";
SettingsJSONExport.Export(configFolder + "\\StrokesPlus.net.bin", configFolder + "\\StrokesPlus.net.json");

Once you have your JSON files from each config, you can compare as needed, though reconciliation might be tedious. However, there are JSON compare websites out there and read the section below as if you're adept at C# you could handle it programmatically (though I'd suspect it would be quicker to just manually handle the necessary differences).


By the way, if you're familiar with C# it's very easy to make plug-ins. In this case it was super easy as I already built-in a JSON export function, but trying to deserialize the JSON back into the Settings class object blew up so I don't use it. Create a new C# .NET Framework Library Class, select .NET version 4.6.2, then under References, click Add and browse to StrokesPlus.net.exe to access the public classes/etc. Below is the entirety of this plug-ins code.
Note that you don't need to reference StrokesPlus.net.exe unless you're trying to access something specific internally - in fact I don't generally recommend it because I don't consider those classes/etc to be something for which I maintain compatibility as they're really internal things. But in this case, it makes sense.
Code:
using StrokesPlus.net.Code;

namespace SettingsJSONExport
{
    public static class SettingsJSONExport
    {
        public static void Export(string configPath, string jsonPath)
        {
            var config = SettingsReader.ReadFromBinaryFile<Settings>(configPath, true);
            SettingsReader.WriteToJSONFile<Settings>(jsonPath, config);
        }
    }
}
lukas  
#3 Posted : Wednesday, September 23, 2020 2:22:30 PM(UTC)
lukas

Rank: Newbie

Reputation:

Groups: Approved
Joined: 5/5/2020(UTC)
Posts: 3

Wow, phenomenal response! ThumpUp

Sync seems to work well with this method so far and I could resolve all my conflicts - there were fewer than I feared.

Thanks a ton!
Rob  
#4 Posted : Thursday, September 24, 2020 11:09:03 AM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 718
United States
Location: Tampa, FL

Thanks: 14 times
Was thanked: 163 time(s) in 141 post(s)
You're very welcome!

I have Synchronize properties for all actions/etc. for the intent of telling S+ which ones you want to sync - e.g. it would work a bit like you're wanting to, except for example don't sync these because I only use them at work.

However, it's just a pain to make the decisions of which one changed first, who wins, etc. Figured it's probably better to use the file system watcher to reload and let other file sync services handle that. Some day I might get that built-in...
lukas  
#5 Posted : Monday, September 28, 2020 10:51:55 AM(UTC)
lukas

Rank: Newbie

Reputation:

Groups: Approved
Joined: 5/5/2020(UTC)
Posts: 3

2 things I wonder:
  1. The settings file updates every time the app shuts down (and thus causes a sync and reload cycle on the other machines). This is not a problem per se, I am just wondering if that's only due to the MatchCount of the actions that changes, or is there something else updated in the settings?
  2. I used to run the backup script that would create a copy of the settings file every time the app shuts down. In the end that proofed rather unhelpful, since the files where innumerable and virtually indistinguishable from each other. I was wondering if there is a way to only create a new backup when the settings have actually changed, e.g. whenever I click 'apply' or 'ok' in the settings window?
Rob  
#6 Posted : Monday, September 28, 2020 11:56:29 AM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 718
United States
Location: Tampa, FL

Thanks: 14 times
Was thanked: 163 time(s) in 141 post(s)
1. It doesn't discriminate in any way, it just saves whatever is in memory to disk upon exit

2. You could use the plug-in and churn through the JSON, comparing it to another JSON file - e.g. have one call in Load which spits out a JSON file, and in Unload does it again then compares. There's no simple method for handling this, at least not that I'm aware of.

Same goes for sync, really. If you put together the necessary logic to determine if any effective changes are present, you could instead shift to outputting JSON files that you keep sync'd (in addition to the StrokesPlus.net.bin file, but perhaps with a different name so it's only used if the JSON compare sees a meaningful difference) and have the Load code watch for the JSON file changes, compare, then replace StrokesPlus.net.bin or something.

This is why I didn't go all in on having sync yet, it's a lot to bother with :P
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.