Table of Contents
I think more and more people are using some kind of online file storage nowadays. This type of storage makes your private files accessible from any computer and most people are perfectly satisfied and comfortable with it. At least those lucky ones who are not limited by some fixed enterprise security policy restrictions that prevent them from using popular services like GDrive, SkyDrive, DropBox, Mozy, WebDAV, etc. If you happen to be one of them, being perfectly happy using these services, then the ideas in this article may not be interesting for you. However if that storage works fine only for your home computers and not your company computers (like my exact case), then please have a look at my proposal below.
Basically, this article presents an idea to solve this problem. We'll be using one of the free online version control servers out there for hosting the files. Simply add your files to your version control repository of your choice – e.g. this article uses Slik SVN since it's a free one – and you can access them from any computer. Thus, it can serve as an alternative “online storage”, you should have no problems using it even behind corporate firewalls (note that I do not declare myself as a network expert, thus I won't even try to describe why the “classic” online storage services don't work in some enterprises and why the version control service does; the SyncBox tool is merely based on observations of that different behavior).
When online storage services do not work across enterprise boundary, SVN does. Note that SyncBox doesn't need to deal directly with your files.
Now the drawback with using version control this way is that you'll want to update your local files each time there's a new version in the server repository and also check in your local files to the repository each time you modify them. This is where SyncBox will help you a lot: SyncBox is a tiny desktop utility running silently in the background and synchronizing your files automatically with the help of the SVN client installed on your machine.
Actually, SyncBox doesn't synchronize the files directly. It does this indirectly, calling the SVN command line client when appropriate. That is, SyncBox automates the job of the SVN client in both directions: locally changed files are checked in automatically (after an adjustable time delay) and out-of-date files are updated from the remote server automatically. This way the whole synchronization process is transparent for the user and made silently on the background.
This whole update/check-in process uses an abstraction through the main interfaces ISyncWorker
and ISyncClient
. The “sync worker” is a non-blocking wrapper around the SVN command line client and the “sync client” is the main application logic issuing synchronization requests to the “sync worker”.
public interface class ISyncWorker
{
void SetClient(ISyncClient^ pClientToCallback);
bool Update();
bool CheckIn();
bool IsBusy();
void RequestWorkerStop(bool finishAllJobsFirst);
bool IsFileModifiedImmediately(String^ fileName);
event UpdateStartedHandler^ UpdateStarted;
event UpdateFinishedHandler^ UpdateFinished;
event CheckInStartedHandler^ CheckInStarted;
event CheckInFinishedHandler^ CheckInFinished;
event WorkerStoppedHandler^ WorkerStopped;
event ConnectionErrorHandler^ ConnectionErrorOccurred;
};
When the “sync worker” deals with the SVN command line client, possibly waiting for a response through the network, it will do so in a background thread – it won't block SyncBox's main GUI thread. That's why all the interface methods must return immediately – mostly they just issue some SVN requests. When the response for those asynchronous requests is available later, the appropriate interface event will be fired by the “sync worker”.
public interface class ISyncClient
{
enum class LogActionDestination
{
LogToFile = 0x1,
LogToOutputWindow = 0x2,
LogToAllDestinations = 0xF
};
List<string^ />^ GetSourceControlledFolders();
void LogAction(String^ msg);
void LogAction(String^ msg, LogActionDestination logDestination);
};
The ISyncClient
implementation will know which local folders contain files that need to be synchronized between local and remote versions (actually, only files contained in the SVN repository are included). Further, it also contains some event logging possibility to be used by the “sync workers”.
First, the SyncBox tool must make sure all your files are always up-to-date. It does so by periodically checking and querying the SVN repository if there are some newer versions of your files available on the remote server. If there are, then it will retrieve the newest versions immediately. The length of these periodic intervals in minutes can be set directly by the user. However, this is not a fixed value. If you're not working on your computer currently, then it's OK to use longer update intervals, thus free up the network usage whenever possible. That's why SyncBox uses a Dynamic Update Interval which means when you lock your Windows session, then the update interval will be temporarily doubled after some time. While you are still away from your computer, this doubling will repeat several times until a maximum of 1 hour is reached. Then, as soon as you return to your computer and unlock your Windows session, all these interval changes will be reverted and the value set by you will take place immediately from that moment on.
This dynamic timer behavior is achieved by a special Timer
subclass called DynamicTimer
:
ref class DynamicTimer : public System::Windows::Forms::Timer
{
public:
DynamicTimer(void);
property int IntervalMultiplyFactor; property int MaxInterval;
event System::EventHandler^ IntervalAutoChanged;
};
You use it as a normal Timer
class, however it will also follow your instructions on “slowing down” the ticks according to the MaxInterval
and IntervalMultiplyFactor
properties. In the case of SyncBox, these properties are set when the Windows session is locked/unlocked, since SyncBox registers itself for these system notifications through the WTSRegisterSessionNotification()
API:
void SyncBoxCLR::MainForm::WndProc(Message% m)
{
if (m.Msg == WM_WTSSESSION_CHANGE)
{
if (m.WParam.ToInt32() == WTS_SESSION_LOCK)
{
LogAction(L"Computer Locked");
this->timerUpdate->IntervalMultiplyFactor = 2;
}
else if (m.WParam.ToInt32() == WTS_SESSION_UNLOCK)
{
LogAction(L"Computer Unlocked");
this->timerUpdate->IntervalMultiplyFactor = 1;
requestUpdate();
}
}
...
...
}
When you change a local file, you'll want to have it uploaded to the remote SVN server – to make it accessible from any other computer of yours. Also, by checking it into the repository, you'll create a new revision (a new version of that file) in your SVN repository, which is fine. However if you are editing a text document, you probably don't wish to create and upload a new revision of that file each time you press Ctrl+S
in your favorite word processor, do you? If not, SyncBox can delay your check-ins by the amount of time you like the best. You can set a non-zero interval of “Check-ins Delay” and whenever SyncBox will detect a local file change, it will create and start a time window for that request. If another file change will happen during that time frame, then the time window will be reset and the check-in will be delayed again. However, if no further editing is made by you during that time, then all your changed files will be uploaded to the SVN repository at once when the time window expires (e.g. if there were no file changes for 15 minutes – provided that you've set a 15 minutes value for the “Check-ins Delay”). This behavior is achieved through the RequestTimeWindow
class with the following, very easy interface:
ref class RequestTimeWindow
{
public:
RequestTimeWindow(void);
property int Period;
property bool IsActive
{
bool get();
}
event System::EventHandler^ NewRequestAdded;
event System::EventHandler^ TimeWindowExpired;
void AddRequest();
void CancelAllRequests();
};
Since SyncBox's core code doesn't deal directly with the SVN repository, any other, alternative version control repository can be used by SyncBox internally. If you are interested, you can create your own ISyncWorker
implementation and hook it up easily with SyncBox's ISyncClient
internally.
SyncBox manages your files indirectly, through a 3rd-party source control client installed on your computer.
This tiny tool has been developed to be used by some of my colleagues and also by me personally, so it may seem that some functionality you would expect is still missing. If that's the case, please let me know, I'll be glad to hear what and where you think could be improved.
For example, there is some place for enhancement in handling of synchronization conflicts which must be made manually through the SVN client currently or adding/removing files to/from the repository which is a similar, non-automated task. Anyway, your feedback on any enhancements is highly appreciated.
- 27 Dec 2009: Initial revision