Files
Discord.Net/test/Discord.Net.Tests/Net/FilesystemProvider.cs
2017-01-24 11:55:41 -04:00

124 lines
4.2 KiB
C#

using Akavache;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reflection;
namespace Discord
{
public class FilesystemProvider : IFilesystemProvider
{
public IObservable<Stream> OpenFileForReadAsync(string path, IScheduler scheduler)
{
return SafeOpenFileAsync(path, FileMode.Open, FileAccess.Read, FileShare.Read, scheduler);
}
public IObservable<Stream> OpenFileForWriteAsync(string path, IScheduler scheduler)
{
return SafeOpenFileAsync(path, FileMode.Create, FileAccess.Write, FileShare.None, scheduler);
}
public IObservable<Unit> CreateRecursive(string path)
{
CreateRecursive(new DirectoryInfo(path));
return Observable.Return(Unit.Default);
}
public IObservable<Unit> Delete(string path)
{
return Observable.Start(() => File.Delete(path), Scheduler.Default);
}
public string GetDefaultRoamingCacheDirectory()
{
throw new NotSupportedException();
}
public string GetDefaultSecretCacheDirectory()
{
throw new NotSupportedException();
}
public string GetDefaultLocalMachineCacheDirectory()
{
throw new NotSupportedException();
}
protected static string GetAssemblyDirectoryName()
{
var assemblyDirectoryName = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
Debug.Assert(assemblyDirectoryName != null, "The directory name of the assembly location is null");
return assemblyDirectoryName;
}
private static IObservable<Stream> SafeOpenFileAsync(string path, FileMode mode, FileAccess access, FileShare share, IScheduler scheduler = null)
{
scheduler = scheduler ?? Scheduler.Default;
var ret = new AsyncSubject<Stream>();
Observable.Start(() =>
{
try
{
var createModes = new[]
{
FileMode.Create,
FileMode.CreateNew,
FileMode.OpenOrCreate,
};
// NB: We do this (even though it's incorrect!) because
// throwing lots of 1st chance exceptions makes debugging
// obnoxious, as well as a bug in VS where it detects
// exceptions caught by Observable.Start as Unhandled.
if (!createModes.Contains(mode) && !File.Exists(path))
{
ret.OnError(new FileNotFoundException());
return;
}
Observable.Start(() => new FileStream(path, mode, access, share, 4096, false), scheduler).Cast<Stream>().Subscribe(ret);
}
catch (Exception ex)
{
ret.OnError(ex);
}
}, scheduler);
return ret;
}
private static void CreateRecursive(DirectoryInfo info)
{
SplitFullPath(info).Aggregate((parent, dir) =>
{
var path = Path.Combine(parent, dir);
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
return path;
});
}
private static IEnumerable<string> SplitFullPath(DirectoryInfo info)
{
var root = Path.GetPathRoot(info.FullName);
var components = new List<string>();
for (var path = info.FullName; path != root && path != null; path = Path.GetDirectoryName(path))
{
var filename = Path.GetFileName(path);
if (String.IsNullOrEmpty(filename))
continue;
components.Add(filename);
}
components.Add(root);
components.Reverse();
return components;
}
}
}