if(($ACT == 'edit' || $ACT == 'preview') && $INFO['editable']){ ?> } else { ?> } ?>
A method to synchronize two DokuWiki installations.
For more elaborate concepts on this topic see dokupubsub.
The idea is simple: For each wiki-write-transaction a small DokuWiki action plugin launches rsync to publish/update the underlying data storage.
Synchronization happens in the background: a small perl script prevents multiple simultaneous rsync processes and re-runs if changes occur during an active transfer.
Note: The index of the receiving side is not updated automatically.
While rsync
is capable of bi-directionally synchronizing multiple wikis. The script below is in use on a (read/write) master to (mostly read-only) slave wiki. Use rsync's -u
option, but with care: page-locks, and edit-drafts are not distributed. - While suitable for a small group of editors, race-conditions may occur on larger public wikis.
One workaround is to make a receiving namespace read-only; optionally in combination with the include plugin to make parts locally writable content.
Alternatively one can make use of redirecting or proxying write-requests (HTTP-POSTs in general) to the central master. There can be different master servers per namespace; but depends on secure cross-site requests and authentication token passing.
Last but not least NFS-sharing the data/lock
folder may be an option. see dokupubsub.
http://dokuwiki.org/tips:farm and http://dokuwiki.org/tips:farm2 have hints about patching DokuWiki to set up master server (aka. farmer).
Configure and test the perl script first; then save this plugin as lib/plugins/rsync/action.php
and edit a page to test it. check /tmp/rwikisync.log
.
<?php /** * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Robin Gareus <robin@gareus.org> */ // must be run within Dokuwiki if(!defined('DOKU_INC')) die(); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once (DOKU_PLUGIN.'action.php'); class action_plugin_rsync extends DokuWiki_Action_Plugin { function getInfo(){ return array( 'author' => 'Robin Gareus', 'email' => 'robin@gareus.org', 'date' => '2007-05-23', 'name' => 'rsync plugin', 'desc' => 'rsync dokuwiki data', 'url' => '', ); } function register($contr){ $contr->register_hook('IO_WIKIPAGE_WRITE', 'AFTER', $this, 'handle_wikipage_write', array()); } function handle_wikipage_write($event, $param) { // if an old revision is saved or the file is empty -> run away if ( $event->data[3] || !$event->data[0][1] ) return false; //$ns=$event->data[1]; //$path=$event->data[0][0]; system ("/usr/local/bin/dokusync.pl &>/tmp/rwikisync.log &"); return true; } }
The Perl script to rsync the actual data. Save as /usr/local/bin/dokusync.pl
or change the path in the above plugin code accordingly.
You need to change username
and provide a ssh-key (just generate one with ssh-keygen
). There's many tutorials on ssh keys and rsync.
#!/usr/bin/perl ### CONFIG $rsyncopts="-azv --delete --no-o --no-g --chmod=Dg+wx,ug+rw"; $myssh="ssh -i /var/opt/id_rsa -l username"; @excludelist = ( "_darcs", "cache/", "attic/", "private/", "index/" ); $src="/var/www/data/"; $dstpath="/site/docroot/data/"; $dsthost="example.org"; $dst=$dsthost.":".$dstpath; ###prevent multiple instances use File::Pid; $pidfile = File::Pid->new({ file => "/var/lock/rwikisync.pid"}); if ( my $num = $pidfile->running ) { # touch restart-file system("touch /var/lock/rsyncrestart"); die "Already running: $num - restart scheduled\n"; } $pidfile->write; ### build commandline $command="rsync $rsyncopts -e \"$myssh\" "; foreach (@excludelist) { $command.=" --exclude '$_'"; } $command.=" $src $dst"; ### and execute it.. system("date"); system($command); ### fix group permissions system("$myssh $dsthost \"chgrp -R www-data $dstpath 2>/dev/null\""); # check if restart was attempted -> rm restart file and rsync again.. while ( -e "/var/lock/rsyncrestart" ) { unlink "/var/lock/rsyncrestart"; system($command); } $pidfile->remove;