ln.http.resources/DirectoryResource.cs

264 lines
7.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ln.templates;
using System.Collections;
using ln.types;
namespace ln.http.resources
{
public delegate Resource ResourceTypeHookDelegate(DirectoryResource directoryResource, FileInfo fileInfo);
public class DirectoryResource : Resource, TemplateProvider
{
public ResourceTypeHookDelegate ResourceTypeHook { get; set; }
protected Dictionary<string, Resource> cache = new Dictionary<string, Resource>();
protected Dictionary<string, Resource> injectedResources = new Dictionary<string, Resource>();
IEnumerable<string> searchPaths;
public DirectoryResource(IEnumerable<string> search)
: base("")
{
searchPaths = search;
}
public DirectoryResource(Resource container,IEnumerable<string> search)
: base(container, System.IO.Path.GetFileName(search.First()))
{
searchPaths = search;
}
public DirectoryResource(String path)
: base("")
{
searchPaths = new string[] { path };
}
public DirectoryResource(String path,string name)
: base(name)
{
searchPaths = new string[] { path };
}
public DirectoryResource(Resource container, String path)
: base(container, System.IO.Path.GetFileName(path))
{
searchPaths = new string[] { path };
if (container is DirectoryResource)
{
DirectoryResource parent = container as DirectoryResource;
ResourceTypeHook = parent.ResourceTypeHook;
}
}
public override bool Contains(string name)
{
if (injectedResources.ContainsKey(name))
return true;
String cPath = PathHelper.FindPath(searchPaths.Select((p) => System.IO.Path.Combine(p, name)));
lock (cache)
{
if ((cPath == null) && cache.ContainsKey(name))
cache.Remove(name);
}
return (cPath != null);
}
public override void AddResource(Resource resource)
{
lock (cache)
{
cache.Add(resource.Name, resource);
}
}
public override void RemoveResource(Resource resource)
{
lock (cache)
{
if (cache.ContainsValue(resource))
cache.Remove(resource.Name);
}
}
public void InjectResource(Resource resource)
{
injectedResources.Add(resource.Name, resource);
}
public override Resource GetResource(string name)
{
lock (cache)
{
if (!Contains(name))
return null;
if (injectedResources.ContainsKey(name))
return injectedResources[name];
if (cache.ContainsKey(name))
return cache[name];
String cPath = PathHelper.FindPath(searchPaths.Select((p) => System.IO.Path.Combine(p, name)));
if (cPath == null)
return null;
if (Directory.Exists(cPath))
{
DirectoryResource child = new DirectoryResource(this, searchPaths.Select((p) => System.IO.Path.Combine(p, name)));
child.ResourceTypeHook = ResourceTypeHook;
return child;
}
else if (File.Exists(cPath))
{
FileInfo fileInfo = new FileInfo(cPath);
Resource resource = null;
if (ResourceTypeHook != null)
{
resource = ResourceTypeHook(this, fileInfo);
}
if (resource == null)
{
resource = new FileResource(this, fileInfo);
}
return resource;
}
}
return GetFallBackResource();
}
public override IEnumerable<Resource> GetResources()
{
return searchPaths.SelectMany((p) => new DirectoryInfo(p).EnumerateFileSystemInfos().Select((x) => GetResource(x.Name))).Distinct();
}
public override HttpResponse GetResponse(HttpRequest httpRequest)
{
if (DefaultResource != null)
return httpRequest.Redirect(String.Join("/", DefaultResource.Path));
Resource fallback = GetFallBackResource();
if (fallback != null)
{
return fallback.GetResponse(httpRequest);
}
else
{
throw new NotImplementedException();
}
}
public Template FindTemplate(string templatePath)
{
if ((templatePath[0] == '/') && (Container is DirectoryResource))
{
return RootDirectoryResource.FindTemplate(templatePath);
}
Resource current = this;
Queue<String> path = new Queue<string>(templatePath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries));
while (path.Count > 0)
{
current = current.GetResource(path.Dequeue());
}
if (current is TemplateResource)
{
return (current as TemplateResource).Template;
}
if (Container is TemplateProvider)
{
return (Container as TemplateProvider).FindTemplate(templatePath);
}
return null;
}
public DirectoryResource RootDirectoryResource
{
get
{
if (Container is DirectoryResource)
{
DirectoryResource parent = Container as DirectoryResource;
return parent.RootDirectoryResource;
}
return this;
}
}
}
public class FileResource : DirectoryResource
{
DirectoryResource DirectoryResource { get; }
public FileInfo FileInfo { get; }
public FileResource(DirectoryResource directoryResource,FileInfo fileInfo)
:base(directoryResource,fileInfo.Name)
{
DirectoryResource = directoryResource;
FileInfo = fileInfo;
}
public override bool Contains(string name)
{
return false;
}
public override void AddResource(Resource resource)
{
throw new NotImplementedException();
}
public override void RemoveResource(Resource resource)
{
throw new NotImplementedException();
}
public override IEnumerable<Resource> GetResources()
{
return new Resource[0];
}
public override HttpResponse GetResponse(HttpRequest httpRequest)
{
if (!httpRequest.Method.Equals("GET"))
throw new NotImplementedException(String.Format("Method {0} is not supported by this resource", httpRequest.Method));
HttpResponse response = new HttpResponse(httpRequest, FileInfo.OpenRead());
response.SetHeader("content-type", GuessContentType());
return response;
}
public string GuessContentType()
{
String ext = FileInfo.Extension;
switch (ext)
{
case ".html":
return "text/html";
case ".txt":
return "text/plain";
case ".css":
return "text/css";
case ".js":
return "text/javascript";
default:
return "application/octet-stream";
}
}
}
}