-
Notifications
You must be signed in to change notification settings - Fork 90
/
EdgeJs.cs
137 lines (121 loc) · 5.13 KB
/
EdgeJs.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace EdgeJs
{
public class Edge
{
static object syncRoot = new object();
static bool initialized;
static Func<object, Task<object>> compileFunc;
static ManualResetEvent waitHandle = new ManualResetEvent(false);
private static string edgeDirectory;
static Edge()
{
// needed because we *must* load the edgedll from the original location else we'll freeze up.
edgeDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(Edge)).Location);
}
static string assemblyDirectory;
static string AssemblyDirectory
{
get
{
if (assemblyDirectory == null)
{
assemblyDirectory = Environment.GetEnvironmentVariable("EDGE_BASE_DIR");
if (string.IsNullOrEmpty(assemblyDirectory))
{
string codeBase = typeof(Edge).Assembly.CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
assemblyDirectory = Path.GetDirectoryName(path);
}
}
return assemblyDirectory;
}
}
// in case we want to set this path and not use an enviroment var
public static void SetAssemblyDirectory(string folder)
{
assemblyDirectory = folder;
}
[EditorBrowsable(EditorBrowsableState.Never)]
public Task<object> InitializeInternal(object input)
{
compileFunc = (Func<object, Task<object>>)input;
initialized = true;
waitHandle.Set();
return Task<object>.FromResult((object)null);
}
[DllImport("node.dll", EntryPoint = "?Start@node@@YAHHQAPAD@Z", CallingConvention = CallingConvention.Cdecl)]
static extern int NodeStartx86(int argc, string[] argv);
[DllImport("node.dll", EntryPoint = "?Start@node@@YAHHQEAPEAD@Z", CallingConvention = CallingConvention.Cdecl)]
static extern int NodeStartx64(int argc, string[] argv);
[DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
static extern int LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);
public static Func<object,Task<object>> Func(string code)
{
if (!initialized)
{
lock (syncRoot)
{
if (!initialized)
{
Func<int, string[], int> nodeStart;
if (IntPtr.Size == 4)
{
LoadLibrary(AssemblyDirectory + @"\edge\x86\node.dll");
nodeStart = NodeStartx86;
}
else if (IntPtr.Size == 8)
{
LoadLibrary(AssemblyDirectory + @"\edge\x64\node.dll");
nodeStart = NodeStartx64;
}
else
{
throw new InvalidOperationException(
"Unsupported architecture. Only x86 and x64 are supported.");
}
Thread v8Thread = new Thread(() =>
{
List<string> argv = new List<string>();
argv.Add("node");
string node_params = Environment.GetEnvironmentVariable("EDGE_NODE_PARAMS");
if (!string.IsNullOrEmpty(node_params))
{
foreach (string p in node_params.Split(' '))
{
argv.Add(p);
}
}
argv.Add(Path.Combine(AssemblyDirectory, "edge", "double_edge.js"));
argv.Add($"-EdgeJs:{Path.Combine(edgeDirectory, "EdgeJs.dll")}");
nodeStart(argv.Count, argv.ToArray());
waitHandle.Set();
});
v8Thread.IsBackground = true;
v8Thread.Start();
waitHandle.WaitOne();
if (!initialized)
{
throw new InvalidOperationException("Unable to initialize Node.js runtime.");
}
}
}
}
if (compileFunc == null)
{
throw new InvalidOperationException("Edge.Func cannot be used after Edge.Close had been called.");
}
var task = compileFunc(code);
task.Wait();
return (Func<object, Task<object>>)task.Result;
}
}
}