using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Timers; using log4net; using Nini.Config; using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Modules.ExportSerialiser; using OpenSim.Region.Environment.Modules.Terrain; using OpenSim.Region.Environment.Scenes; using PumaCode.SvnDotNet.AprSharp; using PumaCode.SvnDotNet.SubversionSharp; using Slash=System.IO.Path; namespace OpenSim.Region.Modules.SvnSerialiser { public class SvnBackupModule : IRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private bool m_enabled = false; private bool m_installBackupOnLoad = false; private List m_scenes = new List(); private IRegionSerialiser m_serialiser; private bool m_svnAutoSave = false; private SvnClient m_svnClient; private string m_svndir = "SVNmodule\\repo"; private string m_svnpass = "password"; private TimeSpan m_svnperiod = new TimeSpan(0, 0, 15, 0, 0); private string m_svnurl = "svn://insert.your.svn/here/"; private string m_svnuser = "username"; private Timer m_timer = new Timer(); #region SvnModule Core /// /// Exports a specified scene to the SVN repo directory, then commits. /// /// The scene to export public void SaveRegion(Scene scene) { List svnfilenames = CreateAndAddExport(scene); m_svnClient.Commit3(svnfilenames, true, false); m_log.Info("[SVNBACKUP]: Region backup successful (" + scene.RegionInfo.RegionName + ")."); } /// /// Saves all registered scenes to the SVN repo, then commits. /// public void SaveAllRegions() { List svnfilenames = new List(); List regions = new List(); foreach (Scene scene in m_scenes) { svnfilenames.AddRange(CreateAndAddExport(scene)); regions.Add("'" + scene.RegionInfo.RegionName + "' "); } m_svnClient.Commit3(svnfilenames, true, false); m_log.Info("[SVNBACKUP]: Server backup successful ( " + String.Concat(regions.ToArray()) + ")."); } private List CreateAndAddExport(Scene scene) { m_log.Info("[SVNBACKUP]: Saving a region to SVN with name " + scene.RegionInfo.RegionName); List filenames = m_serialiser.SerialiseRegion(scene, m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID.ToString() + "\\"); try { m_svnClient.Add3(m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID.ToString(), true, false, false); } catch (SvnException) { } List svnfilenames = new List(); foreach (string filename in filenames) svnfilenames.Add(m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID.ToString() + Slash.DirectorySeparatorChar + filename); svnfilenames.Add(m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID.ToString()); return svnfilenames; } public void LoadRegion(Scene scene) { scene.LoadPrimsFromXml2(m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID.ToString() + Slash.DirectorySeparatorChar + "objects.xml"); scene.RequestModuleInterface().LoadFromFile(m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID.ToString() + Slash.DirectorySeparatorChar + "heightmap.r32"); m_log.Info("[SVNBACKUP]: Region load successful (" + scene.RegionInfo.RegionName + ")."); } private void CheckoutSvn() { m_svnClient.Checkout2(m_svnurl, m_svndir, Svn.Revision.Head, Svn.Revision.Head, true, false); } private void CheckoutSvn(SvnRevision revision) { m_svnClient.Checkout2(m_svnurl, m_svndir, revision, revision, true, false); } private void CheckoutSvnPartial(string subdir) { if (!Directory.Exists(m_svndir + Slash.DirectorySeparatorChar + subdir)) Directory.CreateDirectory(m_svndir + Slash.DirectorySeparatorChar + subdir); m_svnClient.Checkout2(m_svnurl + "/" + subdir, m_svndir, Svn.Revision.Head, Svn.Revision.Head, true, false); } private void CheckoutSvnPartial(string subdir, SvnRevision revision) { if (!Directory.Exists(m_svndir + Slash.DirectorySeparatorChar + subdir)) Directory.CreateDirectory(m_svndir + Slash.DirectorySeparatorChar + subdir); m_svnClient.Checkout2(m_svnurl + "/" + subdir, m_svndir, revision, revision, true, false); } #endregion #region SvnDotNet Callbacks private SvnError SimpleAuth(out SvnAuthCredSimple svnCredentials, IntPtr baton, AprString realm, AprString username, bool maySave, AprPool pool) { svnCredentials = SvnAuthCredSimple.Alloc(pool); svnCredentials.Username = new AprString(m_svnuser, pool); svnCredentials.Password = new AprString(m_svnpass, pool); svnCredentials.MaySave = false; return SvnError.NoError; } private SvnError GetCommitLogCallback(out AprString logMessage, out SvnPath tmpFile, AprArray commitItems, IntPtr baton, AprPool pool) { if (!commitItems.IsNull) { foreach (SvnClientCommitItem2 item in commitItems) { m_log.Debug("[SVNBACKUP]: ... " + Path.GetFileName(item.Path.ToString()) + " (" + item.Kind.ToString() + ") r" + item.Revision.ToString()); } } string msg = "Region Backup (" + System.Environment.MachineName + " at " + DateTime.UtcNow.ToString() + " UTC)"; m_log.Debug("[SVNBACKUP]: Saved with message: " + msg); logMessage = new AprString(msg, pool); tmpFile = new SvnPath(pool); return (SvnError.NoError); } #endregion #region IRegionModule Members public void Initialise(Scene scene, IConfigSource source) { try { if (!source.Configs["SVN"].GetBoolean("Enabled", false)) return; m_enabled = true; m_svndir = source.Configs["SVN"].GetString("Directory", m_svndir); m_svnurl = source.Configs["SVN"].GetString("URL", m_svnurl); m_svnuser = source.Configs["SVN"].GetString("Username", m_svnuser); m_svnpass = source.Configs["SVN"].GetString("Password", m_svnpass); m_installBackupOnLoad = source.Configs["SVN"].GetBoolean("ImportOnStartup", m_installBackupOnLoad); m_svnAutoSave = source.Configs["SVN"].GetBoolean("Autosave", m_svnAutoSave); m_svnperiod = new TimeSpan(0, source.Configs["SVN"].GetInt("AutosavePeriod", (int) m_svnperiod.TotalMinutes), 0); } catch (Exception) { } lock (m_scenes) { m_scenes.Add(scene); } scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; } public void PostInitialise() { if (m_enabled == false) return; if (m_svnAutoSave == true) { m_timer.Interval = m_svnperiod.TotalMilliseconds; m_timer.Elapsed += new ElapsedEventHandler(m_timer_Elapsed); m_timer.AutoReset = true; m_timer.Start(); } m_log.Info("[SVNBACKUP]: Connecting to SVN server " + m_svnurl + " ..."); SetupSvnProvider(); m_log.Info("[SVNBACKUP]: Creating repository in " + m_svndir + "."); CreateSvnDirectory(); CheckoutSvn(); SetupSerialiser(); if (m_installBackupOnLoad) { m_log.Info("[SVNBACKUP]: Importing latest SVN revision to scenes..."); foreach (Scene scene in m_scenes) { LoadRegion(scene); } } } public void Close() { } public string Name { get { return "SvnBackupModule"; } } public bool IsSharedModule { get { return true; } } #endregion private void EventManager_OnPluginConsole(string[] args) { if (args[0] == "svn" && args[1] == "save") { SaveAllRegions(); } if (args.Length == 2) { if (args[0] == "svn" && args[1] == "load") { LoadAllScenes(); } } if (args.Length == 3) { if (args[0] == "svn" && args[1] == "load") { LoadAllScenes(Int32.Parse(args[2])); } } if (args.Length == 3) { if (args[0] == "svn" && args[1] == "load-region") { LoadScene(args[2]); } } if (args.Length == 4) { if (args[0] == "svn" && args[1] == "load-region") { LoadScene(args[2], Int32.Parse(args[3])); } } } public void LoadScene(string name) { CheckoutSvn(); foreach (Scene scene in m_scenes) { if (scene.RegionInfo.RegionName.ToLower().Equals(name.ToLower())) { LoadRegion(scene); return; } } m_log.Warn("[SVNBACKUP]: No region loaded - unable to find matching name."); } public void LoadScene(string name, int revision) { CheckoutSvn(new SvnRevision(revision)); foreach (Scene scene in m_scenes) { if (scene.RegionInfo.RegionName.ToLower().Equals(name.ToLower())) { LoadRegion(scene); return; } } m_log.Warn("[SVNBACKUP]: No region loaded - unable to find matching name."); } public void LoadAllScenes() { CheckoutSvn(); foreach (Scene scene in m_scenes) { LoadRegion(scene); } } public void LoadAllScenes(int revision) { CheckoutSvn(new SvnRevision(revision)); foreach (Scene scene in m_scenes) { LoadRegion(scene); } } private void m_timer_Elapsed(object sender, ElapsedEventArgs e) { SaveAllRegions(); } private void SetupSerialiser() { if (m_scenes.Count > 0) m_serialiser = m_scenes[0].RequestModuleInterface(); } private void SetupSvnProvider() { m_svnClient = new SvnClient(); m_svnClient.AddUsernameProvider(); m_svnClient.AddPromptProvider(new SvnAuthProviderObject.SimplePrompt(SimpleAuth), IntPtr.Zero, 2); m_svnClient.OpenAuth(); m_svnClient.Context.LogMsgFunc2 = new SvnDelegate(new SvnClient.GetCommitLog2(GetCommitLogCallback)); } private void CreateSvnDirectory() { if (!Directory.Exists(m_svndir)) Directory.CreateDirectory(m_svndir); } } }