using System; using System.IO; using System.Collections.Generic; using System.Threading.Tasks; using System.Diagnostics; using SharpCompress.Readers; namespace Nibriboard.RippleSpace { public class RippleSpaceManager { /// /// The temporary directory in which we are currently storing our unpacked planes temporarily. /// public string UnpackedDirectory; /// /// The master list of planes that this PlaneManager is in charge of. /// public List Planes = new List(); /// /// The number of milliseconds between each maintenance run. /// public readonly int MaintenanceInternal = 5000; /// /// The number of milliseconds the last maintenance run took. /// public long LastMaintenanceDuration = 0; public int DefaultChunkSize { get; set; } = 512; public RippleSpaceManager() { // Create a temporary directory in which to store our unpacked planes UnpackedDirectory = Path.GetTempFileName(); File.Delete(UnpackedDirectory); UnpackedDirectory += "/"; Directory.CreateDirectory(UnpackedDirectory); Log.WriteLine("[RippleSpace] New blank ripplespace initialised."); } /// /// Gets the plane with the specified name from this RippleSpace. /// /// The plane name to retrieve. public Plane this[string planeName] { get { return GetById(planeName); } } /// /// Gets the plane with the specified name from this RippleSpace. /// /// The plane name to retrieve. /// The plane wwith the specified name. protected Plane GetById(string targetName) { foreach (Plane plane in Planes) { if (plane.Name == targetName) return plane; } return null; } /// /// Creates a new plane, adds it to this RippleSpaceManager, and then returns it. /// /// The name of the new plane to create. /// The newly created plane. public Plane CreatePlane(string newPlaneName) { if(this[newPlaneName] != null) throw new InvalidOperationException($"Error: A plane with the name '{newPlaneName}' already exists in this RippleSpaceManager."); Log.WriteLine("[RippleSpace] Creating plane {0}", newPlaneName); Plane newPlane = new Plane(newPlaneName, DefaultChunkSize); Planes.Add(newPlane); return newPlane; } public async Task StartMaintenanceMonkey() { Log.WriteLine("[RippleSpace/Maintenance] Automated maintenance monkey created."); while (true) { Stopwatch maintenanceStopwatch = Stopwatch.StartNew(); foreach (Plane plane in Planes) plane.PerformMaintenance(); LastMaintenanceDuration = maintenanceStopwatch.ElapsedMilliseconds; await Task.Delay(MaintenanceInternal); } } public async Task FromFile(string filename) { if(!File.Exists(filename)) throw new FileNotFoundException($"Error: Couldn't find the packed ripplespace at {filename}"); RippleSpaceManager rippleSpace = new RippleSpaceManager(); using(Stream packedRippleSpaceStream = File.OpenRead(filename)) using(IReader rippleSpaceUnpacker = ReaderFactory.Open(packedRippleSpaceStream)) { Log.WriteLine($"[Core] Unpacking ripplespace packed with {rippleSpaceUnpacker.ArchiveType} from {filename}."); rippleSpaceUnpacker.WriteAllToDirectory(UnpackedDirectory); } Log.WriteLine("[Core] done!"); if(!File.Exists(rippleSpace.UnpackedDirectory + "index.list")) throw new InvalidDataException($"Error: The packed ripplespace at {filename} doesn't appear to contain an index file."); Log.WriteLine("[Core] Importing planes"); StreamReader planes = new StreamReader(rippleSpace.UnpackedDirectory + "index.list"); List planeReaders = new List(); string nextPlane; while((nextPlane = await planes.ReadLineAsync()) != null) { planeReaders.Add(Plane.FromFile(rippleSpace.UnpackedDirectory + nextPlane)); } await Task.WhenAll(planeReaders); Log.WriteLine("[Core] done!"); return rippleSpace; } } }