Skip to content

Commit

Permalink
Added assembly Proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
ackava committed Aug 30, 2024
1 parent 1ba46c5 commit ebc0f30
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 120 deletions.
76 changes: 76 additions & 0 deletions Positron/Core/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
namespace NeuroSpeech.Positron.Core;

public class AssemblyInfo: IJSProxy
{
public AssemblyInfo(string name,
AssemblyInfo? parent = null,
Type? type = null
) {
this.Parent = parent;
this.Name = name;
this.Fullname = parent == null
? this.Name
: $"{parent.Fullname}.{this.Name}";
this.Type = type;

//if (this.Parent != null)
//{
// var c = this.Parent.Children ??= new Dictionary<string, AssemblyInfo>();
// // c[this.Name] = this;
//}
}

public AssemblyInfo? Parent { get; }
public string Name { get; }
public string Fullname { get; }
public Type? Type { get; }

public Dictionary<string, AssemblyInfo>? Children { get; private set; }

public Type Resolve(string name)
{
if (Children == null)
{
throw new InvalidOperationException($"Type {name} not found in {this.Fullname}");
}
if(Children.TryGetValue(name, out var value))
{
if (value.Type != null)
{
return value.Type;
}
}
throw new InvalidOperationException($"Type {name} not found in {this.Fullname}");
}

internal AssemblyInfo GetOrCreate(string token)
{
this.Children ??= new();
return this.Children.GetOrCreate(token, (x) => new AssemblyInfo(x, this));
}

internal void AddType(Type type)
{
this.Children ??= new();
this.Children.Add(type.Name, new AssemblyInfo(type.Name, this, type));
}

IJSValue IJSProxy.Get(IJSContext context, IJSValue @this, IList<IJSValue> args)
{

var name = args[1].ToString()!;

if (this.Children?.TryGetValue(name, out var av) ?? false)
{
return context.Marshal(av);
}


throw new ArgumentException($"{name} not found in ${this.Fullname}");
}

IJSValue IJSProxy.Set(IJSContext context, IJSValue @this, IList<IJSValue> args)
{
return context.Undefined;
}
}
122 changes: 36 additions & 86 deletions Positron/Core/GlobalClr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,108 +5,58 @@

namespace NeuroSpeech.Positron.Core;

public class TypeNamespace
{
[JsonPropertyName("name")]
public string Name { get; set; }

[JsonPropertyName("types")]
public List<string> Types { get; } = new List<string>();

public TypeNamespace(string name)
{
this.Name = name;
}
}

public class AssemblyInfo
{
public AssemblyInfo(string name,
AssemblyInfo? parent = null,
Type? type = null
) {
this.Parent = parent;
this.Name = name;
this.Fullname = parent == null
? this.Name
: $"{this.Parent}.${this.Name}";
this.Type = type;

if (this.Parent != null)
{
var c = this.Parent.Children ??= new Dictionary<string, AssemblyInfo>();
c[this.Name] = this;
}
}

public AssemblyInfo? Parent { get; }
public string Name { get; }
public string Fullname { get; }
public Type? Type { get; }

public Dictionary<string, AssemblyInfo>? Children { get; private set; }

public Type Resolve(string name)
{
if (Children == null)
{
throw new InvalidOperationException($"Type {name} not found in {this.Fullname}");
}
if(Children.TryGetValue(name, out var value))
{
if (value.Type != null)
{
return value.Type;
}
}
throw new InvalidOperationException($"Type {name} not found in {this.Fullname}");
}

internal AssemblyInfo GetOrCreate(string token)
{
this.Children ??= new();
return this.Children.GetOrCreate(token, (x) => new AssemblyInfo(x, this));
}

internal void AddType(Type type)
{
this.Children ??= new();
this.Children.Add(type.Name, new AssemblyInfo(type.Name, this, type));
}
}

public class GlobalClr
public class GlobalClr
{

private static long rID = 1;

private ConditionalWeakTable<object, string> references = new ConditionalWeakTable<object, string>();
private Dictionary<string, AssemblyInfo> cache = new Dictionary<string, AssemblyInfo>();

public GlobalClr()
{
}

public AssemblyInfo GetNamespaces(string assemblyName)
public AssemblyInfo Assembly(string assemblyName, string? prefix = null)
{
var assembly = Assembly.Load(assemblyName);
var a = new AssemblyInfo("");
foreach(var type in assembly.GetExportedTypes())
return cache.GetOrCreate(assemblyName, (x) =>
{
if (!type.IsPublic)
{
continue;
}
if (type.Namespace?.Length > 0)
var assembly = System.Reflection.Assembly.Load(assemblyName);
var a = new AssemblyInfo("");
foreach (var type in assembly.GetExportedTypes())
{
var root = a;
foreach(var token in type.Namespace.Split("."))
if (!type.IsPublic)
{
root = root.GetOrCreate(token);
continue;
}
if (type.Namespace?.Length > 0)
{

// ignore yantra, and yantrajs for safety....
if (type.Namespace.StartsWith("Yantra.") || type.Namespace.StartsWith("YantraJS."))
{
continue;
}

if (prefix != null)
{
if (!type.Namespace.StartsWith(prefix))
{
continue;
}
}

var root = a;
foreach (var token in type.Namespace.Split("."))
{
root = root.GetOrCreate(token);
}
root.AddType(type);
}
root.AddType(type);
}
}
return a;
return a;
});
}

public Type? ResolveType(string typeName)
Expand Down Expand Up @@ -285,4 +235,4 @@ public string Serialize(object? obj)
return Serialize<object>(obj);
}
}
}

2 changes: 1 addition & 1 deletion Positron/Engine/ClrClassInterop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,9 @@ private IJSValue Invoke(
for (int i = 0; i < l; i++)
{
var pm = argTypes[i];
var vi = args[i];
if (i < args.Count)
{
var vi = args[i];
if (vi.CanConvertTo(pm.ParameterType, out var cv))
{
p[i] = cv;
Expand Down
10 changes: 10 additions & 0 deletions Positron/Engine/IJSProxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace NeuroSpeech.Positron;

public interface IJSProxy
{

IJSValue Get(IJSContext context, IJSValue @this, IList<IJSValue> args);

IJSValue Set(IJSContext context, IJSValue @this, IList<IJSValue> args);

}
2 changes: 2 additions & 0 deletions Positron/Engine/IJSValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ public interface IJSValue
/// </summary>
bool IsWrapped { get; }

bool IsSymbol { get; }

/// <summary>
/// Boolean value
/// </summary>
Expand Down
17 changes: 5 additions & 12 deletions Positron/Engine/JSContextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,6 @@ public static IJSValue GetOrCreate(this IJSValue context, IJSValue keyOrSymbol,
return v;
}


/// <summary>
/// Evaluates `typeof obj` for this and returns appropriate value.
///
Expand All @@ -385,17 +384,6 @@ public static JSType GetTypeOf(IJSValue value)

static readonly MethodInfo awaitPromiseMethod = typeof(JSContextExtensions).GetMethod("AwaitPromise");

/// <summary>
/// Broadcast message on channel to receive it inside ViewModel in JavaScript
/// </summary>
/// <param name="context"></param>
/// <param name="channel"></param>
/// <param name="data"></param>
public static void Broadcast(this IJSContext context, string channel, IJSValue data)
{
context["bridge"].InvokeMethod("broadcast", context.CreateString(channel), data);
}

public static IJSValue CreateDisposableAction(this IJSContext context, Action dispose)
{
var obj = context.CreateObject();
Expand Down Expand Up @@ -469,6 +457,11 @@ public static IJSValue Marshal(this IJSContext context, object valueToCopy, Seri
return context.CreateClass(type);
}

if (valueToCopy is IJSProxy proxy)
{
return context.CreateProxy(proxy);
}

type = valueToCopy.GetType();

type = Nullable.GetUnderlyingType(type) ?? type;
Expand Down
21 changes: 21 additions & 0 deletions Positron/Engine/JSProxyExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NeuroSpeech.Positron;

public static class JSProxyExtensions
{

public static IJSValue CreateProxy(this IJSContext context, IJSProxy proxy)
{
var wrapped = context.Wrap(proxy);
var trap = context.CreateObject();
trap["get"] = context.CreateBoundFunction(3, proxy.Get , "get");
trap["set"] = context.CreateBoundFunction(3, proxy.Set, "set");
return context["Proxy"].CreateNewInstance(wrapped, trap);
}

}
2 changes: 2 additions & 0 deletions Positron/Platforms/iOS/Engine/WJSValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public IJSValue this[string name]

public bool IsArray => this.value.IsArray;

public bool IsSymbol => this.value.IsSymbol;

public bool IsWrapped {
get {
if (!this.value.IsObject)
Expand Down
3 changes: 3 additions & 0 deletions Positron/Positron.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public enum LogType

public class Positron
{

public static string Version = "1.0";

private readonly WeakEventManager OnUrlRequestedEventManager = new WeakEventManager();
private readonly WeakEventManager OnDeviceTokenUpdatedEventManager = new WeakEventManager();

Expand Down
1 change: 1 addition & 0 deletions Positron/Positron.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<PackageId>NeuroSpeech.Positron</PackageId>
<AssemblyName>NeuroSpeech.Positron</AssemblyName>
<RootNamespace>NeuroSpeech.Positron</RootNamespace>
<Version>1.0.1</Version>
<Nullable>enable</Nullable>
<SingleProject>true</SingleProject>
Expand Down
6 changes: 3 additions & 3 deletions Positron/Resources/Scripts.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 3 additions & 17 deletions Positron/Resources/TSLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,8 @@ function __web_atoms_create_promise() {
return { r, e, promise };
}

global.assemblyCache = {};
global.typeCache = {};
// let us verify if clr.assembly is working...

// lets bind clr.resolve to give assembly...
global.clr.assembly = function (name) {
let cached = global.assemblyCache[name];
if (cached) {
return cached;
}
const nsList = global.clr.getNamespaces(name);
cached = new Proxy({}, {
get(n) {
const fullName = `${n}, ${name}`;
return global.typeCache[fullName] ||= global.clr.resolveType(fullName);
}
});
global.assemblyCache[name] = cached;
return cached;
if (typeof global.clr.assembly("NeuroSpeech.Positron").NeuroSpeech.Positron.Positron.version !== "string") {
throw new Error("clr not available");
}

0 comments on commit ebc0f30

Please sign in to comment.