Skip to content

Commit 5b4b52a

Browse files
committed
Merge pull request #69 from mandrek44/react.owin
React.Owin
2 parents a02eeb4 + 57970a7 commit 5b4b52a

21 files changed

+1007
-3
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (c) 2014-2015, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
using React.TinyIoC;
11+
12+
namespace React.Owin
13+
{
14+
/// <summary>
15+
/// Handles registration of ReactJS.NET components that are only applicable
16+
/// when used with Owin.
17+
/// </summary>
18+
public class AssemblyRegistration : IAssemblyRegistration
19+
{
20+
/// <summary>
21+
/// Registers components in the React IoC container
22+
/// </summary>
23+
/// <param name="container">Container to register components in</param>
24+
public void Register(TinyIoCContainer container)
25+
{
26+
container.Register<IFileSystem, EntryAssemblyFileSystem>();
27+
container.Register<ICache, MemoryFileCache>();
28+
}
29+
}
30+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2014-2015, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
using System.IO;
11+
using System.Reflection;
12+
13+
namespace React.Owin
14+
{
15+
/// <summary>
16+
/// Implements React file system that maps "~" into entry assembly location.
17+
/// </summary>
18+
internal class EntryAssemblyFileSystem : FileSystemBase
19+
{
20+
public override string MapPath(string relativePath)
21+
{
22+
if (relativePath.StartsWith("~"))
23+
return Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), relativePath.Replace("~", string.Empty));
24+
25+
return relativePath;
26+
}
27+
}
28+
}

src/React.Owin/JsxFileExtensions.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) 2014-2015, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
using Owin;
11+
12+
namespace React.Owin
13+
{
14+
/// <summary>
15+
/// Extensions for JsxFileMiddleware.
16+
/// </summary>
17+
public static class JsxFileExtensions
18+
{
19+
/// <summary>
20+
/// Enables serving static JSX file, compiled to JavaScript with the given options.
21+
/// </summary>
22+
public static IAppBuilder UseJsxFiles(this IAppBuilder builder, JsxFileOptions options = null)
23+
{
24+
return builder.Use<JsxFileMiddleware>(options ?? new JsxFileOptions());
25+
}
26+
}
27+
}

src/React.Owin/JsxFileMiddleware.cs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2014-2015, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
using System;
11+
using System.Collections.Generic;
12+
using System.Linq;
13+
using System.Threading.Tasks;
14+
15+
using Microsoft.Owin.StaticFiles;
16+
17+
namespace React.Owin
18+
{
19+
/// <summary>
20+
/// Enables serving static JSX files transformed to pure JavaScript. Wraps around StaticFileMiddleware.
21+
/// </summary>
22+
public class JsxFileMiddleware
23+
{
24+
private readonly Func<IDictionary<string, object>, Task> _next;
25+
private readonly StaticFileOptions _fileOptions;
26+
private readonly IEnumerable<string> _extensions;
27+
28+
static JsxFileMiddleware()
29+
{
30+
// Assume that request will ask for the "per request" instances only once.
31+
Initializer.Initialize(options => options.AsMultiInstance());
32+
}
33+
34+
/// <summary>
35+
/// Creates a new instance of the JsxFileMiddleware.
36+
/// </summary>
37+
/// <param name="next">The next middleware in the pipeline.</param>
38+
/// <param name="options">The configuration options.</param>
39+
public JsxFileMiddleware(Func<IDictionary<string, object>, Task> next, JsxFileOptions options)
40+
{
41+
if (next == null)
42+
throw new ArgumentNullException("next");
43+
44+
_next = next;
45+
46+
// Default values
47+
options = options ?? new JsxFileOptions();
48+
_extensions = (options.Extensions == null || !options.Extensions.Any()) ? new[] { ".jsx", ".js" } : options.Extensions;
49+
_fileOptions = options.StaticFileOptions ?? new StaticFileOptions();
50+
}
51+
52+
/// <summary>
53+
/// Processes a request to determine if it matches a known JSX file, and if so, serves it compiled to JavaScript.
54+
/// </summary>
55+
/// <param name="environment">OWIN environment dictionary which stores state information about the request, response and relevant server state.</param>
56+
/// <returns/>
57+
public async Task Invoke(IDictionary<string, object> environment)
58+
{
59+
// Create all "per request" instances
60+
var reactEnvironment = React.AssemblyRegistration.Container.Resolve<IReactEnvironment>();
61+
62+
var internalStaticMiddleware = CreateFileMiddleware(reactEnvironment.JsxTransformer);
63+
await internalStaticMiddleware.Invoke(environment);
64+
65+
// Clean up all "per request" instances
66+
var disposable = reactEnvironment as IDisposable;
67+
if (disposable != null)
68+
disposable.Dispose();
69+
}
70+
71+
private StaticFileMiddleware CreateFileMiddleware(IJsxTransformer jsxTransformer)
72+
{
73+
return new StaticFileMiddleware(
74+
_next,
75+
new StaticFileOptions()
76+
{
77+
ContentTypeProvider = _fileOptions.ContentTypeProvider,
78+
DefaultContentType = _fileOptions.DefaultContentType,
79+
OnPrepareResponse = _fileOptions.OnPrepareResponse,
80+
RequestPath = _fileOptions.RequestPath,
81+
ServeUnknownFileTypes = _fileOptions.ServeUnknownFileTypes,
82+
FileSystem = new JsxFileSystem(jsxTransformer, _fileOptions.FileSystem, _extensions)
83+
});
84+
}
85+
}
86+
}

src/React.Owin/JsxFileOptions.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright (c) 2014-2015, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
using System.Collections.Generic;
11+
12+
using Microsoft.Owin.StaticFiles;
13+
14+
namespace React.Owin
15+
{
16+
/// <summary>
17+
/// Options for serving JSX files.
18+
/// </summary>
19+
public class JsxFileOptions
20+
{
21+
/// <summary>
22+
/// Collection of extensions that will be treated as JSX files. Defaults to ".jsx" and ".js".
23+
/// </summary>
24+
public IEnumerable<string> Extensions { get; set; }
25+
26+
/// <summary>
27+
/// Options for static file middleware used to server JSX files.
28+
/// </summary>
29+
public StaticFileOptions StaticFileOptions { get; set; }
30+
}
31+
}

src/React.Owin/JsxFileSystem.cs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright (c) 2014-2015, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
using System;
11+
using System.Collections.Generic;
12+
using System.IO;
13+
using System.Linq;
14+
using System.Text;
15+
16+
using Microsoft.Owin.FileSystems;
17+
18+
namespace React.Owin
19+
{
20+
/// <summary>
21+
/// Owin file system that serves transformed JSX files.
22+
/// </summary>
23+
public class JsxFileSystem : Microsoft.Owin.FileSystems.IFileSystem
24+
{
25+
private readonly IJsxTransformer _transformer;
26+
private readonly Microsoft.Owin.FileSystems.IFileSystem _physicalFileSystem;
27+
private readonly string[] _extensions;
28+
29+
/// <summary>
30+
/// Creates a new instance of the JsxFileSystem.
31+
/// </summary>
32+
/// <param name="transformer">JSX transformer used to compile JSX files</param>
33+
/// <param name="root">The root directory</param>
34+
/// <param name="extensions">Extensions of files that will be treated as JSX files</param>
35+
public JsxFileSystem(IJsxTransformer transformer, string root, IEnumerable<string> extensions)
36+
: this(transformer, new PhysicalFileSystem(root), extensions)
37+
{
38+
}
39+
40+
/// <summary>
41+
/// Creates a new instance of the JsxFileSystem.
42+
/// </summary>
43+
/// <param name="transformer">JSX transformer used to compile JSX files</param>
44+
/// <param name="fileSystem">File system used to look up files</param>
45+
/// <param name="extensions">Extensions of files that will be treated as JSX files</param>
46+
public JsxFileSystem(IJsxTransformer transformer, Microsoft.Owin.FileSystems.IFileSystem fileSystem, IEnumerable<string> extensions)
47+
{
48+
_transformer = transformer;
49+
_physicalFileSystem = fileSystem;
50+
51+
// Make sure the extensions start with dot
52+
_extensions = extensions.Select(extension => extension.StartsWith(".") ? extension : "." + extension).ToArray();
53+
}
54+
55+
/// <summary>
56+
/// Locate a JSX file at the given path.
57+
/// </summary>
58+
/// <param name="subpath">The path that identifies the file</param>
59+
/// <param name="fileInfo">The discovered file if any</param>
60+
/// <returns>
61+
/// True if a JSX file was located at the given path
62+
/// </returns>
63+
public bool TryGetFileInfo(string subpath, out IFileInfo fileInfo)
64+
{
65+
IFileInfo internalFileInfo;
66+
fileInfo = null;
67+
68+
if (!_physicalFileSystem.TryGetFileInfo(subpath, out internalFileInfo))
69+
return false;
70+
71+
if (internalFileInfo.IsDirectory || !_extensions.Any(internalFileInfo.Name.EndsWith))
72+
return false;
73+
74+
fileInfo = new JsxFileInfo(_transformer, internalFileInfo);
75+
return true;
76+
}
77+
78+
/// <summary>
79+
/// Enumerate a directory at the given path, if any
80+
/// </summary>
81+
/// <param name="subpath">The path that identifies the directory</param>
82+
/// <param name="contents">The contents if any</param>
83+
/// <returns>
84+
/// True if a directory was located at the given path
85+
/// </returns>
86+
public bool TryGetDirectoryContents(string subpath, out IEnumerable<IFileInfo> contents)
87+
{
88+
return _physicalFileSystem.TryGetDirectoryContents(subpath, out contents);
89+
}
90+
91+
private class JsxFileInfo : IFileInfo
92+
{
93+
private readonly IJsxTransformer _jsxTransformer;
94+
private readonly IFileInfo _fileInfo;
95+
private readonly Lazy<byte[]> _content;
96+
97+
public JsxFileInfo(IJsxTransformer jsxTransformer, IFileInfo fileInfo)
98+
{
99+
_jsxTransformer = jsxTransformer;
100+
_fileInfo = fileInfo;
101+
102+
_content = new Lazy<byte[]>(
103+
() =>
104+
{
105+
return Encoding.UTF8.GetBytes(_jsxTransformer.TransformJsxFile(fileInfo.PhysicalPath));
106+
});
107+
}
108+
109+
public Stream CreateReadStream()
110+
{
111+
return new MemoryStream(_content.Value);
112+
}
113+
114+
public long Length
115+
{
116+
get { return _content.Value.Length; }
117+
}
118+
119+
public string PhysicalPath
120+
{
121+
get { return _fileInfo.PhysicalPath; }
122+
}
123+
124+
public string Name
125+
{
126+
get { return _fileInfo.Name; }
127+
}
128+
129+
public DateTime LastModified
130+
{
131+
get { return _fileInfo.LastModified; }
132+
}
133+
134+
public bool IsDirectory
135+
{
136+
get { return _fileInfo.IsDirectory; }
137+
}
138+
}
139+
}
140+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
using System.Reflection;
2+
using System.Runtime.InteropServices;
3+
4+
[assembly: AssemblyTitle("React.Owin")]
5+
[assembly: AssemblyDescription("Owin integration for ReactJS.NET")]
6+
[assembly: ComVisible(false)]
7+
[assembly: Guid("7f0500f5-5a9f-48c9-b136-41cfd1787724")]

0 commit comments

Comments
 (0)