Пре­жде всего, хо­чу за­ме­тить, что дан­ная ста­тья не пре­тен­ду­ет ни на уни­каль­ность, ни на тех­но­ло­ги­че­ские ин­но­ва­ции тем бо­лее - ис­поль­зо­вать мы бу­дем все го­то­вое. Про­сто в ка­кой-то мо­мент мне ста­ла ин­терес­на те­ма со­зда­ния сво­е­го соб­ствен­но­го ана­ло­га Dropbox-а, поэто­му я ре­шил по­де­лить­ся с ва­ми ре­зульта­том, ко­то­рый мож­но ис­поль­зо­вать ис­клю­чи­тель­но для те­стов или даль­ней­ших раз­ра­бо­ток. Ни я, ни со­зда­те­ли unison ни­че­го вам га­ран­ти­ро­вать не мо­жем, но об этом чуть ни­же. Кто не в кур­се, Dropbox - ве­ли­ко­леп­ней­ший стар­тап из всех ны­не су­ще­ству­ю­щих, поз­во­ля­ет син­хро­ни­зи­ро­вать свои файлы с уда­лен­ным хра­ни­ли­щем в об­ла­ках Amazon S3. Аб­со­лют­но бес­плат­но мож­но по­лу­чить 2GB, а если за­реги­стри­ро­вать­ся по мо­ей ре­фе­раль­ной ссыл­ке, то нам обо­им еще на­ки­нет по 250MB. Вро­де и ме­лочь, а при­ят­но. Ре­кла­ма рекла­мой, но да­вайте перейдем к тех­ни­че­ско­му опи­са­нию.

Де­лать свой ал­го­ритм для diff с по­сле­ду­ю­щим push-pull из­ме­не­ний мы не бу­дем - это слож­но и бес­пер­спек­тив­но, а возь­мем мы го­то­вое ре­ше­ние для син­хро­ни­за­ции ло­каль­ной и уда­лен­ной ди­рек­то­рии под на­зва­ни­ем Unison. Очень, кста­ти, не­пло­хое ре­ше­ние, кро­сплат­фор­мен­ное, со­бра­но под windows, linux и macos, про­стое в на­строй­ке и до­ста­точ­но бы­строе. Есть, прав­да, и свои недо­стат­ки, при пере­имено­ва­нии файла в local folder идет уда­ле­ние его на remote ди­рек­то­рии с по­сле­ду­ю­щей пе­реза­лив­кой, воз­мож­но, это как-то ле­чит­ся на­строй­ка­ми, при по­верх­ност­ном про­чте­нии я подоб­ной ин­фор­ма­ции не на­шел. Unison тре­бу­ет на­личие би­нар­ни­ка на кли­ен­те-сер­ве­ре (важ­ный мо­мент, вер­сии обя­за­тель­но долж­ны сов­па­дать) и мо­жет ра­бо­тать в ви­де со­кет-де­мо­на (не под­хо­дит нам из со­об­ра­же­ний без­опас­но­сти, от­сут­ству­ет аутен­ти­фи­ка­ция), по­верх rsync или ssh. Мы бу­дем ис­поль­зо­вать по­след­ний ва­ри­ант для удоб­ства огра­ни­че­ния до­сту­па, от­сут­ствия проблем с пра­ва­ми до­сту­па, без­опас­ной пере­да­чи и ку­чи дру­гих пре­иму­ществ, ко­то­рые да­ет нам secure shell protocol. Сле­ду­ю­щая труд­ность со­сто­ит в том, что usinon тре­бу­ет би­нар­ник openssh кли­ен­та для сво­ей ра­бо­ты, а мы в на­сто­я­щий мо­мент пи­шем кли­ент для windows, не за­бы­вайте. Ра­зу­ме­ет­ся, ни­что не ме­ша­ет взять cygwin скомпи­ли­ро­ван­ную вер­сию, но она у ме­ня как-то кри­во ра­бо­та­ла, не под­дер­жи­ва­ла ин­тер­ак­тив­ную ав­то­ри­за­цию ло­ги­ном и па­ро­лем, и не да­ва­ла ло­ги­нить­ся че­рез rsa_key, расска­зы­вая про insecure file permission, тре­буя chmod-ить его в 0600, а как, про­сти­те, я это в ок­нах сде­лаю? Бла­го, су­ще­ству­ет на­тив­ная CLI вер­сия PuTTY SSH Client под на­зва­ни­ем Plink.exe, ко­то­рую мы и бу­дем ис­поль­зо­вать. Пря­мое пере­имено­ва­ние plink.exe в ssh.exe ра­бо­тать не бу­дет, plink не под­дер­жи­ва­ет не­ко­то­рые атри­бу­ты и от­ва­ли­ва­ет­ся с ошиб­кой. В ин­тер­не­те бы­ла найде­на оберт­ка, ко­то­рая ис­прав­ляет дан­ный недо­ста­ток. Это обыч­ный bat файл, его со­дер­жа­ние мож­но по­смот­реть. Все, те­перь ни­че­го не ме­ша­ет вам ис­поль­зо­вать дву­сто­роннюю син­хро­ни­за­цию с по­мо­щью ко­манды unison.exe C:\local\path\ ssh://host.com/remote/path/ -batch -sshcmd ssh2plink.bat -sshargs "-pw mysshpass -l mysshlogin". Если вы пере­жи­ва­е­те за без­опас­ность, то мож­но на­строить и passwordless ав­то­ри­за­цию. Для это ге­не­ри­руй­те ключ на сер­ве­ре, кон­вер­ти­руй­те его в ppk фор­мат, ко­то­рый ис­поль­зу­ет PuTTY, c по­мо­щью PuTTYgen и го­во­ри­те Plink-у ис­поль­зо­вать этот файл че­рез -sshargs "-i pathtomykey.ppk -l mysshlogin".

На этом ка­за­лось бы мож­но бы­ло за­кон­чить, но мы же хо­тим ана­лог дропбок­са, весь кайф ко­то­ро­го за­клю­ча­ет­ся в immediate synchronization: откры­ли файл, от­ре­дак­ти­ро­ва­ли его, сохра­ни­ли и он сра­зу же про­толк­нул­ся на сер­вер. Вот тут нам не обой­тись уже без кли­ен­та, пи­сать его мы бу­дем на Microsoft Visual C# Express. По­че­му? Да про­сто мне так удоб­но, к то­му же в нем по умол­ча­нию есть все необ­хо­ди­мые нам инстру­мен­ты. Ос­нов­ные клас­сы, ко­то­рые мы бу­дем ис­поль­зо­вать: System.Diagnostics.Process для ра­бо­ты с unison.exe и его StandardOutput (ко­то­рый по­че­му-то у ме­ня отда­вал­ся в StandardError, не­смот­ря на 0 ExitCode про­цес­са), System.IO.FileSystemWatcher для от­сле­жи­ва­ния из­ме­не­ний в ди­рек­то­рии и System.ComponentModel.BackgroundWorker для ра­бо­ты в фо­не. На­бро­сан­ный на ско­рую ру­ку код вы­гля­дит сле­ду­ю­щим об­разом. Ну или вот весь проект для сбор­ки. А вот го­то­вый би­нар­ник. По­вто­рюсь, все это де­ла­лось на ско­рую ру­ку, но мо­жет стать ба­зой для нор­маль­но­го проек­та, если вам это так ин­терес­но. Да, кста­ти, usinon под­дер­жи­ва­ет мульти­кли­ент­ную син­хро­ни­за­цию с то­по­ло­ги­ей ви­да звез­да, так что, если до­ба­вить таймер для син­хро­ни­за­ции, то тут вам и воз­мож­ность ра­бо­тать це­лым кодлом над од­ним файлом, прав­да я подоб­ное не те­сти­ро­вал.

Та­ким об­разом, для на­строй­ки сво­е­го сер­ве­ра син­хро­ни­за­ции вам ну­жен уда­лен­ный linux\freebsd сер­вер с ру­том или хо­тя бы воз­мож­но­стью со­би­рать би­нар­ни­ки, оди­на­ковые вер­сии unison на обо­их кон­цах (до­ста­точ­но x.xx.000, вер­сия бил­да 000 ни­как не влия­ет на сов­ме­сти­мость), оберт­ка для от­сле­жи­ва­ния из­ме­не­ний и вы по­лу­ча­е­те свой ана­лог Dropbox. Я по­вто­рюсь, ана­лог, ко­то­рый вы­пол­ня­ет лишь 50% функ­ций ори­ги­на­ла, но тем не ме­нее мо­жет стать за­ме­ной лю­дям, ко­то­рые не до­ве­ря­ют свои файли­ки ни­ко­му, а весь /home у них монти­ру­ет­ся в EncFS.