Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit 5aac98033a2754e758b3f20b3a629282d18deec5 @cburgdorf committed Mar 6, 2012
Showing with 26,073 additions and 0 deletions.
  1. +22 −0 .gitignore
  2. BIN SignalR.Reactive/Libraries/SignalR.Hosting.AspNet.dll
  3. BIN SignalR.Reactive/Libraries/SignalR.Hosting.AspNet.pdb
  4. BIN SignalR.Reactive/Libraries/SignalR.dll
  5. BIN SignalR.Reactive/Libraries/SignalR.pdb
  6. +20 −0 SignalR.Reactive/SignalR.Reactive.sln
  7. +62 −0 SignalR.Reactive/SignalR.Reactive/Clientside.cs
  8. +20 −0 SignalR.Reactive/SignalR.Reactive/DependencyResolverExtensions.cs
  9. +36 −0 SignalR.Reactive/SignalR.Reactive/Properties/AssemblyInfo.cs
  10. +211 −0 SignalR.Reactive/SignalR.Reactive/RxJsProxyGenerator.cs
  11. +69 −0 SignalR.Reactive/SignalR.Reactive/SignalR.Reactive.csproj
  12. +4 −0 SignalR.Reactive/SignalR.Reactive/packages.config
  13. BIN SignalR.Reactive/packages/Rx-Main.1.0.11226/Rx-Main.1.0.11226.nupkg
  14. +4,761 −0 SignalR.Reactive/packages/Rx-Main.1.0.11226/lib/Net35/System.Reactive.XML
  15. BIN SignalR.Reactive/packages/Rx-Main.1.0.11226/lib/Net35/System.Reactive.dll
  16. +5,401 −0 SignalR.Reactive/packages/Rx-Main.1.0.11226/lib/Net4/System.Reactive.XML
  17. BIN SignalR.Reactive/packages/Rx-Main.1.0.11226/lib/Net4/System.Reactive.dll
  18. +4,731 −0 SignalR.Reactive/packages/Rx-Main.1.0.11226/lib/SL3-WP/System.Reactive.XML
  19. BIN SignalR.Reactive/packages/Rx-Main.1.0.11226/lib/SL3-WP/System.Reactive.dll
  20. +5,301 −0 SignalR.Reactive/packages/Rx-Main.1.0.11226/lib/SL4/System.Reactive.XML
  21. BIN SignalR.Reactive/packages/Rx-Main.1.0.11226/lib/SL4/System.Reactive.dll
  22. +5,431 −0 SignalR.Reactive/packages/Rx-Main.1.0.11226/lib/SL5/System.Reactive.XML
  23. BIN SignalR.Reactive/packages/Rx-Main.1.0.11226/lib/SL5/System.Reactive.dll
  24. +4 −0 SignalR.Reactive/packages/repositories.config
@@ -0,0 +1,22 @@
+[Oo]bj/
+[Bb]in/
+*.user
+/TestResults
+*.vspscc
+*.vssscc
+deploy
+deploy/*
+*.suo
+*.cache
+*.docstates
+_ReSharper.*
+*.csproj.user
+*[Rr]e[Ss]harper.user
+_ReSharper.*/
+packages/*
+artifacts/*
+msbuild.log
+PublishProfiles/
+*.psess
+*.vsp
+*.csv
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalR.Reactive", "SignalR.Reactive\SignalR.Reactive.csproj", "{2F4D1483-3A2E-4983-8EA4-75243C6759E4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2F4D1483-3A2E-4983-8EA4-75243C6759E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2F4D1483-3A2E-4983-8EA4-75243C6759E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2F4D1483-3A2E-4983-8EA4-75243C6759E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2F4D1483-3A2E-4983-8EA4-75243C6759E4}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
@@ -0,0 +1,62 @@
+using System;
+using System.Linq.Expressions;
+using SignalR.Hosting.AspNet;
+using SignalR.Hubs;
+using SignalR.Infrastructure;
+
+namespace SignalR.Reactive
+{
+ public class Clientside<T>
+ {
+ private readonly IObservable<T> _observable;
+
+ internal Clientside(IObservable<T> observable)
+ {
+ _observable = observable;
+ }
+
+ public IDisposable Observable<THub>(Expression<Func<THub, dynamic>> expression) where THub : Hub, new()
+ {
+ return Observable(expression, null);
+ }
+
+ public IDisposable Observable<THub>(Expression<Func<THub, dynamic>> expression, string clientName) where THub : Hub, new()
+ {
+ var memberExpression = expression.Body as MemberExpression;
+ if (memberExpression == null)
+ {
+ throw new ArgumentException("'expression' should be a member expression");
+ }
+
+ return Observable<THub>(memberExpression.Member.Name, clientName);
+ }
+
+ public IDisposable Observable<THub>(string eventName) where THub : Hub, new()
+ {
+ return Observable<THub>(eventName, null);
+ }
+
+ public IDisposable Observable<THub>(string eventName, string clientName) where THub : Hub, new()
+ {
+ var connectionManager = AspNetHost.DependencyResolver.Resolve<IConnectionManager>();
+
+ dynamic clients = connectionManager.GetClients<THub>();
+ clients = string.IsNullOrEmpty(clientName) ? clients : clients[clientName];
+
+ return _observable.Subscribe(
+ x => clients.Invoke("subjectOnNext", new { Data = x, EventName = eventName, Type = "onNext" }),
+ x => clients.Invoke("subjectOnNext", new { Data = x, EventName = eventName, Type = "onError" }),
+ () => clients.Invoke("subjectOnNext", new { EventName = eventName, Type = "onCompleted" })
+ );
+ }
+
+ }
+
+ public static class SignalRObservableExtensions
+ {
+ public static Clientside<T> ToClientside<T>(this IObservable<T> observable)
+ {
+ return new Clientside<T>(observable);
+ }
+ }
+}
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using SignalR.Hubs;
+using SignalR.Infrastructure;
+
+namespace SignalR.Reactive
+{
+ public static class DependencyResolverExtensions
+ {
+ public static IDependencyResolver EnableRxSupport(this IDependencyResolver dependencyResolver)
+ {
+ var proxyGenerator = new Lazy<RxJsProxyGenerator>(() => new RxJsProxyGenerator(dependencyResolver));
+ dependencyResolver.Register(typeof(IJavaScriptProxyGenerator), () => proxyGenerator.Value);
+
+ return dependencyResolver;
+ }
+ }
+}
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die mit einer Assembly verknüpft sind.
+[assembly: AssemblyTitle("SignalR.Reactive")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("SignalR.Reactive")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
+// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
+// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("126d9d94-4de9-4550-bea6-f63ecb245569")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+// Hauptversion
+// Nebenversion
+// Buildnummer
+// Revision
+//
+// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
+// übernehmen, indem Sie "*" eingeben:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,211 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using SignalR.Hubs;
+using SignalR.Infrastructure;
+
+namespace SignalR.Reactive
+{
+ class RxJsProxyGenerator
+ {
+ private static readonly Lazy<string> _template = new Lazy<string>(GetTemplate);
+ private static readonly ConcurrentDictionary<string, string> _scriptCache = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+
+ private const string ScriptResource = "SignalR.Scripts.hubs.js";
+
+ private readonly IHubLocator _hubLocator;
+ private readonly IJavaScriptMinifier _javascriptMinifier;
+
+ public RxJsProxyGenerator(IDependencyResolver resolver) :
+ this(resolver.Resolve<IHubLocator>(),
+ resolver.Resolve<IJavaScriptMinifier>())
+ {
+ }
+
+ public RxJsProxyGenerator(IHubLocator hubLocator, IJavaScriptMinifier javascriptMinifier)
+ {
+ _hubLocator = hubLocator;
+ _javascriptMinifier = javascriptMinifier ?? NullJavaScriptMinifier.Instance;
+ }
+
+ public bool IsDebuggingEnabled { get; set; }
+
+ public string GenerateProxy(string serviceUrl)
+ {
+ string script;
+ if (_scriptCache.TryGetValue(serviceUrl, out script))
+ {
+ return script;
+ }
+
+ var template = _template.Value;
+
+ script = template.Replace("{serviceUrl}", serviceUrl);
+
+ var hubs = new StringBuilder();
+ var first = true;
+ foreach (var type in _hubLocator.GetHubs())
+ {
+ if (!first)
+ {
+ hubs.AppendLine(",");
+ hubs.Append(" ");
+ }
+ GenerateType(serviceUrl, hubs, type);
+ first = false;
+ }
+
+ script = script.Replace("/*hubs*/", hubs.ToString());
+
+ if (!IsDebuggingEnabled)
+ {
+ script = _javascriptMinifier.Minify(script);
+ }
+
+ _scriptCache.TryAdd(serviceUrl, script);
+
+ return script;
+ }
+
+ private void GenerateType(string serviceUrl, StringBuilder sb, Type type)
+ {
+ // Get public instance methods declared on this type only
+ var methods = GetMethods(type);
+ var members = methods.Select(m => m.Name).ToList();
+
+ // Get observable properties declared on this type
+ var observableProperties = ReflectionHelper.GetExportedHubObservables(type);
+
+ members.Add("namespace");
+ members.Add("ignoreMembers");
+ members.Add("callbacks");
+
+ sb.AppendFormat("{0}: {{", GetHubName(type)).AppendLine();
+ sb.AppendFormat(" _: {{").AppendLine();
+ sb.AppendFormat(" hubName: '{0}',", type.FullName ?? "null").AppendLine();
+ sb.AppendFormat(" ignoreMembers: [{0}],", Commas(members, m => "'" + Json.CamelCase(m) + "'")).AppendLine();
+ sb.AppendLine(" connection: function () { return signalR.hub; }");
+ sb.AppendFormat(" }}");
+ if (methods.Any() || observableProperties.Any())
+ {
+ sb.Append(",").AppendLine();
+ }
+ else
+ {
+ sb.AppendLine();
+ }
+
+ bool firstMethod = true;
+
+ foreach (var method in methods)
+ {
+ if (!firstMethod)
+ {
+ sb.Append(",").AppendLine();
+ }
+ GenerateMethod(serviceUrl, sb, type, method);
+ firstMethod = false;
+ }
+
+ if (observableProperties.Any() && methods.Any())
+ {
+ sb.Append(",").AppendLine();
+ }
+
+ bool firstProperty = true;
+
+ foreach (var observableProperty in observableProperties)
+ {
+ if (!firstProperty)
+ {
+ sb.Append(",").AppendLine();
+ }
+ GenerateRxSubject(sb, type, observableProperty);
+ firstProperty = false;
+ }
+
+ sb.AppendLine();
+ sb.Append(" }");
+ }
+
+ protected virtual string GetHubName(Type type)
+ {
+ return ReflectionHelper.GetAttributeValue<HubNameAttribute, string>(type, a => a.HubName) ?? Json.CamelCase(type.Name);
+ }
+
+ protected virtual IEnumerable<MethodInfo> GetMethods(Type type)
+ {
+ // Pick the overload with the minimum number of arguments
+ return from method in ReflectionHelper.GetExportedHubMethods(type)
+ group method by method.Name into overloads
+ let oload = (from overload in overloads
+ orderby overload.GetParameters().Length
+ select overload).FirstOrDefault()
+ select oload;
+ }
+
+ private void GenerateMethod(string serviceUrl, StringBuilder sb, Type type, MethodInfo method)
+ {
+ var parameters = method.GetParameters();
+ var parameterNames = parameters.Select(p => p.Name).ToList();
+ parameterNames.Add("callback");
+ sb.AppendLine();
+ sb.AppendFormat(" {0}: function ({1}) {{", GetMethodName(method), Commas(parameterNames)).AppendLine();
+ sb.AppendFormat(" return serverCall(this, \"{0}\", $.makeArray(arguments));", method.Name).AppendLine();
+ sb.Append(" }");
+ }
+
+ private void GenerateRxSubject(StringBuilder sb, Type type, PropertyInfo property)
+ {
+ Json.CamelCase(property.Name);
+ var hubName = Json.CamelCase(type.Name);
+ sb.AppendFormat(" subject : new Rx.Subject(),");
+ sb.AppendLine();
+ sb.AppendFormat(" subjectOnNext: function(value) {{ signalR.{0}.subject.onNext(value); }},", hubName);
+ sb.AppendLine();
+ sb.AppendFormat(" getObservable: function (eventName) {{ ").AppendLine();
+ sb.AppendFormat(" return Rx.Observable.create(function (obs) {{ ").AppendLine();
+ sb.AppendFormat(" var disposable = signalR.{0}.subject ", hubName).AppendLine();
+ sb.AppendFormat(" .asObservable() ").AppendLine();
+ sb.AppendFormat(" .where(function (x) {{ return x.EventName.toLowerCase() === eventName.toLowerCase(); }}) ").AppendLine();
+ sb.AppendFormat(" .subscribe(function (x) {{ ").AppendLine();
+ sb.AppendFormat(" if (x.Type === 'onNext') obs.onNext(x.Data); ").AppendLine();
+ sb.AppendFormat(" if (x.Type === 'onError') obs.onError(x.Data); ").AppendLine();
+ sb.AppendFormat(" if (x.Type === 'onCompleted') obs.onCompleted(); ").AppendLine();
+ sb.AppendFormat(" }}); ").AppendLine();
+ sb.AppendFormat(" return disposable.dispose; ").AppendLine();
+ sb.AppendFormat(" }}); ").AppendLine();
+ sb.AppendFormat(" }} ").AppendLine();
+ }
+
+ private static string GetMethodName(MethodInfo method)
+ {
+ return ReflectionHelper.GetAttributeValue<HubMethodNameAttribute, string>(method, a => a.MethodName) ?? Json.CamelCase(method.Name);
+ }
+
+ private static string Commas(IEnumerable<string> values)
+ {
+ return Commas(values, v => v);
+ }
+
+ private static string Commas<T>(IEnumerable<T> values, Func<T, string> selector)
+ {
+ return String.Join(", ", values.Select(selector));
+ }
+
+ private static string GetTemplate()
+ {
+ using (Stream resourceStream = typeof(DefaultJavaScriptProxyGenerator).Assembly.GetManifestResourceStream(ScriptResource))
+ {
+ using (var reader = new StreamReader(resourceStream))
+ {
+ return reader.ReadToEnd();
+ }
+ }
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit 5aac980

Please sign in to comment.