├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── Dockerfile ├── LICENSE.txt ├── README.md ├── binding.gyp ├── lib ├── bootstrap │ ├── Dummy.cs │ └── project.json ├── double_edge.js ├── edge.js └── native │ └── win32 │ ├── ia32 │ ├── 6.5.0 │ │ ├── edge_coreclr.node │ │ └── edge_nativeclr.node │ ├── 7.4.0 │ │ ├── edge_coreclr.node │ │ └── edge_nativeclr.node │ ├── msvcp120.dll │ └── msvcr120.dll │ └── x64 │ ├── 6.5.0 │ ├── edge_coreclr.node │ └── edge_nativeclr.node │ ├── 7.4.0 │ ├── edge_coreclr.node │ └── edge_nativeclr.node │ ├── msvcp120.dll │ └── msvcr120.dll ├── package.json ├── performance ├── .gitignore ├── BookService │ ├── App.config │ ├── BookService.csproj │ ├── BookService.sln │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── compile.sh │ └── packages.config ├── latency.js ├── marshal_clr2v8.js └── performance.cs ├── samples ├── 101_hello_lambda.js ├── 102_hello_function.js ├── 103_hello_file.csx ├── 103_hello_file.js ├── 104_add7_class.js ├── 105_add7_dll.js ├── 106_marshal_v82clr.js ├── 107_marshal_clr2v8.js ├── 108_func.js ├── 108_lambda.js ├── 109_sync.js ├── 110_clr_instance.js ├── 111_clr_listener.js ├── 201_worker.js ├── 202_sql.csx ├── 202_sql.js ├── 203_x509store.js ├── 204_event_log.js ├── 205_soap.csx ├── 205_soap.js ├── 206_registry_read.js ├── 206_registry_write.js ├── 207_unzip.js ├── 207_zip.js ├── 208_convertImage.js ├── 209_websocket.js ├── 210_windows_authentication.js ├── 211_events.js ├── 301_cspyfsps.js ├── Sample105.cs ├── edge.png └── readme.txt ├── src ├── CoreCLREmbedding │ ├── coreclrembedding.cpp │ ├── coreclrfunc.cpp │ ├── coreclrfuncinvokecontext.cpp │ ├── coreclrnodejsfunc.cpp │ ├── coreclrnodejsfuncinvokecontext.cpp │ ├── cpprest │ │ └── include │ │ │ ├── asyncrt_utils.h │ │ │ └── json.h │ ├── deps │ │ ├── deps_entry.cpp │ │ ├── deps_entry.h │ │ ├── deps_format.cpp │ │ ├── deps_format.h │ │ ├── deps_resolver.cpp │ │ └── deps_resolver.h │ ├── edge.h │ ├── fxr │ │ ├── fx_muxer.cpp │ │ ├── fx_muxer.h │ │ ├── fx_ver.cpp │ │ └── fx_ver.h │ ├── host │ │ ├── args.cpp │ │ ├── args.h │ │ ├── coreclr.cpp │ │ ├── coreclr.h │ │ ├── error_codes.h │ │ ├── libhost.cpp │ │ ├── libhost.h │ │ ├── runtime_config.cpp │ │ └── runtime_config.h │ ├── json │ │ └── casablanca │ │ │ ├── LICENSE.txt │ │ │ ├── include │ │ │ ├── cpprest │ │ │ │ ├── asyncrt_utils.h │ │ │ │ ├── details │ │ │ │ │ ├── SafeInt3.hpp │ │ │ │ │ ├── basic_types.h │ │ │ │ │ ├── cpprest_compat.h │ │ │ │ │ └── nosal.h │ │ │ │ └── json.h │ │ │ └── stdafx.h │ │ │ └── src │ │ │ ├── json │ │ │ ├── json.cpp │ │ │ ├── json_parsing.cpp │ │ │ └── json_serialization.cpp │ │ │ └── utilities │ │ │ └── asyncrt_utils.cpp │ └── pal │ │ ├── pal.h │ │ ├── pal.unix.cpp │ │ ├── pal.windows.cpp │ │ ├── pal_utils.cpp │ │ ├── pal_utils.h │ │ ├── trace.cpp │ │ └── trace.h ├── common │ ├── clrfuncreflectionwrap.cs │ ├── edge.cpp │ ├── edge_common.h │ ├── utils.cpp │ └── v8synchronizationcontext.cpp ├── dotnet │ ├── clractioncontext.cpp │ ├── clrfunc.cpp │ ├── clrfuncinvokecontext.cpp │ ├── clrfuncreflectionwrap.cpp │ ├── edge.h │ ├── nodejsfunc.cpp │ ├── nodejsfuncinvokecontext.cpp │ ├── persistentdisposecontext.cpp │ └── utils.cpp ├── double │ └── Edge.js │ │ ├── dotnet │ │ └── EdgeJs.cs │ │ ├── dotnetcore │ │ ├── coreclrembedding.cs │ │ ├── nodejsfunc.cs │ │ ├── nodejsfuncinvokecontext.cs │ │ └── semversion.cs │ │ └── project.json └── mono │ ├── clractioncontext.cpp │ ├── clrfunc.cpp │ ├── clrfuncinvokecontext.cpp │ ├── clrfuncinvokecontext.cs │ ├── dictionary.cpp │ ├── edge.h │ ├── monoembedding.cpp │ ├── monoembedding.cs │ ├── nodejsfunc.cpp │ ├── nodejsfunc.cs │ ├── nodejsfuncinvokecontext.cpp │ ├── nodejsfuncinvokecontext.cs │ ├── task.cpp │ └── utils.cpp ├── stress └── test.js ├── test ├── 101_edge_func.js ├── 102_node2net.js ├── 103_net2node.js ├── 104_csx.js ├── 105_node2net_sync.js ├── 201_patterns.js ├── build.bat ├── build.sh ├── double │ ├── .gitignore │ ├── double_stress │ │ ├── App.config │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ ├── double_stress.csproj │ │ ├── double_stress.sln │ │ └── packages.config │ └── double_test │ │ ├── DoubleEdge.cs │ │ ├── Properties │ │ └── AssemblyInfo.cs │ │ ├── double_test.csproj │ │ ├── double_test.sln │ │ └── packages.config ├── hello_class.cs ├── hello_class.csx ├── hello_lambda.csx ├── project.json ├── test.bat ├── testall.bat └── tests.cs └── tools ├── build.bat ├── build_double.bat ├── buildall.bat ├── checkplatform.js ├── download.cs ├── download.js ├── install.js ├── nuget ├── edge.nuspec └── install.ps1 ├── repl.cs ├── runJsHint.js ├── test.js ├── unzip.cs ├── unzip.vbs └── whereis.js /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.lock.json 10 | 11 | pids 12 | logs 13 | results 14 | 15 | node_modules 16 | npm-debug.log 17 | build 18 | 19 | bin/ 20 | obj/ 21 | *.user 22 | *.suo 23 | packages/* 24 | _ReSharper* 25 | 26 | Edge.Tests.* 27 | node.exe 28 | Sample105.* 29 | 30 | .DS_Store 31 | *.sublime-project 32 | *.sublime-workspace 33 | 34 | .cproject 35 | .project 36 | .metadata/ 37 | .settings/ 38 | 39 | adhoc/ -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "_": true, 4 | "after": true, 5 | "async": true, 6 | "afterEach": true, 7 | "afterEach": true, 8 | "Backbone": true, 9 | "before": true, 10 | "beforeEach": true, 11 | "describe": true, 12 | "expect": true, 13 | "iit": true, 14 | "it": true, 15 | "jasmine": true, 16 | "moment": true, 17 | "runs": true, 18 | "sinon": true, 19 | "spyOn": true, 20 | "waits": true, 21 | "waitsFor": true, 22 | "xit": true, 23 | "xdescribe": true 24 | }, 25 | 26 | "options": { 27 | "asi" : false, 28 | "bitwise" : true, 29 | "boss" : false, 30 | "browser" : true, 31 | "curly" : true, 32 | "debug": false, 33 | "devel": false, 34 | "eqeqeq": true, 35 | "evil": false, 36 | "expr": true, 37 | "forin": false, 38 | "immed": true, 39 | "jquery" : true, 40 | "latedef" : false, 41 | "laxbreak": false, 42 | "multistr": true, 43 | "newcap": true, 44 | "noarg": true, 45 | "node" : true, 46 | "noempty": false, 47 | "nonew": true, 48 | "onevar": false, 49 | "plusplus": false, 50 | "regexp": false, 51 | "strict": false, 52 | "sub": false, 53 | "trailing" : true, 54 | "undef": true 55 | } 56 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "0.12" 5 | - "0.10" 6 | 7 | install: 8 | - sudo apt-key adv --keyserver pgp.mit.edu --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF 9 | - sudo sh -c "echo 'deb http://download.mono-project.com/repo/debian wheezy main' >> /etc/apt/sources.list.d/mono-xamarin.list" 10 | - sudo sh -c "echo 'deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main' >> /etc/apt/sources.list.d/mono-xamarin.list" 11 | - sudo apt-get update 12 | - sudo apt-get install mono-devel 13 | - npm install -g grunt-cli 14 | - npm install 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Edge.js Dockerfile 3 | # Debian with Node.js, Edge.js, Mono, CoreCLR 4 | # 5 | 6 | FROM nodesource/trusty:6.3.0 7 | WORKDIR /data 8 | ADD ./samples /data/samples 9 | RUN bash -c ' \ 10 | set -eux && \ 11 | sed -i "s/..\/lib\/edge/edge/g" /data/samples/*.js && \ 12 | \ 13 | echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ trusty main" > /etc/apt/sources.list.d/dotnetdev.list && \ 14 | apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893 && \ 15 | apt-get -y update && \ 16 | apt-get -y install dotnet-dev-1.0.0-preview2-003121 && \ 17 | \ 18 | apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && \ 19 | echo "deb http://download.mono-project.com/repo/debian wheezy/snapshots/4.2.4 main" | tee /etc/apt/sources.list.d/mono-xamarin.list && \ 20 | apt-get -y update && \ 21 | apt-get -y install curl g++ pkg-config libgdiplus libunwind8 libssl-dev make mono-complete gettext libssl-dev libcurl4-openssl-dev zlib1g libicu-dev uuid-dev unzip && \ 22 | \ 23 | npm i tjanczuk/edge && \ 24 | npm cache clean' 25 | CMD [ "bash", "-c", "echo Welcome to Edge.js && echo Samples are in /data/samples && echo Documentation is at https://github.com/tjanczuk/edge && echo Use EDGE_USE_CORECLR=1 environment variable to select CoreCLR, otherwise Mono is used && bash" ] 26 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2012 Tomasz Janczuk 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /lib/bootstrap/Dummy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | public class Dummy 4 | { 5 | } -------------------------------------------------------------------------------- /lib/bootstrap/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "frameworks": { 3 | "netcoreapp1.0": { 4 | "imports": [ 5 | "portable-net45+wp80+win8+wpa81+dnxcore50", 6 | "portable-dnxcore50+net45+win8+wp8+wpa81" 7 | ], 8 | "dependencies": { 9 | "Microsoft.NETCore.App": { 10 | "type": "platform", 11 | "version": "1.0.0" 12 | }, 13 | "Edge.js": "6.5.1", 14 | "Edge.js.CSharp": "1.2.0" 15 | } 16 | } 17 | }, 18 | 19 | "buildOptions": { 20 | "preserveCompilationContext": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/double_edge.js: -------------------------------------------------------------------------------- 1 | // Fix #176 for GUI applications on Windows 2 | try { 3 | var stdout = process.stdout; 4 | } 5 | catch (e) { 6 | // This is a Windows GUI application without stdout and stderr defined. 7 | // Define process.stdout and process.stderr so that all output is discarded. 8 | (function () { 9 | var stream = require('stream'); 10 | var NullStream = function (o) { 11 | stream.Writable.call(this); 12 | this._write = function (c, e, cb) { cb && cb(); }; 13 | } 14 | require('util').inherits(NullStream, stream.Writable); 15 | var nullStream = new NullStream(); 16 | process.__defineGetter__('stdout', function () { return nullStream; }); 17 | process.__defineGetter__('stderr', function () { return nullStream; }); 18 | })(); 19 | } 20 | 21 | process.env['EDGE_NATIVE'] = process.env['EDGE_NATIVE'] || 22 | __dirname + (process.arch === 'x64' ? '\\x64\\edge_nativeclr.node' : '\\x86\\edge_nativeclr.node'); 23 | 24 | var edge = require('./edge.js'); 25 | 26 | var initialize = edge.func({ 27 | assemblyFile: __dirname + '\\..\\EdgeJs.dll', 28 | typeName: 'EdgeJs.Edge', 29 | methodName: 'InitializeInternal' 30 | }); 31 | 32 | var compileFunc = function (data, callback) { 33 | var wrapper = '(function () { ' + data + ' })'; 34 | var funcFactory = eval(wrapper); 35 | var func = funcFactory(); 36 | if (typeof func !== 'function') { 37 | throw new Error('Node.js code must return an instance of a JavaScript function. ' 38 | + 'Please use `return` statement to return a function.'); 39 | } 40 | 41 | callback(null, func); 42 | }; 43 | 44 | initialize(compileFunc, function (error, data) { 45 | if (error) throw error; 46 | }); 47 | 48 | // prevent the V8 thread from exiting for the lifetime of the CLR application 49 | setInterval(function () {}, 3600000); 50 | -------------------------------------------------------------------------------- /lib/native/win32/ia32/6.5.0/edge_coreclr.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/ia32/6.5.0/edge_coreclr.node -------------------------------------------------------------------------------- /lib/native/win32/ia32/6.5.0/edge_nativeclr.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/ia32/6.5.0/edge_nativeclr.node -------------------------------------------------------------------------------- /lib/native/win32/ia32/7.4.0/edge_coreclr.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/ia32/7.4.0/edge_coreclr.node -------------------------------------------------------------------------------- /lib/native/win32/ia32/7.4.0/edge_nativeclr.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/ia32/7.4.0/edge_nativeclr.node -------------------------------------------------------------------------------- /lib/native/win32/ia32/msvcp120.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/ia32/msvcp120.dll -------------------------------------------------------------------------------- /lib/native/win32/ia32/msvcr120.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/ia32/msvcr120.dll -------------------------------------------------------------------------------- /lib/native/win32/x64/6.5.0/edge_coreclr.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/x64/6.5.0/edge_coreclr.node -------------------------------------------------------------------------------- /lib/native/win32/x64/6.5.0/edge_nativeclr.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/x64/6.5.0/edge_nativeclr.node -------------------------------------------------------------------------------- /lib/native/win32/x64/7.4.0/edge_coreclr.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/x64/7.4.0/edge_coreclr.node -------------------------------------------------------------------------------- /lib/native/win32/x64/7.4.0/edge_nativeclr.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/x64/7.4.0/edge_nativeclr.node -------------------------------------------------------------------------------- /lib/native/win32/x64/msvcp120.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/x64/msvcp120.dll -------------------------------------------------------------------------------- /lib/native/win32/x64/msvcr120.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/lib/native/win32/x64/msvcr120.dll -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-edge", 3 | "author": { 4 | "name": "Tomasz Janczuk ", 5 | "url": "http://tomasz.janczuk.org", 6 | "twitter": "tjanczuk" 7 | }, 8 | "version": "6.5.5", 9 | "description": "Edge.js: run .NET and Node.js in-process on Windows, Mac OS, and Linux", 10 | "tags": [ 11 | "owin", 12 | "edge", 13 | "net", 14 | "clr", 15 | "coreclr", 16 | "c#", 17 | "mono", 18 | "managed", 19 | ".net" 20 | ], 21 | "main": "./lib/edge.js", 22 | "engines": { 23 | "node": ">= 0.8" 24 | }, 25 | "licenses": [ 26 | { 27 | "type": "Apache", 28 | "url": "http://www.apache.org/licenses/LICENSE-2.0" 29 | } 30 | ], 31 | "dependencies": { 32 | "edge-cs": "1.2.1", 33 | "nan": "^2.0.9" 34 | }, 35 | "devDependencies": { 36 | "mocha": "2.5.3", 37 | "jshint": "1.1.0" 38 | }, 39 | "homepage": "https://github.com/tjanczuk/edge", 40 | "repository": { 41 | "type": "git", 42 | "url": "git@github.com:kexplo/electron-edge.git" 43 | }, 44 | "bugs": { 45 | "url": "http://github.com/tjanczuk/edge/issues" 46 | }, 47 | "scripts": { 48 | "install": "node tools/install.js", 49 | "test": "node tools/test.js", 50 | "jshint": "node ./tools/runJsHint.js" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /performance/.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | BookService/packages/ -------------------------------------------------------------------------------- /performance/BookService/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /performance/BookService/BookService.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {860AE049-3944-4CAB-A087-1CDEAEEFCC14} 8 | Exe 9 | Properties 10 | BookService 11 | BookService 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | packages\Newtonsoft.Json.5.0.5\lib\net45\Newtonsoft.Json.dll 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 66 | -------------------------------------------------------------------------------- /performance/BookService/BookService.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BookService", "BookService.csproj", "{860AE049-3944-4CAB-A087-1CDEAEEFCC14}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {860AE049-3944-4CAB-A087-1CDEAEEFCC14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {860AE049-3944-4CAB-A087-1CDEAEEFCC14}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {860AE049-3944-4CAB-A087-1CDEAEEFCC14}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {860AE049-3944-4CAB-A087-1CDEAEEFCC14}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /performance/BookService/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Net.Http.Headers; 4 | using System.ServiceModel; 5 | using System.Web.Http; 6 | using System.Web.Http.SelfHost; 7 | 8 | namespace BookService 9 | { 10 | public class Book 11 | { 12 | public string title = "Run .NET and node.js in-process with edge.js"; 13 | public object author = new { first = "Tomasz", last = "Janczuk" }; 14 | public int year = 2013; 15 | public double price = 24.99; 16 | public bool available = true; 17 | public string description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus posuere tincidunt felis, et mattis mauris ultrices quis. Cras molestie, quam varius tincidunt tincidunt, mi magna imperdiet lacus, quis elementum ante nibh quis orci. In posuere erat sed tellus lacinia luctus. Praesent sodales tellus mauris, et egestas justo. In blandit, metus non congue adipiscing, est orci luctus odio, non sagittis erat orci ac sapien. Proin ut est id enim mattis volutpat. Vivamus ultrices dapibus feugiat. In dictum tincidunt eros, non pretium nisi rhoncus in. Duis a lacus et elit feugiat ullamcorper. Mauris tempor turpis nulla. Nullam nec facilisis elit."; 18 | public byte[] picture = new byte[16000]; 19 | public object[] tags = new object[] { ".NET", "node.js", "CLR", "V8", "interop" }; 20 | } 21 | 22 | public class BookController : ApiController 23 | { 24 | static readonly Uri baseAddress = new Uri("http://localhost:31415/"); 25 | 26 | public Book Get() 27 | { 28 | return new Book(); 29 | } 30 | 31 | static void Main(string[] args) 32 | { 33 | HttpSelfHostServer server = null; 34 | try 35 | { 36 | HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress); 37 | config.HostNameComparisonMode = HostNameComparisonMode.Exact; 38 | 39 | // Register default route 40 | config.Routes.MapHttpRoute( 41 | name: "DefaultApi", 42 | routeTemplate: "api/{controller}" 43 | ); 44 | 45 | server = new HttpSelfHostServer(config); 46 | server.OpenAsync().Wait(); 47 | Console.WriteLine("Listening on " + baseAddress); 48 | Console.WriteLine("Hit ENTER to exit..."); 49 | Console.ReadLine(); 50 | } 51 | catch (Exception e) 52 | { 53 | Console.WriteLine("Could not start server: {0}", e.GetBaseException().Message); 54 | Console.WriteLine("Hit ENTER to exit..."); 55 | Console.ReadLine(); 56 | } 57 | finally 58 | { 59 | if (server != null) 60 | { 61 | server.CloseAsync().Wait(); 62 | } 63 | } 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /performance/BookService/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("BookService")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("BookService")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("00b715fc-f588-4964-8edc-6d9665df29b6")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /performance/BookService/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mcs -sdk:4.5 Program.cs /r:System.Net.Http.dll /r:System.ServiceModel.dll /r:System.Web.Http.dll /r:System.Web.Http.SelfHost.dll 3 | -------------------------------------------------------------------------------- /performance/BookService/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /performance/latency.js: -------------------------------------------------------------------------------- 1 | function help() { 2 | console.log('Usage: node latency.js i|x '); 3 | console.log(' i - 1 compilation, in-process loop of N calls'); 4 | console.log(' c - in-process loop of N compilations and calls'); 5 | console.log(' x - child process loop of N iterations'); 6 | console.log('e.g. node latency.js i 1000'); 7 | process.exit(1); 8 | } 9 | 10 | if (process.argv.length !== 4) 11 | help(); 12 | 13 | if (isNaN(process.argv[3])) 14 | help(); 15 | 16 | var N = +process.argv[3]; 17 | 18 | if (N < 1) 19 | help(); 20 | 21 | if (process.argv[2] === 'i') { 22 | var func = require('../lib/edge').func(function () {/* 23 | async (input) => { 24 | return ".NET welcomes " + input.ToString(); 25 | } 26 | */}); 27 | var M = N; 28 | var start = Date.now(); 29 | one_i(); 30 | function one_i() { 31 | func('Node.js', function (error, result) { 32 | if (error) throw error; 33 | if (--M <= 0) { 34 | var delta = Date.now() - start; 35 | console.log(delta, delta / N); 36 | } 37 | else 38 | setImmediate(one_i); 39 | }); 40 | } 41 | }else if (process.argv[2] === 'c') { 42 | var csharp = 'async (input) => { return ".NET welcomes " + input.ToString(); } /*'; 43 | 44 | var edge = require('../lib/edge'); 45 | var M = N; 46 | var start = Date.now(); 47 | one_c(); 48 | function one_c() { 49 | var code = csharp + M + '*/'; // force cache miss and recompile 50 | var func = edge.func(code); 51 | func('Node.js', function (error, result) { 52 | if (error) throw error; 53 | if (--M <= 0) { 54 | var delta = Date.now() - start; 55 | console.log(delta, delta / N); 56 | } 57 | else 58 | setImmediate(one_c); 59 | }); 60 | } 61 | } 62 | else if (process.argv[2] === 'x') { 63 | var child_process = require('child_process'); 64 | var cmd = [process.argv[0], process.argv[1], 'i', '1'].join(' '); 65 | var M = N; 66 | var start = Date.now(); 67 | one_x(); 68 | function one_x() { 69 | child_process.exec(cmd, function (error) { 70 | if (error) throw error; 71 | if (--M <= 0) { 72 | var delta = Date.now() - start; 73 | console.log(delta, delta / N); 74 | } 75 | else 76 | setImmediate(one_x); 77 | }); 78 | } 79 | } 80 | else 81 | help(); 82 | -------------------------------------------------------------------------------- /performance/marshal_clr2v8.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | var callCount = process.env.EDGE_CALL_COUNT || 10000; 4 | var edgePerformanceDll = path.join(__dirname, 'Edge.Performance.dll'); 5 | 6 | var measure = function (func) { 7 | var start = Date.now(); 8 | var i = 0; 9 | 10 | function one() { 11 | func({ 12 | title: 'Run .NET and node.js in-process with edge.js', 13 | author: { 14 | first: 'Tomasz', 15 | last: 'Janczuk' 16 | }, 17 | year: 2013, 18 | price: 24.99, 19 | available: true, 20 | description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus posuere tincidunt felis, et mattis mauris ultrices quis. Cras molestie, quam varius tincidunt tincidunt, mi magna imperdiet lacus, quis elementum ante nibh quis orci. In posuere erat sed tellus lacinia luctus. Praesent sodales tellus mauris, et egestas justo. In blandit, metus non congue adipiscing, est orci luctus odio, non sagittis erat orci ac sapien. Proin ut est id enim mattis volutpat. Vivamus ultrices dapibus feugiat. In dictum tincidunt eros, non pretium nisi rhoncus in. Duis a lacus et elit feugiat ullamcorper. Mauris tempor turpis nulla. Nullam nec facilisis elit.', 21 | picture: new Buffer(16000), 22 | tags: [ '.NET', 'node.js', 'CLR', 'V8', 'interop'] 23 | }, function (error, callbck) { 24 | if (error) throw error; 25 | if (++i < callCount) setImmediate(one); 26 | else finish(); 27 | }); 28 | } 29 | 30 | function finish() { 31 | var delta = Date.now() - start; 32 | var result = process.memoryUsage(); 33 | result.latency = delta / callCount; 34 | console.log(result); 35 | } 36 | 37 | one(); 38 | }; 39 | 40 | var baseline = function () { 41 | measure(function (input, callback) { 42 | var book = { 43 | title: 'Run .NET and node.js in-process with edge.js', 44 | author: { 45 | first: 'Tomasz', 46 | last: 'Janczuk' 47 | }, 48 | year: 2013, 49 | price: 24.99, 50 | available: true, 51 | description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus posuere tincidunt felis, et mattis mauris ultrices quis. Cras molestie, quam varius tincidunt tincidunt, mi magna imperdiet lacus, quis elementum ante nibh quis orci. In posuere erat sed tellus lacinia luctus. Praesent sodales tellus mauris, et egestas justo. In blandit, metus non congue adipiscing, est orci luctus odio, non sagittis erat orci ac sapien. Proin ut est id enim mattis volutpat. Vivamus ultrices dapibus feugiat. In dictum tincidunt eros, non pretium nisi rhoncus in. Duis a lacus et elit feugiat ullamcorper. Mauris tempor turpis nulla. Nullam nec facilisis elit.', 52 | picture: new Buffer(16000), 53 | tags: [ '.NET', 'node.js', 'CLR', 'V8', 'interop'] 54 | } 55 | callback(null, book); 56 | }); 57 | }; 58 | 59 | var clr2v8 = function () { 60 | measure(require('../lib/edge').func({ 61 | assemblyFile: edgePerformanceDll, 62 | methodName: 'Invoke' 63 | })); 64 | }; 65 | 66 | var crossProcess = function () { 67 | var http = require('http'); 68 | measure(function (input, callback) { 69 | http.get("http://localhost:31415/api/book", function(res) { 70 | if (res.statusCode !== 200) { 71 | return callback(new Error('Status code: ' + res.statusCode)); 72 | } 73 | 74 | var body = ''; 75 | res.on('data', function (chunk) { body += chunk; }); 76 | res.on('end', function () { 77 | callback(null, JSON.parse(body)); 78 | }) 79 | }).on('error', callback); 80 | }); 81 | }; 82 | 83 | var cases = { 84 | js: baseline, 85 | edge: clr2v8, 86 | xproc: crossProcess 87 | }; 88 | 89 | if (!cases[process.argv[2]]) { 90 | console.log('Usage: marshal_clr2v8.js ' + Object.getOwnPropertyNames(cases).join('|')); 91 | process.exit(1); 92 | } 93 | else { 94 | cases[process.argv[2]](); 95 | } 96 | -------------------------------------------------------------------------------- /performance/performance.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Dynamic; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | #pragma warning disable 1998 8 | 9 | namespace Edge.Performance 10 | { 11 | public class Startup 12 | { 13 | public async Task Invoke(dynamic input) 14 | { 15 | var book = new 16 | { 17 | title = "Run .NET and node.js in-process with edge.js", 18 | author = new { 19 | first = "Tomasz", 20 | last = "Janczuk" 21 | }, 22 | year = 2013, 23 | price = 24.99, 24 | available = true, 25 | description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus posuere tincidunt felis, et mattis mauris ultrices quis. Cras molestie, quam varius tincidunt tincidunt, mi magna imperdiet lacus, quis elementum ante nibh quis orci. In posuere erat sed tellus lacinia luctus. Praesent sodales tellus mauris, et egestas justo. In blandit, metus non congue adipiscing, est orci luctus odio, non sagittis erat orci ac sapien. Proin ut est id enim mattis volutpat. Vivamus ultrices dapibus feugiat. In dictum tincidunt eros, non pretium nisi rhoncus in. Duis a lacus et elit feugiat ullamcorper. Mauris tempor turpis nulla. Nullam nec facilisis elit.", 26 | picture = new byte[16000], 27 | tags = new object[] { ".NET", "node.js", "CLR", "V8", "interop" } 28 | }; 29 | 30 | return book; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /samples/101_hello_lambda.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var hello = edge.func('async (input) => { return ".NET welcomes " + input.ToString(); }'); 6 | 7 | hello('Node.js', function (error, result) { 8 | if (error) throw error; 9 | console.log(result); 10 | }); -------------------------------------------------------------------------------- /samples/102_hello_function.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var hello = edge.func(function () {/* 6 | async (input) => 7 | { 8 | return ".NET welcomes " + input.ToString(); 9 | } 10 | */}); 11 | 12 | hello('Node.js', function (error, result) { 13 | if (error) throw error; 14 | console.log(result); 15 | }); -------------------------------------------------------------------------------- /samples/103_hello_file.csx: -------------------------------------------------------------------------------- 1 | async (input) => 2 | { 3 | return ".NET welcomes " + input.ToString(); 4 | } -------------------------------------------------------------------------------- /samples/103_hello_file.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var hello = edge.func('103_hello_file.csx'); 6 | 7 | hello('Node.js', function (error, result) { 8 | if (error) throw error; 9 | console.log(result); 10 | }); -------------------------------------------------------------------------------- /samples/104_add7_class.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var add7 = edge.func(function () {/* 6 | using System.Threading.Tasks; 7 | 8 | public class Startup 9 | { 10 | public async Task Invoke(object input) 11 | { 12 | return this.Add7((int)input); 13 | } 14 | 15 | int Add7(int v) 16 | { 17 | return Helper.Add7(v); 18 | } 19 | } 20 | 21 | static class Helper 22 | { 23 | public static int Add7(int v) 24 | { 25 | return v + 7; 26 | } 27 | } 28 | */}); 29 | 30 | add7(12, function (error, result) { 31 | if (error) throw error; 32 | console.log(result); 33 | }); -------------------------------------------------------------------------------- /samples/105_add7_dll.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | // Compile Sample105.dll with 4 | // - on Windows (.NET Framework): 5 | // csc.exe /target:library /debug Sample105.cs 6 | // - on MacOS/Linux (Mono): 7 | // mcs -sdk:4.5 Sample105.cs -target:library 8 | 9 | var edge = require('../lib/edge'); 10 | 11 | var add7 = edge.func('Sample105.dll'); 12 | 13 | add7(12, function (error, result) { 14 | if (error) throw error; 15 | console.log(result); 16 | }); -------------------------------------------------------------------------------- /samples/106_marshal_v82clr.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var hello = edge.func(function () {/* 6 | using System.Collections.Generic; 7 | 8 | async (data) => 9 | { 10 | Console.WriteLine("-----> In .NET:"); 11 | foreach (var kv in (IDictionary)data) 12 | { 13 | Console.WriteLine(kv.Key + ": " + kv.Value.GetType()); 14 | } 15 | 16 | return null; 17 | } 18 | */}); 19 | 20 | var payload = { 21 | anInteger: 1, 22 | aNumber: 3.1415, 23 | aString: 'foobar', 24 | aBool: true, 25 | anObject: {}, 26 | anArray: [ 'a', 1, true ], 27 | aBuffer: new Buffer(1024) 28 | } 29 | 30 | console.log('-----> In node.js:'); 31 | console.log(payload); 32 | 33 | hello(payload, function (error, result) { 34 | if (error) throw error; 35 | }); 36 | -------------------------------------------------------------------------------- /samples/107_marshal_clr2v8.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var hello = edge.func(function () {/* 6 | async (input) => 7 | { 8 | var result = new { 9 | anInteger = 1, 10 | aNumber = 3.1415, 11 | aString = "foobar", 12 | aBool = true, 13 | anObject = new { a = "b", c = 12 }, 14 | anArray = new object[] { "a", 1, true }, 15 | aBuffer = new byte[1024] 16 | }; 17 | 18 | return result; 19 | } 20 | */}); 21 | 22 | hello(null, function (error, result) { 23 | if (error) throw error; 24 | console.log('-----> In node.js:'); 25 | console.log(result); 26 | }); 27 | -------------------------------------------------------------------------------- /samples/108_func.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var addAndMultiplyBy2 = edge.func(function () {/* 6 | using System.Collections.Generic; 7 | 8 | async (dynamic data) => 9 | { 10 | int sum = (int)data.a + (int)data.b; 11 | var multiplyBy2 = (Func>)data.multiplyBy2; 12 | return await multiplyBy2(sum); 13 | } 14 | */}); 15 | 16 | var payload = { 17 | a: 2, 18 | b: 3, 19 | multiplyBy2: function(input, callback) { 20 | callback(null, input * 2); 21 | } 22 | }; 23 | 24 | addAndMultiplyBy2(payload, function (error, result) { 25 | if (error) throw error; 26 | console.log(result); 27 | }); 28 | -------------------------------------------------------------------------------- /samples/108_lambda.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var createCounter = edge.func(function () {/* 6 | async (start) => 7 | { 8 | var k = (int)start; 9 | return (Func>)( 10 | async (i) => 11 | { 12 | return k++; 13 | } 14 | ); 15 | } 16 | */}); 17 | 18 | var nextNumber = createCounter(12, true); 19 | console.log(nextNumber(null, true)); 20 | console.log(nextNumber(null, true)); 21 | console.log(nextNumber(null, true)); 22 | -------------------------------------------------------------------------------- /samples/109_sync.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var hello = edge.func('async (input) => { return ".NET welcomes " + input.ToString(); }'); 6 | 7 | // call the function synchronously 8 | var result = hello('Node.js', true); 9 | console.log(result); 10 | 11 | // call the same function asynchronously 12 | hello('JavaScript', function (error, result) { 13 | if (error) throw error; 14 | console.log(result); 15 | }); 16 | -------------------------------------------------------------------------------- /samples/110_clr_instance.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var createPerson = edge.func(function () {/* 6 | using System; 7 | using System.Threading.Tasks; 8 | 9 | public class Startup 10 | { 11 | public async Task Invoke(int startingSalary) 12 | { 13 | var person = new Person(startingSalary); 14 | return new { 15 | getSalary = (Func>)( 16 | async (i) => 17 | { 18 | return person.Salary; 19 | } 20 | ), 21 | giveRaise = (Func>)( 22 | async (amount) => 23 | { 24 | person.GiveRaise((int)amount); 25 | return person.Salary; 26 | } 27 | ) 28 | }; 29 | } 30 | } 31 | 32 | public class Person 33 | { 34 | public int Salary { get; private set; } 35 | 36 | public Person(int startingSalary) 37 | { 38 | this.Salary = startingSalary; 39 | } 40 | 41 | public void GiveRaise(int amount) 42 | { 43 | this.Salary += amount; 44 | } 45 | } 46 | */}); 47 | 48 | var person = createPerson(120, true); 49 | console.log(person.getSalary(null, true)); 50 | console.log(person.giveRaise(20, true)); 51 | console.log(person.getSalary(null, true)); 52 | -------------------------------------------------------------------------------- /samples/111_clr_listener.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var createController = edge.func(function () {/* 6 | using System; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | public class Startup 11 | { 12 | static TaskCompletionSource tcs; 13 | 14 | public async Task Invoke(object input) 15 | { 16 | return new { 17 | yieldControl = (Func>)((i) => { 18 | return Startup.AcquireControl(); 19 | }), 20 | regainControl = (Func>)(async (i) => { 21 | Startup.ReleaseControl(); 22 | return null; 23 | }) 24 | }; 25 | } 26 | 27 | static Task AcquireControl() 28 | { 29 | // single threaded; always called on V8 thread 30 | 31 | if (tcs != null) 32 | { 33 | throw new InvalidOperationException("CLR already controls the lifetime of the process."); 34 | } 35 | 36 | TaskCompletionSource tmp = new TaskCompletionSource(); 37 | tcs = tmp; 38 | return tmp.Task; 39 | } 40 | 41 | public static void ReleaseControl() 42 | { 43 | // multi-threaded; can be called from V8 or one of many CLR threads 44 | 45 | TaskCompletionSource tmp = Interlocked.Exchange(ref tcs, null); 46 | if (tmp != null) 47 | { 48 | tmp.SetResult(null); 49 | } 50 | } 51 | } 52 | */}); 53 | 54 | // yield control over process lifetime to CLR 55 | var controller = createController(null, true); 56 | controller.yieldControl(); 57 | console.log('Control over process lifetime yielded to CLR, the process will not exit...'); 58 | 59 | // at this point, the process will not exit until one of the following happens: 60 | // - node.js calls controller.regainControl(), or 61 | // - CLR calls Startup.ReleaseControl() 62 | 63 | // controller.regainControl(); -------------------------------------------------------------------------------- /samples/201_worker.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var hello = edge.func(function () {/* 6 | async (input) => 7 | { 8 | // we are on V8 thread here 9 | 10 | return await Task.Run(async () => { 11 | 12 | // we are on CLR thread pool thread here 13 | 14 | // simulate long running operation 15 | await Task.Delay(5000); 16 | 17 | return ".NET welcomes " + input.ToString(); 18 | }); 19 | } 20 | */}); 21 | 22 | console.log('Starting CPU bound operation...'); 23 | hello('Node.js', function (error, result) { 24 | if (error) throw error; 25 | console.log(result); 26 | }); 27 | 28 | setInterval(function() { 29 | console.log('Node.js event loop is alive'); 30 | }, 1000); 31 | -------------------------------------------------------------------------------- /samples/202_sql.csx: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | //#r "System.dll" 4 | //#r "System.Data.dll" 5 | //#r "System.Web.Extensions.dll" 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Data; 10 | using System.Data.SqlClient; 11 | using System.IO; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | using System.Web.Script.Serialization; 15 | 16 | public class Startup 17 | { 18 | public async Task Invoke(string command) 19 | { 20 | string connectionString = Environment.GetEnvironmentVariable("OWIN_SQL_CONNECTION_STRING"); 21 | 22 | if (command.StartsWith("select ", StringComparison.InvariantCultureIgnoreCase)) 23 | { 24 | return await this.ExecuteQuery(connectionString, command); 25 | } 26 | else if (command.StartsWith("insert ", StringComparison.InvariantCultureIgnoreCase) 27 | || command.StartsWith("update ", StringComparison.InvariantCultureIgnoreCase) 28 | || command.StartsWith("delete ", StringComparison.InvariantCultureIgnoreCase)) 29 | { 30 | return await this.ExecuteNonQuery(connectionString, command); 31 | } 32 | else 33 | { 34 | throw new InvalidOperationException("Unsupported type of SQL command. Only select, insert, update, and delete are supported."); 35 | } 36 | } 37 | 38 | async Task ExecuteQuery(string connectionString, string commandString) 39 | { 40 | List rows = new List(); 41 | 42 | using (SqlConnection connection = new SqlConnection(connectionString)) 43 | { 44 | using (SqlCommand command = new SqlCommand(commandString, connection)) 45 | { 46 | await connection.OpenAsync(); 47 | using (SqlDataReader reader = await command.ExecuteReaderAsync(CommandBehavior.CloseConnection)) 48 | { 49 | object[] fieldNames = new object[reader.FieldCount]; 50 | for (int i = 0; i < reader.FieldCount; i++) 51 | { 52 | fieldNames[i] = reader.GetName(i); 53 | } 54 | rows.Add(fieldNames); 55 | 56 | IDataRecord record = (IDataRecord)reader; 57 | while (await reader.ReadAsync()) 58 | { 59 | object[] resultRecord = new object[record.FieldCount]; 60 | record.GetValues(resultRecord); 61 | for (int i = 0; i < record.FieldCount; i++) 62 | { 63 | Type type = record.GetFieldType(i); 64 | if (type == typeof(byte[]) || type == typeof(char[])) 65 | { 66 | resultRecord[i] = Convert.ToBase64String((byte[])resultRecord[i]); 67 | } 68 | else if (type == typeof(Guid) || type == typeof(DateTime)) 69 | { 70 | resultRecord[i] = resultRecord[i].ToString(); 71 | } 72 | else if (type == typeof(IDataReader)) 73 | { 74 | resultRecord[i] = ""; 75 | } 76 | } 77 | 78 | rows.Add(resultRecord); 79 | } 80 | } 81 | } 82 | } 83 | 84 | return rows; 85 | } 86 | 87 | async Task ExecuteNonQuery(string connectionString, string commandString) 88 | { 89 | using (SqlConnection connection = new SqlConnection(connectionString)) 90 | { 91 | using (SqlCommand command = new SqlCommand(commandString, connection)) 92 | { 93 | await connection.OpenAsync(); 94 | return await command.ExecuteNonQueryAsync(); 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /samples/202_sql.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var sql = edge.func('202_sql.csx'); 6 | 7 | sql('select top 2 * from Products', function (error, result) { 8 | if (error) throw error; 9 | console.log(result); 10 | }); 11 | -------------------------------------------------------------------------------- /samples/203_x509store.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var listCertificates = edge.func(function() {/* 6 | #r "System.dll" 7 | 8 | using System.Collections.Generic; 9 | using System.Security.Cryptography.X509Certificates; 10 | 11 | async (dynamic data) => 12 | { 13 | X509Store store = new X509Store( 14 | (string)data.storeName, 15 | (StoreLocation)Enum.Parse(typeof(StoreLocation), (string)data.storeLocation)); 16 | store.Open(OpenFlags.ReadOnly); 17 | try 18 | { 19 | List result = new List(); 20 | foreach (X509Certificate2 certificate in store.Certificates) 21 | { 22 | result.Add(certificate.Subject); 23 | } 24 | 25 | return result; 26 | } 27 | finally 28 | { 29 | store.Close(); 30 | } 31 | } 32 | */}); 33 | 34 | var result = listCertificates({ storeName: 'My', storeLocation: 'LocalMachine' }, true); 35 | console.log(result); 36 | -------------------------------------------------------------------------------- /samples/204_event_log.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var writeEventLog = edge.func(function() {/* 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | 9 | async (dynamic parameters) => 10 | { 11 | var source = (string)parameters.source; 12 | var log = (string)parameters.log; 13 | if (!EventLog.SourceExists(source)) 14 | { 15 | EventLog.CreateEventSource(source, log); 16 | } 17 | 18 | EventLog.WriteEntry( 19 | source, 20 | (string)parameters.message, 21 | (EventLogEntryType)Enum.Parse( 22 | typeof(EventLogEntryType), (string)parameters.type), 23 | (int)parameters.id 24 | ); 25 | 26 | return null; 27 | } 28 | */}); 29 | 30 | writeEventLog({ 31 | source: 'Edge.js sample application', 32 | log: 'Application', 33 | type: 'Information', 34 | message: 'Hello from node.js. The time is ' + new Date(), 35 | id: 31415 36 | }, true); 37 | 38 | console.log('Success. Check EventViewer.'); 39 | -------------------------------------------------------------------------------- /samples/205_soap.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var convertKilograms = edge.func('205_soap.csx'); 6 | 7 | convertKilograms(123, function (error, result) { 8 | if (error) throw error; 9 | console.log(result); 10 | }); 11 | -------------------------------------------------------------------------------- /samples/206_registry_read.js: -------------------------------------------------------------------------------- 1 | var edge = require('../lib/edge'); 2 | 3 | var readRegistery = edge.func(function () {/* 4 | using Microsoft.Win32; 5 | 6 | async (dynamic input) => 7 | { 8 | return Registry.GetValue((string) input.keyName, (string) input.valueName, null); 9 | } 10 | */}); 11 | 12 | readRegistery({ 13 | keyName: 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MSBuild\\4.0', 14 | valueName: 'MSBuildOverrideTasksPath' 15 | }, function (err, result) { 16 | if (err) { 17 | throw err; 18 | } 19 | 20 | console.log(result); 21 | }); -------------------------------------------------------------------------------- /samples/206_registry_write.js: -------------------------------------------------------------------------------- 1 | var edge = require('../lib/edge'); 2 | 3 | var writeRegistery = edge.func(function () {/* 4 | using Microsoft.Win32; 5 | 6 | async (dynamic input) => 7 | { 8 | Registry.SetValue((string)input.keyName, (string)input.valueName, input.value); 9 | return null; 10 | } 11 | */}); 12 | 13 | writeRegistery({ 14 | keyName: 'HKEY_CURRENT_USER\\Environment', 15 | valueName: 'MyCustomValue', 16 | value: 1050 17 | }, function (err) { 18 | if (err) { 19 | throw err; 20 | } 21 | 22 | console.log('Done!'); 23 | }); -------------------------------------------------------------------------------- /samples/207_unzip.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge') 4 | , path = require('path'); 5 | 6 | var unzipDirectory = edge.func(function() {/* 7 | #r "System.IO.Compression.FileSystem.dll" 8 | 9 | using System.IO.Compression; 10 | 11 | async (dynamic input) => 12 | { 13 | await Task.Run(async () => { 14 | ZipFile.ExtractToDirectory((string)input.source, (string)input.destination); 15 | }); 16 | 17 | return null; 18 | } 19 | */}); 20 | 21 | var params = { 22 | source: path.join(__dirname, '..', 'samples.zip'), 23 | destination: path.join(__dirname, '..', 'samples_tmp') 24 | }; 25 | 26 | unzipDirectory(params, function (error) { 27 | if (error) throw error; 28 | console.log('The ..\\samples.zip archive has been decompressed to ..\\samples_tmp directory.'); 29 | }); 30 | -------------------------------------------------------------------------------- /samples/207_zip.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge') 4 | , path = require('path'); 5 | 6 | var zipDirectory = edge.func(function() {/* 7 | #r "System.IO.Compression.FileSystem.dll" 8 | 9 | using System.IO.Compression; 10 | 11 | async (dynamic input) => 12 | { 13 | await Task.Run(async () => { 14 | ZipFile.CreateFromDirectory((string)input.source, (string)input.destination); 15 | }); 16 | 17 | return null; 18 | } 19 | */}); 20 | 21 | var params = { 22 | source: path.join(__dirname, '..', 'samples'), 23 | destination: path.join(__dirname, '..', 'samples.zip') 24 | }; 25 | 26 | zipDirectory(params, function (error) { 27 | if (error) throw error; 28 | console.log('The samples directory has been compressed to ..\\samples.zip file.'); 29 | }); 30 | -------------------------------------------------------------------------------- /samples/208_convertImage.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge') 4 | , path = require('path'); 5 | 6 | var convertImage = edge.func(function() {/* 7 | #r "System.Drawing.dll" 8 | 9 | using System; 10 | using System.Threading.Tasks; 11 | using System.Collections.Generic; 12 | using System.Drawing; 13 | using System.Drawing.Imaging; 14 | 15 | class Startup 16 | { 17 | static IDictionary formats = new Dictionary 18 | { 19 | { "jpg", ImageFormat.Jpeg }, 20 | { "bmp", ImageFormat.Bmp }, 21 | { "gif", ImageFormat.Gif }, 22 | { "tiff", ImageFormat.Tiff }, 23 | { "png", ImageFormat.Png } 24 | }; 25 | 26 | public async Task Invoke(IDictionary input) 27 | { 28 | await Task.Run(async () => { 29 | using (Image image = Image.FromFile((string)input["source"])) 30 | { 31 | image.Save((string)input["destination"], formats[(string)input["toType"]]); 32 | } 33 | }); 34 | 35 | return null; 36 | } 37 | } 38 | */}); 39 | 40 | var params = { 41 | source: path.join(__dirname, 'edge.png'), 42 | destination: path.join(__dirname, 'edge.jpg'), 43 | toType: 'jpg' 44 | }; 45 | 46 | convertImage(params, function (error) { 47 | if (error) throw error; 48 | console.log('The edge.png has been asynchronously converted to edge.jpg.'); 49 | }); 50 | -------------------------------------------------------------------------------- /samples/210_windows_authentication.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge') 4 | , http = require('http'); 5 | 6 | var authenticate = edge.func(function() {/* 7 | using System; 8 | using System.Threading.Tasks; 9 | using System.Runtime.InteropServices; 10 | using System.Security.Principal; 11 | 12 | class Startup 13 | { 14 | 15 | [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 16 | public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, 17 | int dwLogonType, int dwLogonProvider, out IntPtr phToken); 18 | 19 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 20 | public extern static bool CloseHandle(IntPtr handle); 21 | 22 | public async Task Invoke(dynamic input) 23 | { 24 | return await Task.Run(() => { 25 | IntPtr token; 26 | if (!Startup.LogonUser(input.user, null, input.password, 3, 0, out token)) 27 | { 28 | throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); 29 | } 30 | 31 | try { 32 | using (WindowsIdentity id = new WindowsIdentity(token)) 33 | { 34 | return new { 35 | name = id.Name, 36 | sid = id.User.ToString() 37 | }; 38 | } 39 | } 40 | finally { 41 | Startup.CloseHandle(token); 42 | } 43 | }); 44 | } 45 | } 46 | */}); 47 | 48 | http.createServer(function (req, res) { 49 | function challange() { 50 | res.writeHead(401, { 'WWW-Authenticate': 'Basic realm=""' }); 51 | res.end(); 52 | } 53 | 54 | if (req.headers.authorization && req.headers.authorization.indexOf('Basic ') === 0) { 55 | var tokens = new Buffer(req.headers.authorization.substring(6), 'base64').toString('utf8').split(':'); 56 | if (!tokens || tokens.length !== 2 || tokens[0] === 'noone' && tokens[1] === 'noone') { 57 | challange(); 58 | } 59 | else { 60 | authenticate({ user: tokens[0], password: tokens[1] }, function (error, result) { 61 | if (error) { 62 | console.log(error); 63 | challange(); 64 | } 65 | else { 66 | res.writeHead(200, { 'Content-Type': 'text/html' }); 67 | res.write('

Welcome ' + result.name + ' (' + result.sid + ')'); 68 | res.end('

Logout'); 69 | } 70 | }) 71 | } 72 | } 73 | else { 74 | challange(); 75 | } 76 | }).listen(process.env.PORT || 8080); 77 | -------------------------------------------------------------------------------- /samples/211_events.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge'); 4 | 5 | var subscribe = edge.func(function() {/* 6 | async (dynamic input) => 7 | { 8 | // Create a timer with the specifed interval. 9 | // Conceptually this can be any event source. 10 | 11 | var timer = new System.Timers.Timer(input.interval); 12 | 13 | // Hook up the Elapsed event for the timer and delegate 14 | // the call to a Node.js event handler. 15 | // Depending on the EventArgs, the data may need to be transformed 16 | // if it cannot be directly marshaled by Edge.js. 17 | 18 | timer.Elapsed += (Object source, System.Timers.ElapsedEventArgs e) => { 19 | ((Func>)input.event_handler)(e).Start(); 20 | }; 21 | 22 | // Start the timer 23 | 24 | timer.Enabled = true; 25 | 26 | // Return a function that can be used by Node.js to 27 | // unsubscribe from the event source. 28 | 29 | return (Func>)(async (dynamic data) => { 30 | timer.Enabled = false; 31 | return null; 32 | }); 33 | } 34 | */}); 35 | 36 | subscribe({ 37 | interval: 2000, 38 | event_handler: function (data, cb) { 39 | console.log('Received event', data); 40 | cb(); 41 | } 42 | }, function (error, unsubscribe) { 43 | if (error) throw error; 44 | console.log('Subscribed to .NET events. Unsubscribing in 7 seconds...'); 45 | setTimeout(function () { 46 | unsubscribe(null, function (error) { 47 | if (error) throw error; 48 | console.log('Unsubscribed from .NET events.'); 49 | console.log('Waiting 5 seconds before exit to show that no more events are generated...') 50 | setTimeout(function () {}, 5000); 51 | }); 52 | }, 7000); 53 | }); 54 | -------------------------------------------------------------------------------- /samples/301_cspyfsps.js: -------------------------------------------------------------------------------- 1 | // Overview of edge.js: http://tjanczuk.github.com/edge 2 | 3 | var edge = require('../lib/edge') 4 | , async = require('async'); 5 | 6 | var helloCs = edge.func(function () {/* 7 | async (input) => 8 | { 9 | return "C# welcomes " + input.ToString(); 10 | } 11 | */}); 12 | 13 | var helloPy = edge.func('py', function () {/* 14 | def hello(input): 15 | return "Python welcomes " + input 16 | 17 | lambda x: hello(x) 18 | */}); 19 | 20 | var helloFs = edge.func('fs', function () {/* 21 | fun input -> async { 22 | return "F# welcomes " + input.ToString() 23 | } 24 | */}); 25 | 26 | var helloPs = edge.func('ps', function () {/* 27 | "PowerShell welcomes $inputFromJS" 28 | */}); 29 | 30 | async.waterfall([ 31 | function (cb) { cb(null, 'Node.js'); }, 32 | 33 | helloFs, 34 | helloCs, 35 | helloPy, 36 | helloPs 37 | ], function (error, result) { 38 | console.log(error || result[0]); 39 | }); -------------------------------------------------------------------------------- /samples/Sample105.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Sample105 4 | { 5 | public class Startup 6 | { 7 | public async Task Invoke(object input) 8 | { 9 | return this.Add7((int)input); 10 | } 11 | 12 | int Add7(int v) 13 | { 14 | return Helper.Add7(v); 15 | } 16 | } 17 | 18 | static class Helper 19 | { 20 | public static int Add7(int v) 21 | { 22 | return v + 7; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /samples/edge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kexplo/electron-edge/a5e0e29baea6a0eac1c7a9b51e696fb3c43368c6/samples/edge.png -------------------------------------------------------------------------------- /samples/readme.txt: -------------------------------------------------------------------------------- 1 | Foundations: 2 | 3 | 101_hello_lambda.js - prescriptive interface pattern 4 | 102_hello_function.js - multiline function comment 5 | 103_hello_file.js - separate file 6 | 104_add7_class.js - entire class instead of lambda 7 | 105_add7_dll.js - pre-compiled DLL 8 | On Windows: 9 | csc.exe /target:library /debug Sample105.cs 10 | On Mono (MacOS, Linux): 11 | mcs -sdk:4.5 Sample105.cs -target:library 12 | start repl, attach VS, call func, show debugging 13 | 106_marshal_v82cls.js - data from V8 to CLR 14 | 107_marshal_clr2v8.js - data from CLR to V8 15 | 108_func.js - marshal func from v8 to CLR and call node from .NET 16 | 109_sync.js - async and sync calling conventions 17 | 18 | Scenarios: 19 | 20 | 201_worker.js - CPU bound operation 21 | 202_sql.js - access SQL with async ADO.NET 22 | set OWIN_SQL_CONNECTION_STRING=Data Source=localhost;Initial Catalog=Northwind;Integrated Security=True 23 | reference assemblies 24 | 206_registery - read/write registery operations 25 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/coreclrfuncinvokecontext.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | CoreClrFuncInvokeContext::CoreClrFuncInvokeContext(v8::Local callback, void* task) : task(task), uv_edge_async(NULL), resultData(NULL), resultType(0) 4 | { 5 | DBG("CoreClrFuncInvokeContext::CoreClrFuncInvokeContext"); 6 | 7 | this->callback = new Nan::Persistent(); 8 | v8::Local callbackFunction = v8::Local::Cast(callback); 9 | this->callback->Reset(callbackFunction); 10 | } 11 | 12 | CoreClrFuncInvokeContext::~CoreClrFuncInvokeContext() 13 | { 14 | DBG("CoreClrFuncInvokeContext::~CoreClrFuncInvokeContext"); 15 | 16 | if (this->callback) 17 | { 18 | this->callback->Reset(); 19 | delete this->callback; 20 | this->callback = NULL; 21 | } 22 | 23 | if (this->task) 24 | { 25 | CoreClrEmbedding::FreeHandle(this->task); 26 | this->task = NULL; 27 | } 28 | 29 | if (this->resultData) 30 | { 31 | CoreClrEmbedding::FreeMarshalData(this->resultData, this->resultType); 32 | this->resultData = NULL; 33 | } 34 | } 35 | 36 | void CoreClrFuncInvokeContext::InitializeAsyncOperation() 37 | { 38 | DBG("CoreClrFuncInvokeContext::InitializeAsyncOperation"); 39 | this->uv_edge_async = V8SynchronizationContext::RegisterAction(CoreClrFuncInvokeContext::InvokeCallback, this); 40 | } 41 | 42 | void CoreClrFuncInvokeContext::TaskComplete(void* result, int resultType, int taskState, CoreClrFuncInvokeContext* context) 43 | { 44 | DBG("CoreClrFuncInvokeContext::TaskComplete"); 45 | 46 | context->resultData = result; 47 | context->resultType = resultType; 48 | context->taskState = taskState; 49 | 50 | V8SynchronizationContext::ExecuteAction(context->uv_edge_async); 51 | } 52 | 53 | void CoreClrFuncInvokeContext::TaskCompleteSynchronous(void* result, int resultType, int taskState, v8::Local callback) 54 | { 55 | DBG("CoreClrFuncInvokeContext::TaskCompleteSynchronous"); 56 | 57 | CoreClrFuncInvokeContext* context = new CoreClrFuncInvokeContext(callback, NULL); 58 | 59 | context->resultData = result; 60 | context->resultType = resultType; 61 | context->taskState = taskState; 62 | 63 | InvokeCallback(context); 64 | } 65 | 66 | void CoreClrFuncInvokeContext::InvokeCallback(void* data) 67 | { 68 | DBG("CoreClrFuncInvokeContext::InvokeCallback"); 69 | 70 | CoreClrFuncInvokeContext* context = (CoreClrFuncInvokeContext*)data; 71 | v8::Local callbackData = Nan::Null(); 72 | v8::Local errors = Nan::Null(); 73 | 74 | if (context->taskState == TaskStatusFaulted) 75 | { 76 | errors = CoreClrFunc::MarshalCLRToV8(context->resultData, context->resultType); 77 | } 78 | 79 | else 80 | { 81 | callbackData = CoreClrFunc::MarshalCLRToV8(context->resultData, context->resultType); 82 | } 83 | 84 | DBG("CoreClrFuncInvokeContext::InvokeCallback - Marshalling complete"); 85 | 86 | v8::Local argv[] = { errors, callbackData }; 87 | int argc = 2; 88 | 89 | Nan::TryCatch tryCatch; 90 | Nan::New(*(context->callback))->Call(Nan::GetCurrentContext()->Global(), argc, argv); 91 | 92 | DBG("CoreClrFuncInvokeContext::InvokeCallback - Callback function invoked"); 93 | delete context; 94 | 95 | if (tryCatch.HasCaught()) 96 | { 97 | Nan::FatalException(tryCatch); 98 | } 99 | 100 | DBG("CoreClrFuncInvokeContext::InvokeCallback - Complete"); 101 | } 102 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/coreclrnodejsfunc.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | CoreClrNodejsFunc::CoreClrNodejsFunc(v8::Local function) 4 | { 5 | DBG("CoreClrNodejsFunc::CoreClrNodejsFunc"); 6 | 7 | this->Func = new Nan::Persistent; 8 | this->Func->Reset(function); 9 | } 10 | 11 | CoreClrNodejsFunc::~CoreClrNodejsFunc() 12 | { 13 | DBG("CoreClrNodejsFunc::~CoreClrNodejsFunc"); 14 | this->Func->Reset(); 15 | delete this->Func; 16 | this->Func = NULL; 17 | } 18 | 19 | void CoreClrNodejsFunc::Release(CoreClrNodejsFunc* function) 20 | { 21 | DBG("CoreClrNodejsFunc::Release"); 22 | delete function; 23 | } 24 | 25 | void CoreClrNodejsFunc::Call(void* payload, int payloadType, CoreClrNodejsFunc* functionContext, CoreClrGcHandle callbackContext, NodejsFuncCompleteFunction callbackFunction) 26 | { 27 | DBG("CoreClrNodejsFunc::Call"); 28 | 29 | CoreClrNodejsFuncInvokeContext* invokeContext = new CoreClrNodejsFuncInvokeContext(payload, payloadType, functionContext, callbackContext, callbackFunction); 30 | invokeContext->Invoke(); 31 | } 32 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/coreclrnodejsfuncinvokecontext.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | NAN_METHOD(coreClrV8FuncCallback) 4 | { 5 | DBG("coreClrV8FuncCallback"); 6 | 7 | Nan::HandleScope scope; 8 | v8::Local correlator = v8::Local::Cast(info[2]); 9 | CoreClrNodejsFuncInvokeContext* context = (CoreClrNodejsFuncInvokeContext*)(correlator->Value()); 10 | 11 | if (!info[0]->IsUndefined() && !info[0]->IsNull()) 12 | { 13 | void* clrExceptionData; 14 | CoreClrFunc::MarshalV8ExceptionToCLR(info[0], &clrExceptionData); 15 | 16 | context->Complete(TaskStatusFaulted, clrExceptionData, V8TypeException); 17 | } 18 | 19 | else 20 | { 21 | void* marshalData; 22 | int payloadType; 23 | 24 | CoreClrFunc::MarshalV8ToCLR(info[1], &marshalData, &payloadType); 25 | context->Complete(TaskStatusRanToCompletion, marshalData, payloadType); 26 | } 27 | 28 | info.GetReturnValue().SetUndefined(); 29 | } 30 | 31 | CoreClrNodejsFuncInvokeContext::CoreClrNodejsFuncInvokeContext(void* payload, int payloadType, CoreClrNodejsFunc* functionContext, CoreClrGcHandle callbackContext, NodejsFuncCompleteFunction callbackFunction) 32 | { 33 | DBG("CoreClrNodejsFuncInvokeContext::CoreClrNodejsFuncInvokeContext"); 34 | 35 | uv_edge_async = NULL; 36 | Payload = payload; 37 | PayloadType = payloadType; 38 | FunctionContext = functionContext; 39 | CallbackContext = callbackContext; 40 | CallbackFunction = callbackFunction; 41 | } 42 | 43 | CoreClrNodejsFuncInvokeContext::~CoreClrNodejsFuncInvokeContext() 44 | { 45 | if (uv_edge_async) 46 | { 47 | delete uv_edge_async; 48 | } 49 | 50 | if (Payload) 51 | { 52 | CoreClrFunc::FreeMarshalData(Payload, PayloadType); 53 | } 54 | } 55 | 56 | void CoreClrNodejsFuncInvokeContext::Complete(TaskStatus taskStatus, void* result, int resultType) 57 | { 58 | DBG("CoreClrNodejsFuncInvokeContext::Complete"); 59 | CallbackFunction(CallbackContext, taskStatus, result, resultType); 60 | } 61 | 62 | void CoreClrNodejsFuncInvokeContext::Invoke() 63 | { 64 | this->uv_edge_async = V8SynchronizationContext::RegisterAction(CoreClrNodejsFuncInvokeContext::InvokeCallback, this); 65 | V8SynchronizationContext::ExecuteAction(uv_edge_async); 66 | } 67 | 68 | void CoreClrNodejsFuncInvokeContext::InvokeCallback(void* data) 69 | { 70 | DBG("CoreClrNodejsFuncInvokeContext::InvokeCallback"); 71 | 72 | CoreClrNodejsFuncInvokeContext* context = (CoreClrNodejsFuncInvokeContext*) data; 73 | v8::Local v8Payload = CoreClrFunc::MarshalCLRToV8(context->Payload, context->PayloadType); 74 | 75 | static Nan::Persistent callbackFactory; 76 | static Nan::Persistent callbackFunction; 77 | 78 | Nan::HandleScope scope; 79 | 80 | // See https://github.com/tjanczuk/edge/issues/125 for context 81 | if (callbackFactory.IsEmpty()) 82 | { 83 | v8::Local v8FuncCallbackFunction = Nan::New(coreClrV8FuncCallback)->GetFunction(); 84 | callbackFunction.Reset(v8FuncCallbackFunction); 85 | v8::Local code = Nan::New( 86 | "(function (cb, ctx) { return function (e, d) { return cb(e, d, ctx); }; })").ToLocalChecked(); 87 | v8::Local callbackFactoryFunction = v8::Local::Cast(v8::Script::Compile(code)->Run()); 88 | callbackFactory.Reset(callbackFactoryFunction); 89 | } 90 | 91 | v8::Local factoryArgv[] = { Nan::New(callbackFunction), Nan::New((void*)context) }; 92 | v8::Local callback = v8::Local::Cast( 93 | Nan::New(callbackFactory)->Call(Nan::GetCurrentContext()->Global(), 2, factoryArgv)); 94 | 95 | v8::Local argv[] = { v8Payload, callback }; 96 | TryCatch tryCatch; 97 | 98 | DBG("CoreClrNodejsFuncInvokeContext::InvokeCallback - Calling JavaScript function"); 99 | Nan::New(*(context->FunctionContext->Func))->Call(Nan::GetCurrentContext()->Global(), 2, argv); 100 | DBG("CoreClrNodejsFuncInvokeContext::InvokeCallback - Called JavaScript function"); 101 | 102 | if (tryCatch.HasCaught()) 103 | { 104 | DBG("CoreClrNodejsFuncInvokeContext::InvokeCallback - Caught JavaScript exception"); 105 | 106 | void* exceptionData; 107 | CoreClrFunc::MarshalV8ExceptionToCLR(tryCatch.Exception(), &exceptionData); 108 | 109 | DBG("CoreClrNodejsFuncInvokeContext::InvokeCallback - Exception message is: %s", (char*)exceptionData); 110 | 111 | context->Complete(TaskStatusFaulted, exceptionData, V8TypeException); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/deps/deps_entry.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef __DEPS_ENTRY_H_ 5 | #define __DEPS_ENTRY_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "../pal/pal.h" 11 | 12 | struct deps_entry_t 13 | { 14 | enum asset_types 15 | { 16 | runtime = 0, 17 | resources, 18 | native, 19 | count 20 | }; 21 | 22 | static const std::array s_known_asset_types; 23 | 24 | pal::string_t library_type; 25 | pal::string_t library_name; 26 | pal::string_t library_version; 27 | pal::string_t library_hash; 28 | asset_types asset_type; 29 | pal::string_t asset_name; 30 | pal::string_t relative_path; 31 | bool is_serviceable; 32 | bool is_rid_specific; 33 | 34 | 35 | // Given a "base" dir, yield the filepath within this directory or relative to this directory based on "look_in_base" 36 | bool to_path(const pal::string_t& base, bool look_in_base, pal::string_t* str) const; 37 | 38 | // Given a "base" dir, yield the file path within this directory. 39 | bool to_dir_path(const pal::string_t& base, pal::string_t* str) const; 40 | 41 | // Given a "base" dir, yield the relative path in the package layout. 42 | bool to_rel_path(const pal::string_t& base, pal::string_t* str) const; 43 | 44 | // Given a "base" dir, yield the relative path with package name, version in the package layout. 45 | bool to_full_path(const pal::string_t& root, pal::string_t* str) const; 46 | 47 | // Given a "base" dir, yield the relative path with package name, version in the package layout only if 48 | // the hash matches contents of the hash file. 49 | bool to_hash_matched_path(const pal::string_t& root, pal::string_t* str) const; 50 | }; 51 | 52 | #endif // __DEPS_ENTRY_H_ 53 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/deps/deps_format.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef __DEPS_FORMAT_H_ 5 | #define __DEPS_FORMAT_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "../pal/pal.h" 12 | #include "deps_entry.h" 13 | #include "cpprest/json.h" 14 | 15 | void set_own_rid(pal::string_t set_rid); 16 | 17 | class deps_json_t 18 | { 19 | typedef web::json::value json_value; 20 | struct vec_t { std::vector vec; }; 21 | struct assets_t { std::array by_type; }; 22 | struct deps_assets_t { std::unordered_map libs; }; 23 | struct rid_assets_t { std::unordered_map rid_assets; }; 24 | struct rid_specific_assets_t { std::unordered_map libs; }; 25 | 26 | typedef std::unordered_map> str_to_vector_map_t; 27 | typedef str_to_vector_map_t rid_fallback_graph_t; 28 | 29 | 30 | public: 31 | deps_json_t() 32 | : m_valid(false) 33 | , m_file_exists(false) 34 | { 35 | } 36 | 37 | deps_json_t(bool portable, const pal::string_t& deps_path) 38 | : deps_json_t(portable, deps_path, m_rid_fallback_graph /* dummy */) 39 | { 40 | } 41 | 42 | deps_json_t(bool portable, const pal::string_t& deps_path, const rid_fallback_graph_t& graph) 43 | : deps_json_t() 44 | { 45 | m_valid = load(portable, deps_path, graph); 46 | } 47 | 48 | const std::vector& get_entries(deps_entry_t::asset_types type) 49 | { 50 | assert(type < deps_entry_t::asset_types::count); 51 | return m_deps_entries[type]; 52 | } 53 | 54 | bool has_package(const pal::string_t& name, const pal::string_t& ver) const; 55 | 56 | bool exists() 57 | { 58 | return m_file_exists; 59 | } 60 | 61 | bool is_valid() 62 | { 63 | return m_valid; 64 | } 65 | 66 | const rid_fallback_graph_t& get_rid_fallback_graph() 67 | { 68 | return m_rid_fallback_graph; 69 | } 70 | 71 | const deps_entry_t& try_ni(const deps_entry_t& entry) const; 72 | 73 | private: 74 | bool load_standalone(const json_value& json, const pal::string_t& target_name); 75 | bool load_portable(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph); 76 | bool load(bool portable, const pal::string_t& deps_path, const rid_fallback_graph_t& rid_fallback_graph); 77 | bool process_runtime_targets(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph, rid_specific_assets_t* p_assets); 78 | bool process_targets(const json_value& json, const pal::string_t& target_name, deps_assets_t* p_assets); 79 | 80 | void reconcile_libraries_with_targets( 81 | const json_value& json, 82 | const std::function& library_exists_fn, 83 | const std::function&(const pal::string_t&, int, bool*)>& get_rel_paths_by_asset_type_fn); 84 | 85 | bool perform_rid_fallback(rid_specific_assets_t* portable_assets, const rid_fallback_graph_t& rid_fallback_graph); 86 | 87 | std::vector m_deps_entries[deps_entry_t::asset_types::count]; 88 | 89 | deps_assets_t m_assets; 90 | rid_specific_assets_t m_rid_assets; 91 | 92 | std::unordered_map m_ni_entries; 93 | rid_fallback_graph_t m_rid_fallback_graph; 94 | bool m_file_exists; 95 | bool m_valid; 96 | }; 97 | 98 | #endif // __DEPS_FORMAT_H_ 99 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/fxr/fx_muxer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | class corehost_init_t; 5 | class runtime_config_t; 6 | struct fx_ver_t; 7 | 8 | #include "../host/libhost.h" 9 | 10 | int execute_app( 11 | const pal::string_t& impl_dll_dir, 12 | corehost_init_t* init, 13 | const int argc, 14 | const pal::char_t* argv[]); 15 | 16 | class fx_muxer_t 17 | { 18 | public: 19 | static int execute(const int argc, const pal::char_t* argv[]); 20 | static pal::string_t resolve_fx_dir(host_mode_t mode, const pal::string_t& own_dir, const runtime_config_t& config, const pal::string_t& specified_fx_version); 21 | static bool resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk); 22 | private: 23 | static int read_config_and_execute( 24 | const pal::string_t& own_dir, 25 | const pal::string_t& app_candidate, 26 | const std::unordered_map>& opts, 27 | int new_argc, const pal::char_t** new_argv, host_mode_t mode); 28 | static int parse_args_and_execute(const pal::string_t& own_dir, const pal::string_t& own_dll, int argoff, int argc, const pal::char_t* argv[], bool exec_mode, host_mode_t mode, bool* can_execute); 29 | static bool resolve_hostpolicy_dir(host_mode_t mode, 30 | const pal::string_t& own_dir, 31 | const pal::string_t& fx_dir, 32 | const pal::string_t& app_or_deps_dir, 33 | const pal::string_t& specified_deps_file, 34 | const pal::string_t& specified_fx_version, 35 | const std::vector& probe_realpaths, 36 | const runtime_config_t& config, 37 | pal::string_t* impl_dir); 38 | static pal::string_t resolve_cli_version(const pal::string_t& global); 39 | }; 40 | 41 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/fxr/fx_ver.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef __FX_VER_H__ 5 | #define __FX_VER_H__ 6 | 7 | #include "../pal/pal.h" 8 | 9 | // Note: This is not SemVer (esp., in comparing pre-release part, fx_ver_t does not 10 | // compare multiple dot separated identifiers individually.) ex: 1.0.0-beta.2 vs. 1.0.0-beta.11 11 | struct fx_ver_t 12 | { 13 | fx_ver_t(int major, int minor, int patch); 14 | fx_ver_t(int major, int minor, int patch, const pal::string_t& pre); 15 | fx_ver_t(int major, int minor, int patch, const pal::string_t& pre, const pal::string_t& build); 16 | 17 | int get_major() const { return m_major; } 18 | int get_minor() const { return m_minor; } 19 | int get_patch() const { return m_patch; } 20 | 21 | void set_major(int m) { m_major = m; } 22 | void set_minor(int m) { m_minor = m; } 23 | void set_patch(int p) { m_patch = p; } 24 | 25 | bool is_prerelease() const { return !m_pre.empty(); } 26 | 27 | pal::string_t as_str() const; 28 | pal::string_t prerelease_glob() const; 29 | pal::string_t patch_glob() const; 30 | 31 | bool operator ==(const fx_ver_t& b) const; 32 | bool operator !=(const fx_ver_t& b) const; 33 | bool operator <(const fx_ver_t& b) const; 34 | bool operator >(const fx_ver_t& b) const; 35 | 36 | static bool parse(const pal::string_t& ver, fx_ver_t* fx_ver, bool parse_only_production = false); 37 | 38 | private: 39 | int m_major; 40 | int m_minor; 41 | int m_patch; 42 | pal::string_t m_pre; 43 | pal::string_t m_build; 44 | 45 | static int compare(const fx_ver_t&a, const fx_ver_t& b); 46 | }; 47 | 48 | #endif // __FX_VER_H__ -------------------------------------------------------------------------------- /src/CoreCLREmbedding/host/args.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include "args.h" 5 | #include "../pal/pal_utils.h" 6 | #include "coreclr.h" 7 | #include "libhost.h" 8 | 9 | arguments_t::arguments_t() : 10 | managed_application(_X("")), 11 | own_path(_X("")), 12 | app_dir(_X("")), 13 | app_argc(0), 14 | app_argv(nullptr), 15 | dotnet_packages_cache(_X("")), 16 | core_servicing(_X("")), 17 | deps_path(_X("")) 18 | { 19 | } 20 | 21 | bool parse_arguments( 22 | const pal::string_t& deps_path, 23 | const std::vector& probe_paths, 24 | host_mode_t mode, 25 | const int argc, const pal::char_t* argv[], arguments_t* arg_out) 26 | { 27 | arguments_t& args = *arg_out; 28 | // Get the full name of the application 29 | if (!pal::get_own_executable_path(&args.own_path) || !pal::realpath(&args.own_path)) 30 | { 31 | trace::error(_X("Failed to resolve full path of the current executable [%s]"), args.own_path.c_str()); 32 | return false; 33 | } 34 | 35 | auto own_name = get_filename(args.own_path); 36 | auto own_dir = get_directory(args.own_path); 37 | 38 | if (mode != host_mode_t::standalone) 39 | { 40 | // corerun mode. First argument is managed app 41 | if (argc < 2) 42 | { 43 | return false; 44 | } 45 | args.managed_application = pal::string_t(argv[1]); 46 | if (!pal::realpath(&args.managed_application)) 47 | { 48 | trace::error(_X("Failed to locate managed application [%s]"), args.managed_application.c_str()); 49 | return false; 50 | } 51 | args.app_dir = get_directory(args.managed_application); 52 | args.app_argc = argc - 2; 53 | args.app_argv = &argv[2]; 54 | } 55 | else 56 | { 57 | // coreconsole mode. Find the managed app in the same directory 58 | pal::string_t managed_app(own_dir); 59 | managed_app.push_back(DIR_SEPARATOR); 60 | managed_app.append(get_executable(own_name)); 61 | managed_app.append(_X(".dll")); 62 | args.managed_application = managed_app; 63 | if (!pal::realpath(&args.managed_application)) 64 | { 65 | trace::error(_X("Failed to locate managed application [%s]"), args.managed_application.c_str()); 66 | return false; 67 | } 68 | args.app_dir = own_dir; 69 | args.app_argv = &argv[1]; 70 | args.app_argc = argc - 1; 71 | } 72 | 73 | if (!deps_path.empty()) 74 | { 75 | args.deps_path = deps_path; 76 | args.app_dir = get_directory(args.deps_path); 77 | } 78 | 79 | for (const auto& probe : probe_paths) 80 | { 81 | args.probe_paths.push_back(probe); 82 | } 83 | 84 | if (args.deps_path.empty()) 85 | { 86 | const auto& app_base = args.app_dir; 87 | auto app_name = get_filename(args.managed_application); 88 | 89 | args.deps_path.reserve(app_base.length() + 1 + app_name.length() + 5); 90 | args.deps_path.append(app_base); 91 | args.deps_path.push_back(DIR_SEPARATOR); 92 | args.deps_path.append(app_name, 0, app_name.find_last_of(_X("."))); 93 | args.deps_path.append(_X(".deps.json")); 94 | } 95 | 96 | pal::getenv(_X("DOTNET_HOSTING_OPTIMIZATION_CACHE"), &args.dotnet_packages_cache); 97 | pal::get_default_servicing_directory(&args.core_servicing); 98 | 99 | return true; 100 | } 101 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/host/args.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef ARGS_H 5 | #define ARGS_H 6 | 7 | #include "../pal/pal_utils.h" 8 | #include "../pal/pal.h" 9 | #include "../pal/trace.h" 10 | #include "../deps/deps_format.h" 11 | #include "libhost.h" 12 | 13 | struct probe_config_t 14 | { 15 | pal::string_t probe_dir; 16 | bool match_hash; 17 | bool patch_roll_fwd; 18 | bool prerelease_roll_fwd; 19 | const deps_json_t* probe_deps_json; 20 | 21 | bool only_runtime_assets; 22 | bool only_serviceable_assets; 23 | 24 | void print() const 25 | { 26 | trace::verbose(_X("probe_config_t: probe=[%s] match-hash=[%d] patch-roll-forward=[%d] prerelease-roll-forward=[%d] deps-json=[%p]"), 27 | probe_dir.c_str(), match_hash, patch_roll_fwd, prerelease_roll_fwd, probe_deps_json); 28 | } 29 | bool is_roll_fwd_set() const 30 | { 31 | return patch_roll_fwd || prerelease_roll_fwd; 32 | } 33 | 34 | probe_config_t( 35 | const pal::string_t& probe_dir, 36 | bool match_hash, 37 | bool patch_roll_fwd, 38 | bool prerelease_roll_fwd, 39 | const deps_json_t* probe_deps_json, 40 | bool only_serviceable_assets, 41 | bool only_runtime_assets) 42 | : probe_dir(probe_dir) 43 | , match_hash(match_hash) 44 | , patch_roll_fwd(patch_roll_fwd) 45 | , prerelease_roll_fwd(prerelease_roll_fwd) 46 | , probe_deps_json(probe_deps_json) 47 | , only_serviceable_assets(only_serviceable_assets) 48 | , only_runtime_assets(only_runtime_assets) 49 | { 50 | // Cannot roll forward and also match hash. 51 | assert(!is_roll_fwd_set() || !match_hash); 52 | // Will not roll forward within a deps json. 53 | assert(!is_roll_fwd_set() || probe_deps_json == nullptr); 54 | // Will not do hash match when probing a deps json. 55 | assert(!match_hash || probe_deps_json == nullptr); 56 | } 57 | 58 | static probe_config_t svc_ni(const pal::string_t& dir, bool patch_roll_fwd, bool prerelease_roll_fwd) 59 | { 60 | return probe_config_t(dir, false, patch_roll_fwd, prerelease_roll_fwd, nullptr, true, true); 61 | } 62 | 63 | static probe_config_t svc(const pal::string_t& dir, bool patch_roll_fwd, bool prerelease_roll_fwd) 64 | { 65 | return probe_config_t(dir, false, patch_roll_fwd, prerelease_roll_fwd, nullptr, true, false); 66 | } 67 | 68 | static probe_config_t cache_ni(const pal::string_t& dir) 69 | { 70 | return probe_config_t(dir, true, false, false, nullptr, false, true); 71 | } 72 | 73 | static probe_config_t cache(const pal::string_t& dir) 74 | { 75 | return probe_config_t(dir, true, false, false, nullptr, false, false); 76 | } 77 | 78 | static probe_config_t fx(const pal::string_t& dir, const deps_json_t* deps) 79 | { 80 | return probe_config_t(dir, false, false, false, deps, false, false); 81 | } 82 | 83 | static probe_config_t additional(const pal::string_t& dir) 84 | { 85 | return probe_config_t(dir, false, false, false, nullptr, false, false); 86 | } 87 | }; 88 | 89 | struct arguments_t 90 | { 91 | pal::string_t own_path; 92 | pal::string_t app_dir; 93 | pal::string_t deps_path; 94 | pal::string_t core_servicing; 95 | std::vector probe_paths; 96 | pal::string_t dotnet_packages_cache; 97 | pal::string_t managed_application; 98 | 99 | int app_argc; 100 | const pal::char_t** app_argv; 101 | 102 | arguments_t(); 103 | 104 | inline void print() 105 | { 106 | if (trace::is_enabled()) 107 | { 108 | trace::verbose(_X("-- arguments_t: own_path=%s app_dir=%s deps=%s core_svc=%s packages_cache=%s mgd_app=%s"), 109 | own_path.c_str(), app_dir.c_str(), deps_path.c_str(), core_servicing.c_str(), dotnet_packages_cache.c_str(), managed_application.c_str()); 110 | for (const auto& probe : probe_paths) 111 | { 112 | trace::verbose(_X("-- arguments_t: probe dir: [%s]"), probe.c_str()); 113 | } 114 | } 115 | } 116 | }; 117 | 118 | bool parse_arguments(const pal::string_t& deps_path, const std::vector& probe_paths, host_mode_t mode, const int argc, const pal::char_t* argv[], arguments_t* args); 119 | 120 | #endif // ARGS_H 121 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/host/coreclr.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include 5 | 6 | #include "coreclr.h" 7 | #include "../pal/pal_utils.h" 8 | 9 | // Prototype of the coreclr_initialize function from coreclr.dll 10 | typedef pal::hresult_t(STDMETHODCALLTYPE *coreclr_initialize_fn)( 11 | const char* exePath, 12 | const char* appDomainFriendlyName, 13 | int propertyCount, 14 | const char** propertyKeys, 15 | const char** propertyValues, 16 | coreclr::host_handle_t* hostHandle, 17 | unsigned int* domainId); 18 | 19 | // Prototype of the coreclr_shutdown function from coreclr.dll 20 | typedef pal::hresult_t(STDMETHODCALLTYPE *coreclr_shutdown_fn)( 21 | coreclr::host_handle_t hostHandle, 22 | unsigned int domainId); 23 | 24 | // Prototype of the coreclr_execute_assembly function from coreclr.dll 25 | typedef pal::hresult_t(STDMETHODCALLTYPE *coreclr_execute_assembly_fn)( 26 | coreclr::host_handle_t hostHandle, 27 | unsigned int domainId, 28 | int argc, 29 | const char** argv, 30 | const char* managedAssemblyPath, 31 | unsigned int* exitCode); 32 | 33 | // Prototype of the coreclr_create_delegate function from coreclr.dll 34 | typedef pal::hresult_t(STDMETHODCALLTYPE *coreclr_create_delegate_fn)( 35 | coreclr::host_handle_t hostHandle, 36 | unsigned int domainId, 37 | const char* assemblyName, 38 | const char* typeName, 39 | const char* methodName, 40 | void** delegate); 41 | 42 | static coreclr_shutdown_fn coreclr_shutdown = nullptr; 43 | static coreclr_initialize_fn coreclr_initialize = nullptr; 44 | static coreclr_execute_assembly_fn coreclr_execute_assembly = nullptr; 45 | static coreclr_create_delegate_fn coreclr_create_delegate = nullptr; 46 | 47 | bool coreclr::bind(const pal::string_t& libcoreclr_path) 48 | { 49 | assert(g_coreclr == nullptr); 50 | 51 | pal::string_t coreclr_dll_path(libcoreclr_path); 52 | append_path(&coreclr_dll_path, LIBCORECLR_NAME); 53 | 54 | if (!pal::load_library(coreclr_dll_path.c_str(), &g_coreclr)) 55 | { 56 | return false; 57 | } 58 | 59 | coreclr_initialize = (coreclr_initialize_fn)pal::get_symbol(g_coreclr, "coreclr_initialize"); 60 | coreclr_shutdown = (coreclr_shutdown_fn)pal::get_symbol(g_coreclr, "coreclr_shutdown"); 61 | coreclr_execute_assembly = (coreclr_execute_assembly_fn)pal::get_symbol(g_coreclr, "coreclr_execute_assembly"); 62 | coreclr_create_delegate = (coreclr_create_delegate_fn)pal::get_symbol(g_coreclr, "coreclr_create_delegate"); 63 | 64 | return true; 65 | } 66 | 67 | void coreclr::unload() 68 | { 69 | assert(g_coreclr != nullptr && coreclr_initialize != nullptr); 70 | 71 | pal::unload_library(g_coreclr); 72 | } 73 | 74 | pal::hresult_t coreclr::initialize( 75 | const char* exe_path, 76 | const char* app_domain_friendly_name, 77 | const char** property_keys, 78 | const char** property_values, 79 | int property_count, 80 | host_handle_t* host_handle, 81 | domain_id_t* domain_id) 82 | { 83 | assert(g_coreclr != nullptr && coreclr_initialize != nullptr); 84 | 85 | return coreclr_initialize( 86 | exe_path, 87 | app_domain_friendly_name, 88 | property_count, 89 | property_keys, 90 | property_values, 91 | host_handle, 92 | domain_id); 93 | } 94 | 95 | pal::hresult_t coreclr::shutdown(host_handle_t host_handle, domain_id_t domain_id) 96 | { 97 | assert(g_coreclr != nullptr && coreclr_shutdown != nullptr); 98 | 99 | return coreclr_shutdown(host_handle, domain_id); 100 | } 101 | 102 | pal::hresult_t coreclr::execute_assembly( 103 | host_handle_t host_handle, 104 | domain_id_t domain_id, 105 | int argc, 106 | const char** argv, 107 | const char* managed_assembly_path, 108 | unsigned int* exit_code) 109 | { 110 | assert(g_coreclr != nullptr && coreclr_execute_assembly != nullptr); 111 | 112 | return coreclr_execute_assembly( 113 | host_handle, 114 | domain_id, 115 | argc, 116 | argv, 117 | managed_assembly_path, 118 | exit_code); 119 | } 120 | 121 | pal::hresult_t coreclr::create_delegate( 122 | coreclr::host_handle_t hostHandle, 123 | unsigned int domainId, 124 | const char* assemblyName, 125 | const char* typeName, 126 | const char* methodName, 127 | void** delegate) 128 | { 129 | return coreclr_create_delegate(hostHandle, domainId, assemblyName, typeName, methodName, delegate); 130 | } -------------------------------------------------------------------------------- /src/CoreCLREmbedding/host/coreclr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef CLR_H 5 | #define CLR_H 6 | 7 | #include "../pal/pal.h" 8 | #include "../pal/trace.h" 9 | 10 | namespace coreclr 11 | { 12 | typedef void* host_handle_t; 13 | typedef unsigned int domain_id_t; 14 | 15 | static pal::dll_t g_coreclr = nullptr; 16 | 17 | bool bind(const pal::string_t& libcoreclr_path); 18 | 19 | void unload(); 20 | 21 | pal::hresult_t initialize( 22 | const char* exe_path, 23 | const char* app_domain_friendly_name, 24 | const char** property_keys, 25 | const char** property_values, 26 | int property_count, 27 | host_handle_t* host_handle, 28 | domain_id_t* domain_id); 29 | 30 | pal::hresult_t shutdown(host_handle_t host_handle, domain_id_t domain_id); 31 | 32 | pal::hresult_t execute_assembly( 33 | host_handle_t host_handle, 34 | domain_id_t domain_id, 35 | int argc, 36 | const char** argv, 37 | const char* managed_assembly_path, 38 | unsigned int* exit_code); 39 | 40 | pal::hresult_t create_delegate( 41 | coreclr::host_handle_t hostHandle, 42 | unsigned int domainId, 43 | const char* assemblyName, 44 | const char* typeName, 45 | const char* methodName, 46 | void** delegate); 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/host/error_codes.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef __ERROR_CODES_H__ 5 | #define __ERROR_CODES_H__ 6 | enum StatusCode 7 | { 8 | Success = 0, 9 | InvalidArgFailure = 0x80008081, 10 | CoreHostLibLoadFailure = 0x80008082, 11 | CoreHostLibMissingFailure = 0x80008083, 12 | CoreHostEntryPointFailure = 0x80008084, 13 | CoreHostCurExeFindFailure = 0x80008085, 14 | CoreHostResolveModeFailure = 0x80008086, 15 | CoreClrResolveFailure = 0x80008087, 16 | CoreClrBindFailure = 0x80008088, 17 | CoreClrInitFailure = 0x80008089, 18 | CoreClrExeFailure = 0x8000808a, 19 | ResolverInitFailure = 0x8000808b, 20 | ResolverResolveFailure = 0x8000808c, 21 | LibHostCurExeFindFailure = 0x8000808d, 22 | LibHostInitFailure = 0x8000808e, 23 | LibHostMuxFailure = 0x8000808f, 24 | LibHostExecModeFailure = 0x80008090, 25 | LibHostSdkFindFailure = 0x80008091, 26 | LibHostInvalidArgs = 0x80008092, 27 | InvalidConfigFile = 0x80008093, 28 | AppArgNotRunnable = 0x80008094 29 | }; 30 | #endif // __ERROR_CODES_H__ 31 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/host/runtime_config.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef __RUNTIME_CONFIG_H__ 5 | #define __RUNTIME_CONFIG_H__ 6 | 7 | #include 8 | 9 | #include "../pal/pal.h" 10 | #include "cpprest/json.h" 11 | 12 | typedef web::json::value json_value; 13 | 14 | class runtime_config_t 15 | { 16 | public: 17 | runtime_config_t(const pal::string_t& path, const pal::string_t& dev_path); 18 | bool is_valid() { return m_valid; } 19 | const pal::string_t& get_path() { return m_path; } 20 | const pal::string_t& get_dev_path() { return m_dev_path; } 21 | const pal::string_t& get_gc_server() const; 22 | const pal::string_t& get_fx_version() const; 23 | const pal::string_t& get_fx_name() const; 24 | const std::list& get_probe_paths() const; 25 | bool get_patch_roll_fwd() const; 26 | bool get_prerelease_roll_fwd() const; 27 | bool get_portable() const; 28 | bool parse_opts(const json_value& opts); 29 | void config_kv(std::vector*, std::vector*) const; 30 | 31 | private: 32 | bool ensure_parsed(); 33 | bool ensure_dev_config_parsed(); 34 | 35 | std::unordered_map m_properties; 36 | std::vector m_prop_keys; 37 | std::vector m_prop_values; 38 | std::list m_probe_paths; 39 | pal::string_t m_fx_name; 40 | pal::string_t m_fx_ver; 41 | bool m_patch_roll_fwd; 42 | bool m_prerelease_roll_fwd; 43 | 44 | pal::string_t m_dev_path; 45 | pal::string_t m_path; 46 | bool m_portable; 47 | bool m_valid; 48 | }; 49 | #endif // __RUNTIME_CONFIG_H__ -------------------------------------------------------------------------------- /src/CoreCLREmbedding/json/casablanca/LICENSE.txt: -------------------------------------------------------------------------------- 1 | https://github.com/Microsoft/cpprestsdk 2 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/json/casablanca/include/cpprest/details/basic_types.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * ==++== 3 | * 4 | * Copyright (c) Microsoft Corporation. All rights reserved. 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ==--== 17 | * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 18 | * 19 | * Platform-dependent type definitions 20 | * 21 | * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk 22 | * 23 | * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 24 | ****/ 25 | 26 | #pragma once 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "cpprest/details/cpprest_compat.h" 33 | 34 | #ifndef _WIN32 35 | # define __STDC_LIMIT_MACROS 36 | # include 37 | #else 38 | #include 39 | #endif 40 | 41 | #include "cpprest/details/SafeInt3.hpp" 42 | 43 | namespace utility 44 | { 45 | 46 | #ifdef _WIN32 47 | #define _UTF16_STRINGS 48 | #endif 49 | 50 | // We should be using a 64-bit size type for most situations that do 51 | // not involve specifying the size of a memory allocation or buffer. 52 | typedef uint64_t size64_t; 53 | 54 | #ifndef _WIN32 55 | typedef uint32_t HRESULT; // Needed for PPLX 56 | #endif 57 | 58 | #ifdef _UTF16_STRINGS 59 | // 60 | // On Windows, all strings are wide 61 | // 62 | typedef wchar_t char_t ; 63 | typedef std::wstring string_t; 64 | #define _XPLATSTR(x) L ## x 65 | typedef std::wostringstream ostringstream_t; 66 | typedef std::wofstream ofstream_t; 67 | typedef std::wostream ostream_t; 68 | typedef std::wistream istream_t; 69 | typedef std::wifstream ifstream_t; 70 | typedef std::wistringstream istringstream_t; 71 | typedef std::wstringstream stringstream_t; 72 | #define ucout std::wcout 73 | #define ucin std::wcin 74 | #define ucerr std::wcerr 75 | #else 76 | // 77 | // On POSIX platforms, all strings are narrow 78 | // 79 | typedef char char_t; 80 | typedef std::string string_t; 81 | #define _XPLATSTR(x) x 82 | typedef std::ostringstream ostringstream_t; 83 | typedef std::ofstream ofstream_t; 84 | typedef std::ostream ostream_t; 85 | typedef std::istream istream_t; 86 | typedef std::ifstream ifstream_t; 87 | typedef std::istringstream istringstream_t; 88 | typedef std::stringstream stringstream_t; 89 | #define ucout std::cout 90 | #define ucin std::cin 91 | #define ucerr std::cerr 92 | #endif // endif _UTF16_STRINGS 93 | 94 | #ifndef _TURN_OFF_PLATFORM_STRING 95 | #define U(x) _XPLATSTR(x) 96 | #endif // !_TURN_OFF_PLATFORM_STRING 97 | 98 | }// namespace utility 99 | 100 | typedef char utf8char; 101 | typedef std::string utf8string; 102 | typedef std::stringstream utf8stringstream; 103 | typedef std::ostringstream utf8ostringstream; 104 | typedef std::ostream utf8ostream; 105 | typedef std::istream utf8istream; 106 | typedef std::istringstream utf8istringstream; 107 | 108 | #ifdef _UTF16_STRINGS 109 | typedef wchar_t utf16char; 110 | typedef std::wstring utf16string; 111 | typedef std::wstringstream utf16stringstream; 112 | typedef std::wostringstream utf16ostringstream; 113 | typedef std::wostream utf16ostream; 114 | typedef std::wistream utf16istream; 115 | typedef std::wistringstream utf16istringstream; 116 | #else 117 | typedef char16_t utf16char; 118 | typedef std::u16string utf16string; 119 | typedef std::basic_stringstream utf16stringstream; 120 | typedef std::basic_ostringstream utf16ostringstream; 121 | typedef std::basic_ostream utf16ostream; 122 | typedef std::basic_istream utf16istream; 123 | typedef std::basic_istringstream utf16istringstream; 124 | #endif 125 | 126 | 127 | #if defined(_WIN32) 128 | // Include on everything except Windows Desktop ARM, unless explicitly excluded. 129 | #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) 130 | #if defined(WINAPI_FAMILY) 131 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && defined(_M_ARM) 132 | #define CPPREST_EXCLUDE_WEBSOCKETS 133 | #endif 134 | #else 135 | #if defined(_M_ARM) 136 | #define CPPREST_EXCLUDE_WEBSOCKETS 137 | #endif 138 | #endif 139 | #endif 140 | #endif 141 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/json/casablanca/include/cpprest/details/cpprest_compat.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * ==++== 3 | * 4 | * Copyright (c) Microsoft Corporation. All rights reserved. 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ==--== 17 | * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 18 | * 19 | * Standard macros and definitions. 20 | * This header has minimal dependency on windows headers and is safe for use in the public API 21 | * 22 | * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk 23 | * 24 | * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 25 | ****/ 26 | 27 | #pragma once 28 | 29 | #if defined(_WIN32) // Settings specific to Windows 30 | 31 | #if _MSC_VER >= 1900 32 | #define CPPREST_NOEXCEPT noexcept 33 | #else 34 | #define CPPREST_NOEXCEPT 35 | #endif 36 | 37 | #define CASABLANCA_UNREFERENCED_PARAMETER(x) (x) 38 | 39 | #include 40 | 41 | #else // End settings specific to Windows 42 | 43 | // Settings common to all but Windows 44 | 45 | #define __declspec(x) __attribute__ ((x)) 46 | #define dllimport 47 | #define novtable /* no novtable equivalent */ 48 | #define __assume(x) do { if (!(x)) __builtin_unreachable(); } while (false) 49 | #define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x 50 | #define CPPREST_NOEXCEPT noexcept 51 | 52 | #include 53 | #define _ASSERTE(x) assert(x) 54 | 55 | // No SAL on non Windows platforms 56 | #include "cpprest/details/nosal.h" 57 | 58 | #if not defined __cdecl 59 | #if defined cdecl 60 | #define __cdecl __attribute__ ((cdecl)) 61 | #else 62 | #define __cdecl 63 | #endif 64 | 65 | #if defined(__ANDROID__) 66 | // This is needed to disable the use of __thread inside the boost library. 67 | // Android does not support thread local storage -- if boost is included 68 | // without this macro defined, it will create references to __tls_get_addr 69 | // which (while able to link) will not be available at runtime and prevent 70 | // the .so from loading. 71 | #define BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION 72 | #endif 73 | 74 | #ifdef __clang__ 75 | #include 76 | #endif 77 | 78 | #endif // defined(__APPLE__) 79 | 80 | #endif 81 | 82 | 83 | #ifdef _NO_ASYNCRTIMP 84 | #define _ASYNCRTIMP 85 | #else 86 | #ifdef _ASYNCRT_EXPORT 87 | #define _ASYNCRTIMP __declspec(dllexport) 88 | #else 89 | #define _ASYNCRTIMP __declspec(dllimport) 90 | #endif 91 | #endif 92 | 93 | #ifdef CASABLANCA_DEPRECATION_NO_WARNINGS 94 | #define CASABLANCA_DEPRECATED(x) 95 | #else 96 | #define CASABLANCA_DEPRECATED(x) __declspec(deprecated(x)) 97 | #endif 98 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/json/casablanca/include/cpprest/details/nosal.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * ==++== 3 | * 4 | * Copyright (c) Microsoft Corporation. All rights reserved. 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ==--== 17 | * 18 | * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk 19 | * 20 | * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 21 | ***/ 22 | 23 | #pragma once 24 | // selected MS SAL annotations 25 | 26 | #ifdef _In_ 27 | #undef _In_ 28 | #endif 29 | #define _In_ 30 | 31 | #ifdef _Inout_ 32 | #undef _Inout_ 33 | #endif 34 | #define _Inout_ 35 | 36 | #ifdef _Out_ 37 | #undef _Out_ 38 | #endif 39 | #define _Out_ 40 | 41 | #ifdef _In_z_ 42 | #undef _In_z_ 43 | #endif 44 | #define _In_z_ 45 | 46 | #ifdef _Out_z_ 47 | #undef _Out_z_ 48 | #endif 49 | #define _Out_z_ 50 | 51 | #ifdef _Inout_z_ 52 | #undef _Inout_z_ 53 | #endif 54 | #define _Inout_z_ 55 | 56 | #ifdef _In_opt_ 57 | #undef _In_opt_ 58 | #endif 59 | #define _In_opt_ 60 | 61 | #ifdef _Out_opt_ 62 | #undef _Out_opt_ 63 | #endif 64 | #define _Out_opt_ 65 | 66 | #ifdef _Inout_opt_ 67 | #undef _Inout_opt_ 68 | #endif 69 | #define _Inout_opt_ 70 | 71 | #ifdef _Out_writes_ 72 | #undef _Out_writes_ 73 | #endif 74 | #define _Out_writes_(x) 75 | 76 | #ifdef _Out_writes_opt_ 77 | #undef _Out_writes_opt_ 78 | #endif 79 | #define _Out_writes_opt_(x) 80 | 81 | #ifdef _In_reads_ 82 | #undef _In_reads_ 83 | #endif 84 | #define _In_reads_(x) 85 | 86 | #ifdef _Inout_updates_bytes_ 87 | #undef _Inout_updates_bytes_ 88 | #endif 89 | #define _Inout_updates_bytes_(x) -------------------------------------------------------------------------------- /src/CoreCLREmbedding/json/casablanca/include/stdafx.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * ==++== 3 | * 4 | * Copyright (c) Microsoft Corporation. All rights reserved. 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ==--== 17 | * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 18 | * 19 | * Pre-compiled headers 20 | * 21 | * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk 22 | * 23 | * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 24 | ****/ 25 | 26 | #pragma once 27 | 28 | #if defined(__clang__) 29 | #pragma clang diagnostic push 30 | #pragma clang diagnostic ignored "-Wunused-local-typedef" 31 | #endif 32 | 33 | #include 34 | #include 35 | #ifdef _WIN32 36 | #ifdef CPPREST_TARGET_XP 37 | #include 38 | #ifndef _WIN32_WINNT 39 | #define _WIN32_WINNT _WIN32_WINNT_WS03 //Windows XP with SP2 40 | #endif 41 | #endif 42 | #include 43 | // use the debug version of the CRT if _DEBUG is defined 44 | #ifdef _DEBUG 45 | #define _CRTDBG_MAP_ALLOC 46 | #include 47 | #include 48 | #endif 49 | 50 | #ifndef WIN32_LEAN_AND_MEAN 51 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 52 | // Windows Header Files: 53 | #define NOMINMAX 54 | #endif 55 | 56 | #include 57 | #include 58 | 59 | // Windows Header Files: 60 | #if !defined(__cplusplus_winrt) 61 | #include 62 | 63 | #endif // #if !defined(__cplusplus_winrt) 64 | #else // LINUX or APPLE 65 | #define __STDC_LIMIT_MACROS 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include "pthread.h" 74 | #include 75 | #include 76 | #include 77 | #include 78 | #endif // _WIN32 79 | 80 | // Macro indicating the C++ Rest SDK product itself is being built. 81 | // This is to help track how many developers are directly building from source themselves. 82 | #define _CASA_BUILD_FROM_SRC 83 | 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #include 91 | #include 92 | #include 93 | #include 94 | #include 95 | 96 | // json 97 | #include "cpprest/json.h" 98 | 99 | #if defined(max) 100 | #error: max macro defined -- make sure to #define NOMINMAX before including windows.h 101 | #endif 102 | #if defined(min) 103 | #error: min macro defined -- make sure to #define NOMINMAX before including windows.h 104 | #endif 105 | 106 | #if defined(__clang__) 107 | #pragma clang diagnostic pop 108 | #endif 109 | 110 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/pal/pal_utils.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef UTILS_H 5 | #define UTILS_H 6 | 7 | #include "pal.h" 8 | 9 | #define _STRINGIFY(s) _X(s) 10 | 11 | bool ends_with(const pal::string_t& value, const pal::string_t& suffix, bool match_case); 12 | bool starts_with(const pal::string_t& value, const pal::string_t& prefix, bool match_case); 13 | pal::string_t get_executable(const pal::string_t& filename); 14 | pal::string_t get_directory(const pal::string_t& path); 15 | pal::string_t strip_file_ext(const pal::string_t& path); 16 | pal::string_t get_filename(const pal::string_t& path); 17 | pal::string_t get_filename_without_ext(const pal::string_t& path); 18 | void append_path(pal::string_t* path1, const pal::char_t* path2); 19 | bool library_exists_in_dir(const pal::string_t& lib_dir, const pal::string_t& lib_name, pal::string_t* p_lib_path); 20 | bool coreclr_exists_in_dir(const pal::string_t& candidate); 21 | void replace_char(pal::string_t* path, pal::char_t match, pal::char_t repl); 22 | const pal::char_t* get_arch(); 23 | pal::string_t get_last_known_arg( 24 | const std::unordered_map>& opts, 25 | const pal::string_t& opt_key, 26 | const pal::string_t& de_fault); 27 | bool parse_known_args( 28 | const int argc, 29 | const pal::char_t* argv[], 30 | const std::vector& known_opts, 31 | std::unordered_map>* opts, 32 | int* num_args); 33 | bool skip_utf8_bom(pal::ifstream_t* stream); 34 | #endif 35 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/pal/trace.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include "trace.h" 5 | 6 | static bool g_enabled = false; 7 | 8 | // 9 | // Turn on tracing for the corehost based on "COREHOST_TRACE" env. 10 | // 11 | void trace::setup() 12 | { 13 | // Read trace environment variable 14 | pal::string_t trace_str; 15 | if (!pal::getenv(_X("COREHOST_TRACE"), &trace_str)) 16 | { 17 | return; 18 | } 19 | 20 | auto trace_val = pal::xtoi(trace_str.c_str()); 21 | if (trace_val > 0) 22 | { 23 | trace::enable(); 24 | trace::info(_X("Tracing enabled")); 25 | } 26 | } 27 | 28 | void trace::enable() 29 | { 30 | g_enabled = true; 31 | } 32 | 33 | bool trace::is_enabled() 34 | { 35 | return g_enabled; 36 | } 37 | 38 | void trace::verbose(const pal::char_t* format, ...) 39 | { 40 | if (g_enabled) 41 | { 42 | va_list args; 43 | va_start(args, format); 44 | pal::err_vprintf(format, args); 45 | va_end(args); 46 | } 47 | } 48 | 49 | void trace::info(const pal::char_t* format, ...) 50 | { 51 | if (g_enabled) 52 | { 53 | va_list args; 54 | va_start(args, format); 55 | pal::err_vprintf(format, args); 56 | va_end(args); 57 | } 58 | } 59 | 60 | void trace::error(const pal::char_t* format, ...) 61 | { 62 | // Always print errors 63 | va_list args; 64 | va_start(args, format); 65 | pal::err_vprintf(format, args); 66 | va_end(args); 67 | } 68 | 69 | void trace::println(const pal::char_t* format, ...) 70 | { 71 | va_list args; 72 | va_start(args, format); 73 | pal::out_vprintf(format, args); 74 | va_end(args); 75 | } 76 | 77 | void trace::println() 78 | { 79 | println(_X("")); 80 | } 81 | 82 | void trace::warning(const pal::char_t* format, ...) 83 | { 84 | if (g_enabled) 85 | { 86 | va_list args; 87 | va_start(args, format); 88 | pal::err_vprintf(format, args); 89 | va_end(args); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/CoreCLREmbedding/pal/trace.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef TRACE_H 5 | #define TRACE_H 6 | 7 | #include "pal.h" 8 | 9 | namespace trace 10 | { 11 | void setup(); 12 | void enable(); 13 | bool is_enabled(); 14 | void verbose(const pal::char_t* format, ...); 15 | void info(const pal::char_t* format, ...); 16 | void warning(const pal::char_t* format, ...); 17 | void error(const pal::char_t* format, ...); 18 | void println(const pal::char_t* format, ...); 19 | void println(); 20 | }; 21 | 22 | #endif // TRACE_H 23 | -------------------------------------------------------------------------------- /src/common/clrfuncreflectionwrap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using System.Reflection; 4 | 5 | public class ClrFuncReflectionWrap 6 | { 7 | Object instance; 8 | MethodInfo invokeMethod; 9 | 10 | public static ClrFuncReflectionWrap Create(Assembly assembly, String typeName, String methodName) 11 | { 12 | Type startupType = assembly.GetType(typeName); 13 | 14 | if (startupType == null) 15 | { 16 | throw new TypeLoadException("Could not load type '" + typeName + "'"); 17 | } 18 | 19 | ClrFuncReflectionWrap wrap = new ClrFuncReflectionWrap(); 20 | wrap.instance = System.Activator.CreateInstance(startupType); 21 | wrap.invokeMethod = startupType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public); 22 | if (wrap.invokeMethod == null) 23 | { 24 | throw new System.InvalidOperationException( 25 | "Unable to access the CLR method to wrap through reflection. Make sure it is a public instance method."); 26 | } 27 | 28 | return wrap; 29 | } 30 | 31 | public Task Call(Object payload) 32 | { 33 | return (Task)this.invokeMethod.Invoke(this.instance, new object[] { payload }); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /src/common/edge.cpp: -------------------------------------------------------------------------------- 1 | #if !defined(HAVE_CORECLR) && !defined(HAVE_NATIVECLR) 2 | #error "CoreCLR and/or a native .NET runtime (native .NET on Windows or Mono on Linux) must be installed in order for Edge.js to compile." 3 | #endif 4 | 5 | #include "edge_common.h" 6 | 7 | #ifdef HAVE_CORECLR 8 | #include "../CoreCLREmbedding/edge.h" 9 | #endif 10 | #ifdef HAVE_NATIVECLR 11 | #ifdef EDGE_PLATFORM_WINDOWS 12 | #include "../dotnet/edge.h" 13 | #else 14 | #include "../mono/edge.h" 15 | #endif 16 | #endif 17 | 18 | BOOL debugMode; 19 | BOOL enableScriptIgnoreAttribute; 20 | BOOL enableMarshalEnumAsInt; 21 | 22 | NAN_METHOD(initializeClrFunc) 23 | { 24 | #ifdef HAVE_NATIVECLR 25 | #ifdef HAVE_CORECLR 26 | if (HasEnvironmentVariable("EDGE_USE_CORECLR")) 27 | { 28 | CoreClrFunc::Initialize(info); 29 | } 30 | 31 | #endif 32 | ClrFunc::Initialize(info); 33 | #else 34 | CoreClrFunc::Initialize(info); 35 | #endif 36 | } 37 | 38 | #ifdef EDGE_PLATFORM_WINDOWS 39 | #pragma unmanaged 40 | #endif 41 | NAN_MODULE_INIT(init) 42 | { 43 | debugMode = HasEnvironmentVariable("EDGE_DEBUG"); 44 | DBG("edge::init"); 45 | 46 | V8SynchronizationContext::Initialize(); 47 | 48 | #ifdef HAVE_CORECLR 49 | if (FAILED(CoreClrEmbedding::Initialize(debugMode))) 50 | { 51 | DBG("Error occurred during CoreCLR initialization"); 52 | return; 53 | } 54 | #else 55 | #ifndef EDGE_PLATFORM_WINDOWS 56 | MonoEmbedding::Initialize(); 57 | #endif 58 | #endif 59 | 60 | enableScriptIgnoreAttribute = HasEnvironmentVariable("EDGE_ENABLE_SCRIPTIGNOREATTRIBUTE"); 61 | enableMarshalEnumAsInt = HasEnvironmentVariable("EDGE_MARSHAL_ENUM_AS_INT"); 62 | Nan::Set(target, 63 | Nan::New("initializeClrFunc").ToLocalChecked(), 64 | Nan::New(initializeClrFunc)->GetFunction()); 65 | } 66 | 67 | #ifdef EDGE_PLATFORM_WINDOWS 68 | #pragma unmanaged 69 | #endif 70 | bool HasEnvironmentVariable(const char* variableName) 71 | { 72 | #ifdef EDGE_PLATFORM_WINDOWS 73 | return 0 < GetEnvironmentVariable(variableName, NULL, 0); 74 | #else 75 | return getenv(variableName) != NULL; 76 | #endif 77 | } 78 | 79 | #ifdef EDGE_PLATFORM_WINDOWS 80 | #pragma unmanaged 81 | #endif 82 | #ifdef HAVE_CORECLR 83 | NODE_MODULE(edge_coreclr, init); 84 | #else 85 | NODE_MODULE(edge_nativeclr, init); 86 | #endif 87 | 88 | // vim: ts=4 sw=4 et: 89 | -------------------------------------------------------------------------------- /src/common/edge_common.h: -------------------------------------------------------------------------------- 1 | #ifndef __EDGE_COMMON_H 2 | #define __EDGE_COMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace v8; 13 | 14 | // From http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor 15 | #ifdef _WIN64 16 | // Windows 64 17 | #define EDGE_PLATFORM_WINDOWS 1 18 | #elif _WIN32 19 | // Windows 32 20 | #define EDGE_PLATFORM_WINDOWS 1 21 | #elif __APPLE__ 22 | // OSX 23 | #define EDGE_PLATFORM_APPLE 1 24 | #elif __linux 25 | // linux 26 | #define EDGE_PLATFORM_NIX 1 27 | #elif __unix // all unices not caught above 28 | // Unix 29 | #define EDGE_PLATFORM_NIX 1 30 | #elif __posix 31 | // POSIX 32 | #define EDGE_PLATFORM_NIX 1 33 | #endif 34 | 35 | #ifndef EDGE_PLATFORM_WINDOWS 36 | #include 37 | #include 38 | #define __cdecl 39 | #endif 40 | 41 | #ifndef EDGE_PLATFORM_WINDOWS 42 | #ifdef FALSE 43 | #undef FALSE 44 | #endif 45 | #define FALSE 0 46 | #ifdef TRUE 47 | #undef TRUE 48 | #endif 49 | #define TRUE 1 50 | typedef int BOOL; 51 | #endif 52 | 53 | #ifdef EDGE_PLATFORM_WINDOWS 54 | #define ABORT_TODO() do { printf("%s (%d): %s\n", __FILE__, __LINE__, __FUNCTION__); abort(); } while (0) 55 | #elif EDGE_PLATFORM_APPLE 56 | #define ABORT_TODO() do { printf("%s (%d): %s\n", __FILE__, __LINE__, __func__); abort(); } while (0) 57 | #else 58 | #define ABORT_TODO() do { printf("%s (%d): %s\n", __FILE__, __LINE__, __func__); exit(1); } while (0) 59 | #endif 60 | 61 | extern BOOL debugMode; 62 | extern BOOL enableScriptIgnoreAttribute; 63 | extern BOOL enableMarshalEnumAsInt; 64 | 65 | #define DBG(...) if (debugMode) { printf(__VA_ARGS__); printf("\n"); } 66 | 67 | typedef void (*uv_async_edge_cb)(void* data); 68 | 69 | typedef struct uv_edge_async_s { 70 | uv_async_t uv_async; 71 | uv_async_edge_cb action; 72 | void* data; 73 | bool singleton; 74 | } uv_edge_async_t; 75 | 76 | class V8SynchronizationContext { 77 | private: 78 | 79 | static unsigned long v8ThreadId; 80 | static unsigned long GetCurrentThreadId(); 81 | 82 | public: 83 | 84 | // The node process will not exit until ExecuteAction or CancelAction had been called for all actions 85 | // registered by calling RegisterAction on V8 thread. Actions registered by calling RegisterAction 86 | // on CLR thread do not prevent the process from exiting. 87 | // Calls from JavaScript to .NET always call RegisterAction on V8 thread before invoking .NET code. 88 | // Calls from .NET to JavaScript call RegisterAction either on CLR or V8 thread, depending on 89 | // whether .NET code executes synchronously on V8 thread it strarted running on. 90 | // This means that if any call of a .NET function from JavaScript is in progress, the process won't exit. 91 | // It also means that existence of .NET proxies to JavaScript functions in the CLR does not prevent the 92 | // process from exiting. 93 | // In this model, JavaScript owns the lifetime of the process. 94 | 95 | static uv_edge_async_t* uv_edge_async; 96 | static uv_sem_t* funcWaitHandle; 97 | 98 | static void Initialize(); 99 | static uv_edge_async_t* RegisterAction(uv_async_edge_cb action, void* data); 100 | static void ExecuteAction(uv_edge_async_t* uv_edge_async); 101 | static void CancelAction(uv_edge_async_t* uv_edge_async); 102 | static void Unref(uv_edge_async_t* uv_edge_async); 103 | }; 104 | 105 | typedef enum taskStatus 106 | { 107 | TaskStatusCreated = 0, 108 | TaskStatusWaitingForActivation = 1, 109 | TaskStatusWaitingToRun = 2, 110 | TaskStatusRunning = 3, 111 | TaskStatusWaitingForChildrenToComplete = 4, 112 | TaskStatusRanToCompletion = 5, 113 | TaskStatusCanceled = 6, 114 | TaskStatusFaulted = 7 115 | } TaskStatus; 116 | 117 | v8::Local throwV8Exception(v8::Local exception); 118 | v8::Local throwV8Exception(const char* format, ...); 119 | 120 | bool HasEnvironmentVariable(const char* variableName); 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /src/common/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "edge_common.h" 2 | 3 | v8::Local throwV8Exception(v8::Local exception) 4 | { 5 | Nan::EscapableHandleScope scope; 6 | Nan::ThrowError(exception); 7 | return scope.Escape(exception); 8 | } 9 | 10 | v8::Local throwV8Exception(const char* format, ...) 11 | { 12 | va_list args; 13 | va_start(args, format); 14 | 15 | size_t size = vsnprintf(NULL, 0, format, args); 16 | char* message = new char[size + 1]; 17 | 18 | vsnprintf(message, size + 1, format, args); 19 | 20 | Nan::EscapableHandleScope scope; 21 | 22 | v8::Local exception = Nan::New(); 23 | exception->SetPrototype(v8::Exception::Error(Nan::New(message).ToLocalChecked())); 24 | 25 | v8::Local exceptionValue = exception; 26 | Nan::ThrowError(exceptionValue); 27 | 28 | return scope.Escape(exception); 29 | } 30 | -------------------------------------------------------------------------------- /src/common/v8synchronizationcontext.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Portions Copyright (c) Microsoft Corporation. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 10 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 11 | * ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR 12 | * PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 13 | * 14 | * See the Apache Version 2.0 License for specific language governing 15 | * permissions and limitations under the License. 16 | */ 17 | #include "edge_common.h" 18 | 19 | void continueOnV8Thread(uv_async_t* handle, int status) 20 | { 21 | // This executes on V8 thread 22 | 23 | DBG("continueOnV8Thread"); 24 | Nan::HandleScope scope; 25 | uv_edge_async_t* uv_edge_async = (uv_edge_async_t*)handle; 26 | uv_async_edge_cb action = uv_edge_async->action; 27 | void* data = uv_edge_async->data; 28 | V8SynchronizationContext::CancelAction(uv_edge_async); 29 | action(data); 30 | } 31 | 32 | unsigned long V8SynchronizationContext::v8ThreadId; 33 | uv_sem_t* V8SynchronizationContext::funcWaitHandle; 34 | uv_edge_async_t* V8SynchronizationContext::uv_edge_async; 35 | 36 | void V8SynchronizationContext::Initialize() 37 | { 38 | // This executes on V8 thread 39 | 40 | DBG("V8SynchronizationContext::Initialize"); 41 | V8SynchronizationContext::uv_edge_async = new uv_edge_async_t; 42 | uv_edge_async->singleton = TRUE; 43 | uv_async_init(uv_default_loop(), &V8SynchronizationContext::uv_edge_async->uv_async, (uv_async_cb)continueOnV8Thread); 44 | V8SynchronizationContext::Unref(V8SynchronizationContext::uv_edge_async); 45 | V8SynchronizationContext::funcWaitHandle = new uv_sem_t; 46 | uv_sem_init(V8SynchronizationContext::funcWaitHandle, 1); 47 | V8SynchronizationContext::v8ThreadId = V8SynchronizationContext::GetCurrentThreadId(); 48 | } 49 | 50 | void V8SynchronizationContext::Unref(uv_edge_async_t* uv_edge_async) 51 | { 52 | DBG("V8SynchronizationContext::Unref"); 53 | uv_unref((uv_handle_t*)&uv_edge_async->uv_async); 54 | } 55 | 56 | uv_edge_async_t* V8SynchronizationContext::RegisterAction(uv_async_edge_cb action, void* data) 57 | { 58 | DBG("V8SynchronizationContext::RegisterAction"); 59 | 60 | if (V8SynchronizationContext::GetCurrentThreadId() == V8SynchronizationContext::v8ThreadId) 61 | { 62 | // This executes on V8 thread. 63 | // Allocate new uv_edge_async. 64 | 65 | uv_edge_async_t* uv_edge_async = new uv_edge_async_t; 66 | uv_edge_async->action = action; 67 | uv_edge_async->data = data; 68 | uv_edge_async->singleton = FALSE; 69 | uv_async_init(uv_default_loop(), &uv_edge_async->uv_async, (uv_async_cb)continueOnV8Thread); 70 | return uv_edge_async; 71 | } 72 | else 73 | { 74 | // This executes on CLR thread. 75 | // Acquire exlusive access to uv_edge_async previously initialized on V8 thread. 76 | 77 | uv_sem_wait(V8SynchronizationContext::funcWaitHandle); 78 | V8SynchronizationContext::uv_edge_async->action = action; 79 | V8SynchronizationContext::uv_edge_async->data = data; 80 | return V8SynchronizationContext::uv_edge_async; 81 | } 82 | } 83 | 84 | void V8SynchronizationContext::ExecuteAction(uv_edge_async_t* uv_edge_async) 85 | { 86 | DBG("V8SynchronizationContext::ExecuteAction"); 87 | // Transfer control to completeOnV8hread method executing on V8 thread 88 | uv_async_send(&uv_edge_async->uv_async); 89 | } 90 | 91 | void close_uv_edge_async_cb(uv_handle_t* handle) { 92 | uv_edge_async_t* uv_edge_async = (uv_edge_async_t*)handle; 93 | delete uv_edge_async; 94 | } 95 | 96 | void V8SynchronizationContext::CancelAction(uv_edge_async_t* uv_edge_async) 97 | { 98 | DBG("V8SynchronizationContext::CancelAction"); 99 | if (uv_edge_async->singleton) 100 | { 101 | // This is a cancellation of an action registered on CLR thread. 102 | // Release the wait handle to allow the uv_edge_async reuse by another CLR thread. 103 | uv_edge_async->action = NULL; 104 | uv_edge_async->data = NULL; 105 | uv_sem_post(V8SynchronizationContext::funcWaitHandle); 106 | } 107 | else 108 | { 109 | // This is a cancellation of an action registered on V8 thread. 110 | // Unref the handle to stop preventing the process from exiting. 111 | // V8SynchronizationContext::Unref(uv_edge_async); 112 | uv_close((uv_handle_t*)&uv_edge_async->uv_async, close_uv_edge_async_cb); 113 | } 114 | } 115 | 116 | unsigned long V8SynchronizationContext::GetCurrentThreadId() 117 | { 118 | #ifdef _WIN32 119 | return (unsigned long)::GetCurrentThreadId(); 120 | #else 121 | return (unsigned long)pthread_self(); 122 | #endif 123 | } 124 | -------------------------------------------------------------------------------- /src/dotnet/clractioncontext.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | void ClrActionContext::ActionCallback(void* data) 4 | { 5 | ClrActionContext* context = (ClrActionContext*)data; 6 | System::Action^ action = context->action; 7 | delete context; 8 | action(); 9 | } 10 | -------------------------------------------------------------------------------- /src/dotnet/clrfuncreflectionwrap.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | ClrFuncReflectionWrap::ClrFuncReflectionWrap() 4 | { 5 | // empty 6 | } 7 | 8 | ClrFuncReflectionWrap^ ClrFuncReflectionWrap::Create( 9 | Assembly^ assembly, System::String^ typeName, System::String^ methodName) 10 | { 11 | System::Type^ startupType = assembly->GetType(typeName, true, true); 12 | ClrFuncReflectionWrap^ wrap = gcnew ClrFuncReflectionWrap(); 13 | wrap->instance = System::Activator::CreateInstance(startupType, false); 14 | wrap->invokeMethod = startupType->GetMethod(methodName, BindingFlags::Instance | BindingFlags::Public); 15 | if (wrap->invokeMethod == nullptr) 16 | { 17 | throw gcnew System::InvalidOperationException( 18 | "Unable to access the CLR method to wrap through reflection. Make sure it is a public instance method."); 19 | } 20 | 21 | return wrap; 22 | } 23 | 24 | Task^ ClrFuncReflectionWrap::Call(System::Object^ payload) 25 | { 26 | return (Task^)this->invokeMethod->Invoke( 27 | this->instance, gcnew array { payload }); 28 | } 29 | -------------------------------------------------------------------------------- /src/dotnet/edge.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Portions Copyright (c) Microsoft Corporation. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 10 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 11 | * ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR 12 | * PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 13 | * 14 | * See the Apache Version 2.0 License for specific language governing 15 | * permissions and limitations under the License. 16 | */ 17 | #ifndef __EDGE_H 18 | #define __EDGE_H 19 | 20 | #include "../common/edge_common.h" 21 | 22 | #include 23 | 24 | #using 25 | #using 26 | 27 | using namespace System::Collections::Generic; 28 | using namespace System::Reflection; 29 | using namespace System::Threading::Tasks; 30 | using namespace System::Threading; 31 | using namespace System::Web::Script::Serialization; 32 | 33 | v8::Local stringCLR2V8(System::String^ text); 34 | System::String^ stringV82CLR(v8::Local text); 35 | System::String^ stringV82CLR(v8::String::Utf8Value& utf8text); 36 | System::String^ exceptionV82stringCLR(v8::Local exception); 37 | 38 | typedef struct clrActionContext { 39 | gcroot action; 40 | static void ActionCallback(void* data); 41 | } ClrActionContext; 42 | 43 | ref class ClrFuncInvokeContext { 44 | private: 45 | Nan::Persistent* callback; 46 | uv_edge_async_t* uv_edge_async; 47 | 48 | void DisposeCallback(); 49 | 50 | public: 51 | 52 | property System::Object^ Payload; 53 | property Task^ Task; 54 | property bool Sync; 55 | 56 | ClrFuncInvokeContext(v8::Local callbackOrSync); 57 | 58 | void CompleteOnCLRThread(System::Threading::Tasks::Task^ task); 59 | void CompleteOnV8ThreadAsynchronous(); 60 | v8::Local CompleteOnV8Thread(); 61 | void InitializeAsyncOperation(); 62 | }; 63 | 64 | ref class NodejsFunc { 65 | public: 66 | 67 | property Nan::Persistent* Func; 68 | 69 | NodejsFunc(v8::Local function); 70 | ~NodejsFunc(); 71 | !NodejsFunc(); 72 | 73 | Task^ FunctionWrapper(System::Object^ payload); 74 | }; 75 | 76 | ref class PersistentDisposeContext { 77 | private: 78 | System::IntPtr ptr; 79 | public: 80 | PersistentDisposeContext(Nan::Persistent* handle); 81 | void CallDisposeOnV8Thread(); 82 | }; 83 | 84 | ref class NodejsFuncInvokeContext; 85 | 86 | typedef struct nodejsFuncInvokeContextWrap { 87 | gcroot context; 88 | } NodejsFuncInvokeContextWrap; 89 | 90 | ref class NodejsFuncInvokeContext { 91 | private: 92 | NodejsFunc^ functionContext; 93 | System::Object^ payload; 94 | System::Exception^ exception; 95 | System::Object^ result; 96 | NodejsFuncInvokeContextWrap* wrap; 97 | 98 | void Complete(); 99 | 100 | public: 101 | 102 | property TaskCompletionSource^ TaskCompletionSource; 103 | 104 | NodejsFuncInvokeContext( 105 | NodejsFunc^ functionContext, System::Object^ payload); 106 | ~NodejsFuncInvokeContext(); 107 | !NodejsFuncInvokeContext(); 108 | 109 | void CompleteWithError(System::Exception^ exception); 110 | void CompleteWithResult(v8::Local result); 111 | void CallFuncOnV8Thread(); 112 | }; 113 | 114 | ref class ClrFuncReflectionWrap { 115 | private: 116 | System::Object^ instance; 117 | MethodInfo^ invokeMethod; 118 | 119 | ClrFuncReflectionWrap(); 120 | 121 | public: 122 | 123 | static ClrFuncReflectionWrap^ Create(Assembly^ assembly, System::String^ typeName, System::String^ methodName); 124 | Task^ Call(System::Object^ payload); 125 | }; 126 | 127 | ref class ClrFunc { 128 | private: 129 | System::Func^>^ func; 130 | 131 | ClrFunc(); 132 | 133 | static v8::Local MarshalCLRObjectToV8(System::Object^ netdata); 134 | 135 | public: 136 | static NAN_METHOD(Initialize); 137 | static v8::Local Initialize(System::Func^>^ func); 138 | v8::Local Call(v8::Local payload, v8::Local callback); 139 | static v8::Local MarshalCLRToV8(System::Object^ netdata); 140 | static v8::Local MarshalCLRExceptionToV8(System::Exception^ exception); 141 | static System::Object^ MarshalV8ToCLR(v8::Local jsdata); 142 | }; 143 | 144 | typedef struct clrFuncWrap { 145 | gcroot clrFunc; 146 | } ClrFuncWrap; 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /src/dotnet/nodejsfunc.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Portions Copyright (c) Microsoft Corporation. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 10 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 11 | * ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR 12 | * PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 13 | * 14 | * See the Apache Version 2.0 License for specific language governing 15 | * permissions and limitations under the License. 16 | */ 17 | #include "edge.h" 18 | 19 | NodejsFunc::NodejsFunc(v8::Local function) 20 | { 21 | DBG("NodejsFunc::NodejsFunc"); 22 | this->Func = new Nan::Persistent; 23 | this->Func->Reset(function); 24 | } 25 | 26 | NodejsFunc::~NodejsFunc() 27 | { 28 | this->!NodejsFunc(); 29 | } 30 | 31 | NodejsFunc::!NodejsFunc() 32 | { 33 | DBG("NodejsFunc::!NodejsFunc"); 34 | PersistentDisposeContext^ context = gcnew PersistentDisposeContext((Nan::Persistent*)this->Func); 35 | ClrActionContext* data = new ClrActionContext; 36 | data->action = gcnew System::Action(context, &PersistentDisposeContext::CallDisposeOnV8Thread); 37 | uv_edge_async_t* uv_edge_async = V8SynchronizationContext::RegisterAction(ClrActionContext::ActionCallback, data); 38 | V8SynchronizationContext::ExecuteAction(uv_edge_async); 39 | } 40 | 41 | Task^ NodejsFunc::FunctionWrapper(System::Object^ payload) 42 | { 43 | DBG("NodejsFunc::FunctionWrapper"); 44 | NodejsFuncInvokeContext^ context = gcnew NodejsFuncInvokeContext(this, payload); 45 | ClrActionContext* data = new ClrActionContext; 46 | data->action = gcnew System::Action(context, &NodejsFuncInvokeContext::CallFuncOnV8Thread); 47 | uv_edge_async_t* uv_edge_async = V8SynchronizationContext::RegisterAction(ClrActionContext::ActionCallback, data); 48 | V8SynchronizationContext::ExecuteAction(uv_edge_async); 49 | 50 | return context->TaskCompletionSource->Task; 51 | } 52 | -------------------------------------------------------------------------------- /src/dotnet/persistentdisposecontext.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 10 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 11 | * ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR 12 | * PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 13 | * 14 | * See the Apache Version 2.0 License for specific language governing 15 | * permissions and limitations under the License. 16 | */ 17 | #include "edge.h" 18 | 19 | PersistentDisposeContext::PersistentDisposeContext(Nan::Persistent* handle) 20 | : ptr((void*)handle) 21 | { 22 | DBG("PersistentDisposeContext::PersistentDisposeContext"); 23 | } 24 | 25 | void PersistentDisposeContext::CallDisposeOnV8Thread() { 26 | DBG("PersistentDisposeContext::CallDisposeOnV8Thread"); 27 | 28 | Nan::Persistent* handle = (Nan::Persistent*)ptr.ToPointer(); 29 | handle->Reset(); 30 | delete handle; 31 | } -------------------------------------------------------------------------------- /src/dotnet/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | v8::Local stringCLR2V8(System::String^ text) 4 | { 5 | Nan::EscapableHandleScope scope; 6 | if (text->Length > 0) 7 | { 8 | array^ utf8 = System::Text::Encoding::UTF8->GetBytes(text); 9 | pin_ptr ch = &utf8[0]; 10 | return scope.Escape(Nan::New((char*)ch, utf8->Length).ToLocalChecked()); 11 | } 12 | else 13 | { 14 | return scope.Escape(Nan::New("").ToLocalChecked()); 15 | } 16 | } 17 | 18 | System::String^ stringV82CLR(v8::Local text) 19 | { 20 | Nan::HandleScope scope; 21 | v8::String::Utf8Value utf8text(text); 22 | if (*utf8text) 23 | { 24 | return gcnew System::String( 25 | *utf8text, 0, utf8text.length(), System::Text::Encoding::UTF8); 26 | } 27 | else 28 | { 29 | return System::String::Empty; 30 | } 31 | } 32 | 33 | System::String^ stringV82CLR(v8::String::Utf8Value& utf8text) 34 | { 35 | Nan::HandleScope scope; 36 | if (*utf8text) 37 | { 38 | return gcnew System::String( 39 | *utf8text, 0, utf8text.length(), System::Text::Encoding::UTF8); 40 | } 41 | else 42 | { 43 | return System::String::Empty; 44 | } 45 | } 46 | System::String^ exceptionV82stringCLR(v8::Local exception) 47 | { 48 | Nan::HandleScope scope; 49 | if (exception->IsObject()) 50 | { 51 | v8::Local stack = exception->ToObject()->Get(Nan::New("stack").ToLocalChecked()); 52 | if (stack->IsString()) 53 | { 54 | return gcnew System::String(stringV82CLR(stack->ToString())); 55 | } 56 | } 57 | 58 | return gcnew System::String(stringV82CLR(v8::Local::Cast(exception))); 59 | } 60 | -------------------------------------------------------------------------------- /src/double/Edge.js/dotnetcore/nodejsfunc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using System.Runtime.CompilerServices; 4 | 5 | public class NodejsFunc 6 | { 7 | public IntPtr Context 8 | { 9 | get; 10 | private set; 11 | } 12 | 13 | public NodejsFunc(IntPtr context) 14 | { 15 | Context = context; 16 | } 17 | 18 | ~NodejsFunc() 19 | { 20 | // TODO: implement release 21 | } 22 | 23 | public Func> GetFunc() 24 | { 25 | return new Func>(FunctionWrapper); 26 | } 27 | 28 | private Task FunctionWrapper(object payload) 29 | { 30 | CoreCLREmbedding.DebugMessage("NodejsFunc::FunctionWrapper (CLR) - Started"); 31 | 32 | NodejsFuncInvokeContext invokeContext = new NodejsFuncInvokeContext(this, payload); 33 | invokeContext.CallFunc(); 34 | 35 | CoreCLREmbedding.DebugMessage("NodejsFunc::FunctionWrapper (CLR) - Node.js function invoked on the V8 thread, returning the task completion source"); 36 | 37 | return invokeContext.TaskCompletionSource.Task; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/double/Edge.js/dotnetcore/nodejsfuncinvokecontext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | public delegate void NodejsFuncCompleteDelegate(IntPtr context, int taskStatus, IntPtr result, int resultType); 7 | 8 | public class NodejsFuncInvokeContext 9 | { 10 | private NodejsFunc functionContext; 11 | private object payload; 12 | private static IntPtr NodejsFuncCompleteCallback; 13 | private static NodejsFuncCompleteDelegate NodeJsFuncCompleteInstance; 14 | 15 | static NodejsFuncInvokeContext() 16 | { 17 | NodeJsFuncCompleteInstance = new NodejsFuncCompleteDelegate(NodejsFuncComplete); 18 | NodejsFuncCompleteCallback = Marshal.GetFunctionPointerForDelegate(NodeJsFuncCompleteInstance); 19 | } 20 | 21 | internal static CallV8FunctionDelegate CallV8Function 22 | { 23 | get; 24 | set; 25 | } 26 | 27 | public TaskCompletionSource TaskCompletionSource 28 | { 29 | get; 30 | private set; 31 | } 32 | 33 | public NodejsFuncInvokeContext(NodejsFunc functionContext, object payload) 34 | { 35 | this.functionContext = functionContext; 36 | this.payload = payload; 37 | this.TaskCompletionSource = new TaskCompletionSource(); 38 | } 39 | 40 | internal void CallFunc() 41 | { 42 | CoreCLREmbedding.DebugMessage("NodejsFuncInvokeContext::CallFunc (CLR) - Starting"); 43 | 44 | V8Type v8PayloadType; 45 | IntPtr v8Payload = CoreCLREmbedding.MarshalCLRToV8(payload, out v8PayloadType); 46 | 47 | CoreCLREmbedding.DebugMessage("NodejsFuncInvokeContext::CallFunc (CLR) - Marshalled payload data for V8"); 48 | 49 | IntPtr callbackContext = GCHandle.ToIntPtr(GCHandle.Alloc(this)); 50 | CoreCLREmbedding.DebugMessage("NodejsFuncInvokeContext::CallFunc (CLR) - Getting a GCHandle for this context object"); 51 | 52 | CoreCLREmbedding.DebugMessage("NodejsFuncInvokeContext::CallFunc (CLR) - Invoking the unmanaged V8 function to invoke the Node.js function on the V8 thread"); 53 | CallV8Function(v8Payload, (int)v8PayloadType, functionContext.Context, callbackContext, NodejsFuncCompleteCallback); 54 | } 55 | 56 | public static void NodejsFuncComplete(IntPtr context, int taskStatus, IntPtr result, int resultType) 57 | { 58 | CoreCLREmbedding.DebugMessage("NodejsFuncInvokeContext::NodejsFuncComplete (CLR) - Starting"); 59 | 60 | GCHandle gcHandle = GCHandle.FromIntPtr(context); 61 | NodejsFuncInvokeContext actualContext = (NodejsFuncInvokeContext)gcHandle.Target; 62 | 63 | gcHandle.Free(); 64 | 65 | V8Type v8ResultType = (V8Type)resultType; 66 | object marshalledResult = CoreCLREmbedding.MarshalV8ToCLR(result, v8ResultType); 67 | 68 | CoreCLREmbedding.DebugMessage("NodejsFuncInvokeContext::NodejsFuncComplete (CLR) - Marshalled result data back to the CLR"); 69 | 70 | if (taskStatus == (int)TaskStatus.Faulted) 71 | { 72 | actualContext.TaskCompletionSource.SetException((Exception)marshalledResult); 73 | CoreCLREmbedding.DebugMessage("NodejsFuncInvokeContext::NodejsFuncComplete (CLR) - Set the exception received from Node.js: {0}", ((Exception)marshalledResult).Message); 74 | } 75 | 76 | else 77 | { 78 | actualContext.TaskCompletionSource.SetResult(marshalledResult); 79 | CoreCLREmbedding.DebugMessage("NodejsFuncInvokeContext::NodejsFuncComplete (CLR) - Set result data"); 80 | } 81 | 82 | CoreCLREmbedding.DebugMessage("NodejsFuncInvokeContext::NodejsFuncComplete (CLR) - Finished"); 83 | } 84 | } -------------------------------------------------------------------------------- /src/double/Edge.js/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "6.5.1", 3 | "description": "With Edge.js you can script Node.js in a .NET application. Edge.js allows you to run Node.js and .NET code in one process. You can call Node.js functions from .NET and .NET functions from Node.js. Edge.js takes care of marshalling data between CLR and V8. Edge.js also reconciles threading models of single threaded V8 and multi-threaded CLR. Edge.js ensures correct lifetime of objects on V8 and CLR heaps. This Edge.js NuGet package supports scripting Node.js v6.5.0.", 4 | "copyright": "Copyright 2015 Tomasz Janczuk", 5 | "packOptions": { 6 | "summary": "Script Node.js in a .NET application.", 7 | "projectUrl": "https://github.com/tjanczuk/edge", 8 | "licenseUrl": "https://raw.githubusercontent.com/tjanczuk/edge/master/LICENSE.txt", 9 | "tags": "node.js node .net edge edge.js v8 clr coreclr mono interop javascript" 10 | }, 11 | 12 | "frameworks": { 13 | "net40": { 14 | "bin": { 15 | "assembly": "bin/{configuration}/net40/EdgeJs.dll" 16 | } 17 | }, 18 | 19 | "netstandard1.6": { 20 | "dependencies": { 21 | "NETStandard.Library": "1.6.0", 22 | "System.Console": "4.0.0", 23 | "System.Runtime": "4.1.0", 24 | "System.Runtime.InteropServices": "4.1.0", 25 | "System.Dynamic.Runtime": "4.0.11", 26 | "System.Linq": "4.1.0", 27 | "System.Linq.Expressions": "4.1.0", 28 | "System.IO.FileSystem": "4.0.1", 29 | "System.Runtime.Loader": "4.0.0", 30 | "Microsoft.CSharp": "4.0.1", 31 | "System.Reflection": "4.1.0", 32 | "System.Xml.XPath.XmlDocument": "4.0.1", 33 | "System.Xml.ReaderWriter": "4.0.11", 34 | "System.Private.Uri": "4.0.1", 35 | "System.Collections.Specialized": "4.0.1", 36 | "Microsoft.Extensions.DependencyModel": "1.0.0", 37 | "Microsoft.DotNet.InternalAbstractions": "1.0.0", 38 | "System.AppContext": "4.1.0" 39 | }, 40 | 41 | "buildOptions": { 42 | "allowUnsafe": true, 43 | "compile": { 44 | "include": [ 45 | "dotnetcore/*.cs", 46 | "../../common/*.cs" 47 | ], 48 | "exclude": "dotnet/*.cs" 49 | } 50 | } 51 | } 52 | }, 53 | 54 | "buildOptions": { 55 | "outputName": "EdgeJs" 56 | }, 57 | 58 | "packOptions": { 59 | "licenseUrl": "https://raw.githubusercontent.com/tjanczuk/edge/master/LICENSE.txt", 60 | "owners": [ 61 | "Tomasz Janczuk" 62 | ], 63 | "tags": [ 64 | "node.js", 65 | "node", 66 | ".net", 67 | "edge", 68 | "edge.js", 69 | "v8", 70 | "clr", 71 | "coreclr", 72 | "mono", 73 | "interop", 74 | "javascript" 75 | ], 76 | "files": { 77 | "mappings": { 78 | "tools/": "../../../tools/nuget/install.ps1", 79 | "content/edge/": "../../../lib/*.js", 80 | "content/edge/x86/": "../../../tools/build/nuget/content/edge/x86/*", 81 | "content/edge/x64/": "../../../tools/build/nuget/content/edge/x64/*" 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/mono/clractioncontext.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | void ClrActionContext::ActionCallback(void* data) 4 | { 5 | static MonoMethod* actionInvoke; 6 | if (!actionInvoke) 7 | { 8 | MonoClass* actionClass = mono_class_from_name(mono_get_corlib(), "System", "Action"); 9 | actionInvoke = mono_class_get_method_from_name(actionClass, "Invoke", -1); 10 | } 11 | 12 | ClrActionContext* context = (ClrActionContext*)data; 13 | MonoObject* action = mono_gchandle_get_target(context->action); 14 | MonoException* exc = NULL; 15 | mono_runtime_invoke(actionInvoke, action, NULL, (MonoObject**)&exc); 16 | mono_gchandle_free(context->action); 17 | delete context; 18 | if (exc) 19 | ABORT_TODO(); 20 | } 21 | -------------------------------------------------------------------------------- /src/mono/clrfuncinvokecontext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using System.Runtime.CompilerServices; 4 | 5 | class ClrFuncInvokeContext 6 | { 7 | #pragma warning disable 649 // assigned from clrfuncinvokecontext.cpp through embedding APIs 8 | IntPtr native; 9 | #pragma warning disable 169 // assigned from clrfuncinvokecontext.cpp through embedding APIs 10 | Object Payload; 11 | Task Task; 12 | bool Sync; 13 | #pragma warning restore 169 14 | #pragma warning restore 649 15 | 16 | [MethodImplAttribute(MethodImplOptions.InternalCall)] 17 | static extern void CompleteOnCLRThreadICall(IntPtr ptr, Task task); 18 | 19 | internal void CompleteOnCLRThread(Task task) 20 | { 21 | CompleteOnCLRThreadICall(native, task); 22 | } 23 | 24 | [MethodImplAttribute(MethodImplOptions.InternalCall)] 25 | static extern void CompleteOnV8ThreadAsynchronousICall(IntPtr ptr); 26 | 27 | void CompleteOnV8ThreadAsynchronous() 28 | { 29 | CompleteOnV8ThreadAsynchronousICall(native); 30 | } 31 | 32 | public Action GetCompleteOnV8ThreadAsynchronousAction() 33 | { 34 | return new Action(CompleteOnV8ThreadAsynchronous); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /src/mono/dictionary.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | void Dictionary::Add(MonoObject* _this, const char* name, MonoObject* value) 4 | { 5 | static MonoMethod* add; 6 | 7 | if(!add) { 8 | add = mono_class_get_method_from_name(mono_object_get_class(_this), 9 | "System.Collections.Generic.IDictionary.Add", -1); 10 | } 11 | 12 | void* params[2]; 13 | params[0] = mono_string_new(mono_domain_get(), name); 14 | params[1] = value; 15 | 16 | mono_runtime_invoke(add, _this, params, NULL); 17 | } 18 | -------------------------------------------------------------------------------- /src/mono/edge.h: -------------------------------------------------------------------------------- 1 | #ifndef __MONO_EDGE_H 2 | #define __MONO_EDGE_H 3 | 4 | #include "../common/edge_common.h" 5 | 6 | #include 7 | #include "mono/metadata/class.h" 8 | #include "mono/metadata/object.h" 9 | #include "mono/metadata/appdomain.h" 10 | 11 | typedef int GCHandle; 12 | 13 | v8::Local stringCLR2V8(MonoString* text); 14 | MonoString* stringV82CLR(v8::Handle text); 15 | MonoString* exceptionV82stringCLR(v8::Handle exception); 16 | 17 | class MonoEmbedding 18 | { 19 | static MonoAssembly* assembly; 20 | public: 21 | static void Initialize(); 22 | static void NormalizeException(MonoException** e); 23 | static MonoAssembly* GetAssembly(); 24 | static MonoImage* GetImage(); 25 | static MonoClass* GetClass(); 26 | static MonoObject* GetClrFuncReflectionWrapFunc(const char* assembly, const char* typeName, const char* methodName, MonoException ** exc); 27 | static MonoObject* CreateDateTime(double ticks); 28 | static MonoClass* GetIDictionaryStringObjectClass(MonoException** exc); 29 | static MonoClass* GetUriClass(MonoException** exc); 30 | static MonoObject* CreateExpandoObject(); 31 | static MonoClass* GetFuncClass(); 32 | static MonoArray* IEnumerableToArray(MonoObject* ienumerable, MonoException** exc); 33 | static MonoArray* IDictionaryToFlatArray(MonoObject* dictionary, MonoException** exc); 34 | static void ContinueTask(MonoObject* task, MonoObject* state, MonoException** exc); 35 | static double GetDateValue(MonoObject* dt, MonoException** exc); 36 | static MonoString* ToString(MonoObject* o, MonoException** exc); 37 | static double Int64ToDouble(MonoObject* i64, MonoException** exc); 38 | static MonoString* TryConvertPrimitiveOrDecimal(MonoObject* obj, MonoException** exc); 39 | }; 40 | 41 | typedef struct clrActionContext { 42 | GCHandle action; 43 | static void ActionCallback(void* data); 44 | } ClrActionContext; 45 | 46 | // wrapper for System.Threading.Task 47 | 48 | class Task 49 | { 50 | public: 51 | static TaskStatus Status(MonoObject* _this); 52 | static MonoException* Exception(MonoObject* _this); 53 | static MonoObject* Result(MonoObject* _this); 54 | }; 55 | 56 | // wrapper for System.Collections.Generic.Dictionary 57 | 58 | class Dictionary 59 | { 60 | public: 61 | static void Add(MonoObject* _this, const char* name, MonoObject* value); 62 | }; 63 | 64 | class ClrFuncInvokeContext { 65 | private: 66 | GCHandle _this; 67 | Nan::Persistent* callback; 68 | uv_edge_async_t* uv_edge_async; 69 | 70 | public: 71 | MonoObject* Payload(); 72 | void Payload(MonoObject* value); 73 | MonoObject* Task(); 74 | void Task(MonoObject* value); 75 | bool Sync(); 76 | void Sync(bool value); 77 | 78 | MonoObject* GetMonoObject(); 79 | 80 | ClrFuncInvokeContext(v8::Local callbackOrSync); 81 | ~ClrFuncInvokeContext(); 82 | 83 | void InitializeAsyncOperation(); 84 | 85 | static void __cdecl CompleteOnCLRThread(ClrFuncInvokeContext *_this, MonoObject* task); 86 | static void __cdecl CompleteOnV8ThreadAsynchronous(ClrFuncInvokeContext *_this); 87 | v8::Local CompleteOnV8Thread(bool completedSynchronously); 88 | }; 89 | 90 | class NodejsFunc { 91 | GCHandle _this; 92 | public: 93 | Nan::Persistent* Func; 94 | 95 | NodejsFunc(v8::Local function); 96 | ~NodejsFunc(); 97 | 98 | MonoObject* GetFunc(); // returns Func> 99 | 100 | static void __cdecl ExecuteActionOnV8Thread(MonoObject* action); 101 | static void __cdecl Release(NodejsFunc* _this); 102 | }; 103 | 104 | class NodejsFuncInvokeContext { 105 | GCHandle _this; 106 | public: 107 | NodejsFuncInvokeContext(MonoObject* _this); 108 | ~NodejsFuncInvokeContext(); 109 | 110 | static void __cdecl CallFuncOnV8Thread(MonoObject* _this, NodejsFunc* nativeNodejsFunc, MonoObject* payload); 111 | void Complete(MonoObject* exception, MonoObject* result); 112 | }; 113 | 114 | class ClrFunc { 115 | private: 116 | //System::Func^>^ func; 117 | GCHandle func; 118 | 119 | ClrFunc(); 120 | 121 | static v8::Local MarshalCLRObjectToV8(MonoObject* netdata, MonoException** exc); 122 | 123 | public: 124 | static NAN_METHOD(Initialize); 125 | static v8::Local Initialize(MonoObject* func); 126 | v8::Local Call(v8::Local payload, v8::Local callback); 127 | static v8::Local MarshalCLRToV8(MonoObject* netdata, MonoException** exc); 128 | static v8::Local MarshalCLRExceptionToV8(MonoException* exception); 129 | static MonoObject* MarshalV8ToCLR(v8::Local jsdata); 130 | }; 131 | 132 | typedef struct clrFuncWrap { 133 | ClrFunc* clrFunc; 134 | } ClrFuncWrap; 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /src/mono/monoembedding.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Dynamic; 3 | using System.Threading.Tasks; 4 | using System.Reflection; 5 | using System.Collections.Generic; 6 | 7 | public static class MonoEmbedding 8 | { 9 | static Int64 MinDateTimeTicks = 621355968000000000; // (new DateTime(1970, 1, 1, 0, 0, 0)).Ticks; 10 | 11 | // dummy Main so we can exec from mono 12 | static public int Main() 13 | { 14 | return 0; 15 | } 16 | 17 | static public Exception NormalizeException(Exception e) 18 | { 19 | AggregateException aggregate = e as AggregateException; 20 | if (aggregate != null && aggregate.InnerExceptions.Count == 1) 21 | { 22 | e = aggregate.InnerExceptions[0]; 23 | } 24 | else { 25 | TargetInvocationException target = e as TargetInvocationException; 26 | if (target != null && target.InnerException != null) 27 | { 28 | e = target.InnerException; 29 | } 30 | } 31 | 32 | return e; 33 | } 34 | 35 | static public Type GetIDictionaryStringObjectType() 36 | { 37 | return typeof(IDictionary); 38 | } 39 | 40 | static public Type GetUriType() 41 | { 42 | return typeof(Uri); 43 | } 44 | 45 | static public Func> GetFunc(string assemblyFile, string typeName, string methodName) 46 | { 47 | var assembly = Assembly.LoadFrom(assemblyFile); 48 | var wrap = ClrFuncReflectionWrap.Create(assembly, typeName, methodName); 49 | return new Func>(wrap.Call); 50 | } 51 | 52 | static public DateTime CreateDateTime(double ticks) 53 | { 54 | return new DateTime((Int64)ticks * 10000 + MinDateTimeTicks, DateTimeKind.Utc); 55 | } 56 | 57 | static public ExpandoObject CreateExpandoObject() 58 | { 59 | return new ExpandoObject(); 60 | } 61 | 62 | static public double GetDateValue(DateTime dt) 63 | { 64 | if (dt.Kind == DateTimeKind.Local) 65 | dt = dt.ToUniversalTime(); 66 | else if (dt.Kind == DateTimeKind.Unspecified) 67 | dt = new DateTime(dt.Ticks, DateTimeKind.Utc); 68 | Int64 value = (dt.Ticks - MinDateTimeTicks) / 10000; 69 | 70 | return (double)value; 71 | } 72 | 73 | static public object[] IDictionaryToFlatArray(object dictionary) 74 | { 75 | var list = new List(); 76 | IDictionary dso = dictionary as IDictionary; 77 | if (dso != null) 78 | { 79 | foreach (var kv in dso) 80 | { 81 | list.Add(kv.Key); 82 | list.Add(kv.Value); 83 | } 84 | } 85 | else 86 | { 87 | System.Collections.IDictionary d = dictionary as System.Collections.IDictionary; 88 | if (d != null) 89 | { 90 | foreach (System.Collections.DictionaryEntry kv in d) 91 | { 92 | if ((kv.Key as string) != null) 93 | { 94 | list.Add(kv.Key); 95 | list.Add(kv.Value); 96 | } 97 | } 98 | } 99 | else 100 | { 101 | throw new InvalidOperationException("Expected a dictionary."); 102 | } 103 | } 104 | 105 | return list.ToArray(); 106 | } 107 | 108 | static public object[] IEnumerableToArray(System.Collections.IEnumerable enumerable) 109 | { 110 | var list = new List(); 111 | foreach (var item in enumerable) 112 | list.Add(item); 113 | 114 | return list.ToArray(); 115 | } 116 | 117 | static public Type GetFuncType() 118 | { 119 | return typeof(Func>); 120 | } 121 | 122 | static public void edgeAppCompletedOnCLRThread(Task task, object state) 123 | { 124 | var context = (ClrFuncInvokeContext)state; 125 | context.CompleteOnCLRThread(task); 126 | } 127 | 128 | static public void ContinueTask(Task task, object state) 129 | { 130 | // Will complete asynchronously. Schedule continuation to finish processing. 131 | task.ContinueWith(new Action, object>(edgeAppCompletedOnCLRThread), state); 132 | } 133 | 134 | static public string ObjectToString(object o) 135 | { 136 | return o.ToString(); 137 | } 138 | 139 | static public double Int64ToDouble(long i64) 140 | { 141 | return (double)i64; 142 | } 143 | 144 | static public string TryConvertPrimitiveOrDecimal(object obj) 145 | { 146 | Type t = obj.GetType(); 147 | if (t.IsPrimitive || typeof(Decimal) == t) 148 | { 149 | IConvertible c = obj as IConvertible; 150 | return c == null ? obj.ToString() : c.ToString(); 151 | } 152 | else 153 | { 154 | return null; 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/mono/nodejsfunc.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | static MonoClass* GetNodejsFuncClass() 4 | { 5 | static MonoClass* klass; 6 | 7 | if (!klass) 8 | klass = mono_class_from_name(MonoEmbedding::GetImage(), "", "NodejsFunc"); 9 | 10 | return klass; 11 | } 12 | 13 | NodejsFunc::NodejsFunc(v8::Local function) 14 | { 15 | DBG("NodejsFunc::NodejsFunc"); 16 | 17 | static MonoMethod* ctor; 18 | if (!ctor) 19 | ctor = mono_class_get_method_from_name(GetNodejsFuncClass(), ".ctor", -1); 20 | 21 | this->Func = new Nan::Persistent; 22 | (this->Func)->Reset(function); 23 | 24 | MonoObject* thisObj = mono_object_new(mono_domain_get(), GetNodejsFuncClass()); 25 | MonoException* exc = NULL; 26 | void *thisPtr = this; 27 | void *args[] = { &thisPtr }; 28 | mono_runtime_invoke(ctor, thisObj, args, (MonoObject**)&exc); 29 | _this = mono_gchandle_new_weakref(thisObj, FALSE); 30 | } 31 | 32 | NodejsFunc::~NodejsFunc() 33 | { 34 | DBG("NodejsFunc::~NodejsFunc"); 35 | this->Func->Reset(); 36 | delete this->Func; 37 | this->Func = NULL; 38 | } 39 | 40 | void NodejsFunc::Release(NodejsFunc* _this) 41 | { 42 | delete _this; 43 | } 44 | 45 | MonoObject* NodejsFunc::GetFunc() 46 | { 47 | static MonoMethod* method; 48 | 49 | if (!method) 50 | method = mono_class_get_method_from_name(GetNodejsFuncClass(), "GetFunc", -1); 51 | 52 | MonoException* exc = NULL; 53 | MonoObject* func = mono_runtime_invoke(method, mono_gchandle_get_target(_this), NULL, (MonoObject**)&exc); 54 | 55 | return func; 56 | } 57 | 58 | void NodejsFunc::ExecuteActionOnV8Thread(MonoObject* action) 59 | { 60 | ClrActionContext* data = new ClrActionContext; 61 | data->action = mono_gchandle_new(action, FALSE); // released in ClrActionContext::ActionCallback 62 | uv_edge_async_t* uv_edge_async = V8SynchronizationContext::RegisterAction(ClrActionContext::ActionCallback, data); 63 | V8SynchronizationContext::ExecuteAction(uv_edge_async); 64 | } 65 | -------------------------------------------------------------------------------- /src/mono/nodejsfunc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using System.Runtime.CompilerServices; 4 | 5 | class NodejsFunc 6 | { 7 | public IntPtr NativeNodejsFunc { get; set; } 8 | 9 | public NodejsFunc(IntPtr native) 10 | { 11 | this.NativeNodejsFunc = native; 12 | } 13 | 14 | ~NodejsFunc() 15 | { 16 | IntPtr native = this.NativeNodejsFunc; 17 | ExecuteActionOnV8Thread(() => { 18 | Release(native); 19 | }); 20 | } 21 | 22 | [MethodImplAttribute(MethodImplOptions.InternalCall)] 23 | static extern void Release(IntPtr nativeNodejsFunc); 24 | 25 | Func> GetFunc() 26 | { 27 | return new Func>(this.FunctionWrapper); 28 | } 29 | 30 | Task FunctionWrapper(object payload) 31 | { 32 | NodejsFuncInvokeContext ctx = new NodejsFuncInvokeContext(this, payload); 33 | ExecuteActionOnV8Thread(ctx.CallFuncOnV8Thread); 34 | 35 | return ctx.TaskCompletionSource.Task; 36 | } 37 | 38 | [MethodImplAttribute(MethodImplOptions.InternalCall)] 39 | static extern void ExecuteActionOnV8Thread(Action action); 40 | }; 41 | -------------------------------------------------------------------------------- /src/mono/nodejsfuncinvokecontext.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | NAN_METHOD(v8FuncCallback) 4 | { 5 | DBG("v8FuncCallback"); 6 | Nan::HandleScope scope; 7 | v8::Local correlator = v8::Local::Cast(info[2]); 8 | NodejsFuncInvokeContext* context = (NodejsFuncInvokeContext*)(correlator->Value()); 9 | if (!info[0]->IsUndefined() && !info[0]->IsNull()) 10 | { 11 | context->Complete((MonoObject*)exceptionV82stringCLR(info[0]), NULL); 12 | } 13 | else 14 | { 15 | // TODO add support for exceptions during marshaling: 16 | MonoObject* result = ClrFunc::MarshalV8ToCLR(info[1]); 17 | context->Complete(NULL, result); 18 | } 19 | info.GetReturnValue().SetUndefined(); 20 | } 21 | 22 | 23 | NodejsFuncInvokeContext::NodejsFuncInvokeContext(MonoObject* _this) 24 | { 25 | DBG("NodejsFuncInvokeContext::NodejsFuncInvokeContext"); 26 | 27 | this->_this = mono_gchandle_new(_this, FALSE); // released in Complete 28 | } 29 | 30 | NodejsFuncInvokeContext::~NodejsFuncInvokeContext() 31 | { 32 | mono_gchandle_free(this->_this); 33 | } 34 | 35 | void NodejsFuncInvokeContext::CallFuncOnV8Thread(MonoObject* _this, NodejsFunc* nativeNodejsFunc, MonoObject* payload) 36 | { 37 | DBG("NodejsFuncInvokeContext::CallFuncOnV8Thread"); 38 | 39 | static Nan::Persistent callbackFactory; 40 | static Nan::Persistent callbackFunction; 41 | 42 | Nan::HandleScope scope; 43 | NodejsFuncInvokeContext* ctx = new NodejsFuncInvokeContext(_this); 44 | 45 | MonoException* exc = NULL; 46 | v8::Local jspayload = ClrFunc::MarshalCLRToV8(payload, &exc); 47 | if (exc) 48 | { 49 | ctx->Complete((MonoObject*)exc, NULL); 50 | // ctx deleted in Complete 51 | } 52 | else 53 | { 54 | // See https://github.com/tjanczuk/edge/issues/125 for context 55 | 56 | if (callbackFactory.IsEmpty()) 57 | { 58 | v8::Local v8FuncCallbackFunction = Nan::New(v8FuncCallback)->GetFunction(); 59 | callbackFunction.Reset(v8FuncCallbackFunction); 60 | v8::Local code = Nan::New( 61 | "(function (cb, ctx) { return function (e, d) { return cb(e, d, ctx); }; })").ToLocalChecked(); 62 | v8::Local callbackFactoryFunction = v8::Local::Cast(v8::Script::Compile(code)->Run()); 63 | callbackFactory.Reset(callbackFactoryFunction); 64 | } 65 | 66 | v8::Local factoryArgv[] = { Nan::New(callbackFunction), Nan::New((void*)ctx) }; 67 | v8::Local callback = v8::Local::Cast( 68 | Nan::New(callbackFactory)->Call(Nan::GetCurrentContext()->Global(), 2, factoryArgv)); 69 | 70 | v8::Local argv[] = { jspayload, callback }; 71 | Nan::TryCatch tryCatch; 72 | DBG("NodejsFuncInvokeContext::CallFuncOnV8Thread calling JavaScript function"); 73 | Nan::New(*(nativeNodejsFunc->Func))->Call(Nan::GetCurrentContext()->Global(), 2, argv); 74 | DBG("NodejsFuncInvokeContext::CallFuncOnV8Thread called JavaScript function"); 75 | if (tryCatch.HasCaught()) 76 | { 77 | DBG("NodejsFuncInvokeContext::CallFuncOnV8Thread caught JavaScript exception"); 78 | ctx->Complete((MonoObject*)exceptionV82stringCLR(tryCatch.Exception()), NULL); 79 | // ctx deleted in Complete 80 | } 81 | 82 | // In the absence of exception, processing resumes in v8FuncCallback 83 | } 84 | } 85 | 86 | void NodejsFuncInvokeContext::Complete(MonoObject* exception, MonoObject* result) 87 | { 88 | DBG("NodejsFuncInvokeContext::Complete"); 89 | 90 | static MonoMethod* method; 91 | 92 | if (!method) 93 | { 94 | MonoClass* klass = mono_class_from_name(MonoEmbedding::GetImage(), "", "NodejsFuncInvokeContext"); 95 | method = mono_class_get_method_from_name(klass, "Complete", 2); 96 | } 97 | 98 | void* args[] = { exception, result }; 99 | mono_runtime_invoke(method, mono_gchandle_get_target(this->_this), args, NULL); 100 | delete this; 101 | } 102 | 103 | // vim: ts=4 sw=4 et: 104 | -------------------------------------------------------------------------------- /src/mono/nodejsfuncinvokecontext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using System.Runtime.CompilerServices; 4 | 5 | class NodejsFuncInvokeContext { 6 | NodejsFunc functionContext; 7 | object payload; 8 | 9 | public TaskCompletionSource TaskCompletionSource { get; set; } 10 | 11 | public NodejsFuncInvokeContext(NodejsFunc functionContext, object payload) 12 | { 13 | this.functionContext = functionContext; 14 | this.payload = payload; 15 | this.TaskCompletionSource = new TaskCompletionSource(); 16 | } 17 | 18 | public void CallFuncOnV8Thread() 19 | { 20 | // This function must run on V8 thread 21 | CallFuncOnV8ThreadInternal( 22 | this, this.functionContext.NativeNodejsFunc, this.payload); 23 | } 24 | 25 | [MethodImplAttribute(MethodImplOptions.InternalCall)] 26 | static extern void CallFuncOnV8ThreadInternal(NodejsFuncInvokeContext _this, IntPtr nativeNodejsFunc, object payload); 27 | 28 | public void Complete(object exception, object result) 29 | { 30 | Task.Run(() => { 31 | if (exception != null) 32 | { 33 | var e = exception as Exception; 34 | var s = exception as string; 35 | if (e != null) 36 | { 37 | this.TaskCompletionSource.SetException(e); 38 | } 39 | else if (!string.IsNullOrEmpty(s)) 40 | { 41 | this.TaskCompletionSource.SetException(new Exception(s)); 42 | } 43 | else 44 | { 45 | this.TaskCompletionSource.SetException( 46 | new InvalidOperationException("Unrecognized exception received from JavaScript.")); 47 | } 48 | } 49 | else 50 | { 51 | this.TaskCompletionSource.SetResult(result); 52 | } 53 | }); 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /src/mono/task.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | TaskStatus Task::Status(MonoObject* _this) 4 | { 5 | MonoProperty* prop = mono_class_get_property_from_name(mono_object_get_class(_this), "Status"); 6 | MonoObject* statusBoxed = mono_property_get_value(prop, _this, NULL, NULL); 7 | TaskStatus status = *(TaskStatus*)mono_object_unbox(statusBoxed); 8 | return status; 9 | } 10 | 11 | MonoException* Task::Exception(MonoObject* _this) 12 | { 13 | MonoProperty* prop = mono_class_get_property_from_name(mono_object_get_class(_this), "Exception"); 14 | MonoObject* exception = mono_property_get_value(prop, _this, NULL, NULL); 15 | return (MonoException*)exception; 16 | } 17 | 18 | MonoObject* Task::Result(MonoObject* _this) 19 | { 20 | MonoProperty* prop = mono_class_get_property_from_name(mono_object_get_class(_this), "Result"); 21 | MonoObject* result = mono_property_get_value(prop, _this, NULL, NULL); 22 | return result; 23 | } 24 | -------------------------------------------------------------------------------- /src/mono/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | 3 | v8::Local stringCLR2V8(MonoString* text) 4 | { 5 | Nan::EscapableHandleScope scope; 6 | return scope.Escape(Nan::New( 7 | mono_string_chars(text), 8 | mono_string_length(text)).ToLocalChecked()); 9 | } 10 | 11 | MonoString* stringV82CLR(v8::Handle text) 12 | { 13 | Nan::HandleScope scope; 14 | v8::String::Utf8Value utf8text(text); 15 | return mono_string_new(mono_domain_get(), *utf8text); 16 | } 17 | 18 | MonoString* exceptionV82stringCLR(v8::Handle exception) 19 | { 20 | Nan::HandleScope scope; 21 | if (exception->IsObject()) 22 | { 23 | v8::Handle stack = exception->ToObject()->Get(Nan::New("stack").ToLocalChecked()); 24 | if (stack->IsString()) 25 | { 26 | return stringV82CLR(stack->ToString()); 27 | } 28 | } 29 | 30 | return stringV82CLR(v8::Handle::Cast(exception)); 31 | } 32 | -------------------------------------------------------------------------------- /test/101_edge_func.js: -------------------------------------------------------------------------------- 1 | var edge = require('../lib/edge.js'), assert = require('assert') 2 | , path = require('path'); 3 | 4 | var edgeTestDll = process.env.EDGE_USE_CORECLR ? 'test' : path.join(__dirname, 'Edge.Tests.dll'); 5 | 6 | describe('edge.func', function () { 7 | 8 | it('exists', function () { 9 | assert.equal(typeof edge.func, 'function'); 10 | }); 11 | 12 | it('fails without parameters', function () { 13 | assert.throws( 14 | edge.func, 15 | /Specify the source code as string or provide an options object/ 16 | ); 17 | }); 18 | 19 | it('fails with a wrong parameter', function () { 20 | assert.throws( 21 | function () { edge.func(12); }, 22 | /Specify the source code as string or provide an options object/ 23 | ); 24 | }); 25 | 26 | it('fails with a wrong language parameter', function () { 27 | assert.throws( 28 | function () { edge.func(12, 'somescript'); }, 29 | /The first argument must be a string identifying the language compiler to use/ 30 | ); 31 | }); 32 | 33 | it('fails with a unsupported language parameter', function () { 34 | assert.throws( 35 | function () { edge.func('idontexist', 'somescript'); }, 36 | /Unsupported language 'idontexist'/ 37 | ); 38 | }); 39 | 40 | it('fails with missing assemblyFile or source', function () { 41 | assert.throws( 42 | function () { edge.func({}); }, 43 | /Provide DLL or source file name or .NET script literal as a string parmeter, or specify an options object/ 44 | ); 45 | }); 46 | 47 | it('fails with both assemblyFile or source', function () { 48 | assert.throws( 49 | function () { edge.func({ assemblyFile: 'foo.dll', source: 'async (input) => { return null; }'}); }, 50 | /Provide either an asseblyFile or source property, but not both/ 51 | ); 52 | }); 53 | 54 | it('fails with nonexisting assemblyFile', function () { 55 | assert.throws( 56 | function () { edge.func('idontexist.dll'); }, 57 | /System.IO.FileNotFoundException/ 58 | ); 59 | }); 60 | 61 | if (!process.env.EDGE_USE_CORECLR) { 62 | it('succeeds with assemblyFile as string', function () { 63 | var func = edge.func(edgeTestDll); 64 | assert.equal(typeof func, 'function'); 65 | }); 66 | 67 | it('succeeds with assemblyFile as options property', function () { 68 | var func = edge.func({ assemblyFile: edgeTestDll }); 69 | assert.equal(typeof func, 'function'); 70 | }); 71 | } 72 | 73 | it('succeeds with assemblyFile and type name', function () { 74 | var func = edge.func({ 75 | assemblyFile: edgeTestDll, 76 | typeName: 'Edge.Tests.Startup' 77 | }); 78 | assert.equal(typeof func, 'function'); 79 | }); 80 | 81 | it('fails with assemblyFile and nonexisting type name', function () { 82 | assert.throws( 83 | function () { 84 | edge.func({ 85 | assemblyFile: edgeTestDll, 86 | typeName: 'Edge.Tests.idontexist' 87 | }); 88 | }, 89 | /Could not load type 'Edge.Tests.idontexist'/ 90 | ); 91 | }); 92 | 93 | it('succeeds with assemblyFile, type name, and method name', function () { 94 | var func = edge.func({ 95 | assemblyFile: edgeTestDll, 96 | typeName: 'Edge.Tests.Startup', 97 | methodName: 'Invoke' 98 | }); 99 | assert.equal(typeof func, 'function'); 100 | }); 101 | 102 | it('fails with assemblyFile, type name and nonexisting method name', function () { 103 | assert.throws( 104 | function () { 105 | edge.func({ 106 | assemblyFile: edgeTestDll, 107 | typeName: 'Edge.Tests.Startup', 108 | methodName: 'idontexist' 109 | }); 110 | }, 111 | /Unable to access the CLR method to wrap through reflection/ 112 | ); 113 | }); 114 | }); -------------------------------------------------------------------------------- /test/105_node2net_sync.js: -------------------------------------------------------------------------------- 1 | var edge = require('../lib/edge.js'), assert = require('assert') 2 | , path = require('path'); 3 | 4 | var edgeTestDll = process.env.EDGE_USE_CORECLR ? 'test' : path.join(__dirname, 'Edge.Tests.dll'); 5 | 6 | describe('sync call from node.js to .net', function () { 7 | 8 | it('succeeds for hello world', function () { 9 | var func = edge.func({ 10 | assemblyFile: edgeTestDll, 11 | typeName: 'Edge.Tests.Startup', 12 | methodName: 'Invoke' 13 | }); 14 | var result = func('Node.js', true); 15 | assert.equal(result, '.NET welcomes Node.js'); 16 | }); 17 | 18 | it('succeeds for hello world when called sync and async', function (done) { 19 | // create the func 20 | var func = edge.func({ 21 | assemblyFile: edgeTestDll, 22 | typeName: 'Edge.Tests.Startup', 23 | methodName: 'Invoke' 24 | }); 25 | 26 | // call the func synchronously 27 | var result = func('Node.js', true); 28 | assert.equal(result, '.NET welcomes Node.js'); 29 | 30 | // call the same func asynchronously 31 | func('Node.js', function (error, result) { 32 | assert.ifError(error); 33 | assert.equal(result, '.NET welcomes Node.js'); 34 | done(); 35 | }); 36 | }); 37 | 38 | it('successfuly marshals data from node.js to .net', function () { 39 | var func = edge.func({ 40 | assemblyFile: edgeTestDll, 41 | typeName: 'Edge.Tests.Startup', 42 | methodName: 'MarshalIn' 43 | }); 44 | var payload = { 45 | a: 1, 46 | b: 3.1415, 47 | c: 'foo', 48 | d: true, 49 | e: false, 50 | f: new Buffer(10), 51 | g: [ 1, 'foo' ], 52 | h: { a: 'foo', b: 12 }, 53 | i: function (payload, callback) { }, 54 | j: new Date(Date.UTC(2013,07,30)) 55 | }; 56 | var result = func(payload, true); 57 | assert.equal(result, 'yes'); 58 | }); 59 | 60 | it('successfuly marshals .net exception thrown on v8 thread from .net to node.js', function () { 61 | var func = edge.func({ 62 | assemblyFile: edgeTestDll, 63 | typeName: 'Edge.Tests.Startup', 64 | methodName: 'NetExceptionTaskStart' 65 | }); 66 | assert.throws( 67 | function() { func(null, true); }, 68 | function (error) { 69 | if ((error instanceof Error) && error.Message.match(/Test .NET exception/)) { 70 | return true; 71 | } 72 | return false; 73 | }, 74 | 'Unexpected result' 75 | ); 76 | }); 77 | 78 | it('fails if C# method does not complete synchronously', function () { 79 | var func = edge.func({ 80 | assemblyFile: edgeTestDll, 81 | typeName: 'Edge.Tests.Startup', 82 | methodName: 'DelayedReturn' 83 | }); 84 | assert.throws( 85 | function() { func(null, true); }, 86 | / The JavaScript function was called synchronously but/ 87 | ); 88 | }); 89 | }); -------------------------------------------------------------------------------- /test/build.bat: -------------------------------------------------------------------------------- 1 | set SELF=%~dp0 2 | ver > nul 3 | 4 | IF "%EDGE_USE_CORECLR%"=="1" ( 5 | cmd /c "cd ""%SELF%"" && dotnet restore -f ..\tools\build\nuget -f ..\..\edge-cs\src\Edge.js.CSharp\bin\Release && dotnet build" 6 | 7 | IF %ERRORLEVEL% NEQ 0 ( 8 | ECHO Test restore failed 9 | EXIT /b -1 10 | ) 11 | ) ELSE ( 12 | csc /target:library /debug /out:"%SELF%\Edge.Tests.dll" "%SELF%\tests.cs" 13 | 14 | IF %ERRORLEVEL% NEQ 0 ( 15 | ECHO Test build failed 16 | EXIT /b -1 17 | ) 18 | ) -------------------------------------------------------------------------------- /test/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$(which dotnet 2>/dev/null)" ] 4 | then 5 | dotnet restore 6 | dotnet build 7 | cp bin/Debug/netcoreapp1.0/test.dll Edge.Tests.CoreClr.dll 8 | fi 9 | 10 | if [ -n "$(which mono 2>/dev/null)" ] 11 | then 12 | mcs /target:library /debug /out:Edge.Tests.dll tests.cs 13 | fi 14 | -------------------------------------------------------------------------------- /test/double/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | packages/ 3 | edge/ 4 | TestResults/ -------------------------------------------------------------------------------- /test/double/double_stress/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/double/double_stress/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("double_stress")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("double_stress")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("806b8070-743b-46f3-8178-5c1acd7badaf")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /test/double/double_stress/double_stress.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {51C38DFE-9FC5-4A14-A046-1F6EA3910904} 8 | Exe 9 | Properties 10 | double_stress 11 | double_stress 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | packages\Edge.js.4.0.0\lib\EdgeJs.dll 37 | True 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | PreserveNewest 55 | 56 | 57 | PreserveNewest 58 | 59 | 60 | 61 | 62 | 63 | PreserveNewest 64 | 65 | 66 | PreserveNewest 67 | 68 | 69 | PreserveNewest 70 | 71 | 72 | PreserveNewest 73 | 74 | 75 | 76 | 83 | -------------------------------------------------------------------------------- /test/double/double_stress/double_stress.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "double_stress", "double_stress.csproj", "{51C38DFE-9FC5-4A14-A046-1F6EA3910904}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {51C38DFE-9FC5-4A14-A046-1F6EA3910904}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {51C38DFE-9FC5-4A14-A046-1F6EA3910904}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {51C38DFE-9FC5-4A14-A046-1F6EA3910904}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {51C38DFE-9FC5-4A14-A046-1F6EA3910904}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /test/double/double_stress/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /test/double/double_test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("double_test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("double_test")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("787ea5a0-e995-417f-92d2-ae117b05ac40")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /test/double/double_test/double_test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "double_test", "double_test.csproj", "{721FC9B2-4747-48E7-B57D-1084FCE6D7D3}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {721FC9B2-4747-48E7-B57D-1084FCE6D7D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {721FC9B2-4747-48E7-B57D-1084FCE6D7D3}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {721FC9B2-4747-48E7-B57D-1084FCE6D7D3}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {721FC9B2-4747-48E7-B57D-1084FCE6D7D3}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /test/double/double_test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /test/hello_class.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | public class Startup 5 | { 6 | public async Task Invoke(object input) 7 | { 8 | return "Hello, " + input.ToString(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/hello_class.csx: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | public class Startup 5 | { 6 | public async Task Invoke(object input) 7 | { 8 | return "Hello, " + input.ToString(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/hello_lambda.csx: -------------------------------------------------------------------------------- 1 | async (input) => { return "Hello, " + input.ToString(); } 2 | -------------------------------------------------------------------------------- /test/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "frameworks": { 3 | "netcoreapp1.0": { 4 | "imports": [ 5 | "portable-net45+wp80+win8+wpa81+dnxcore50", 6 | "portable-dnxcore50+net45+win8+wp8+wpa81" 7 | ], 8 | "dependencies": { 9 | "System.Runtime": "4.1.0", 10 | "System.Dynamic.Runtime": "4.0.11", 11 | "System.Linq": "4.1.0", 12 | "System.Linq.Expressions": "4.1.0", 13 | "Microsoft.CSharp": "4.0.1", 14 | "System.Data.Common": "4.1.0", 15 | "System.Runtime.Loader": "4.0.0", 16 | "System.Reflection": "4.1.0", 17 | "System.Console": "4.0.0", 18 | "Newtonsoft.Json": "9.0.1", 19 | "System.Reflection.TypeExtensions": "4.1.0", 20 | "Microsoft.Extensions.DependencyModel": "1.0.0", 21 | "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", 22 | "Microsoft.NETCore.App": { 23 | "type": "platform", 24 | "version": "1.0.0" 25 | }, 26 | "Edge.js": "6.5.1", 27 | "Edge.js.CSharp": "1.2.0", 28 | "System.Xml.XmlSerializer": "4.0.11", 29 | "System.Xml.ReaderWriter": "4.0.11" 30 | } 31 | } 32 | }, 33 | 34 | "buildOptions": { 35 | "emitEntryPoint": true, 36 | "preserveCompilationContext": true, 37 | "compile": { 38 | "exclude": ["double/**/*.cs", "hello_class.cs"] 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/test.bat: -------------------------------------------------------------------------------- 1 | rem usage: test.bat [ia32|x64 {version}], e.g. test.bat x64 0.10.0 2 | @echo off 3 | set EDGE_APP_ROOT=%~dp0\bin\Debug\netcoreapp1.0 4 | set NODEEXE=node.exe 5 | set EDGE_USE_CORECLR= 6 | if "%1" neq "" if "%2" neq "" set NODEEXE=%~dp0\..\lib\native\win32\%1\%2\node.exe 7 | echo Using node.js: %NODEEXE% 8 | call "%~dp0\build.bat" 9 | if %ERRORLEVEL% NEQ 0 exit /b -1; 10 | pushd "%~dp0\.." 11 | "%NODEEXE%" "%APPDATA%\npm\node_modules\mocha\bin\mocha" -R spec 12 | set EDGE_USE_CORECLR=1 13 | REM set EDGE_DEBUG=1 14 | popd 15 | call "%~dp0\build.bat" 16 | if %ERRORLEVEL% NEQ 0 exit /b -1; 17 | pushd "%~dp0\.." 18 | "%NODEEXE%" "%APPDATA%\npm\node_modules\mocha\bin\mocha" -R spec -t 10000 19 | set EDGE_USE_CORECLR= 20 | set EDGE_DEBUG= 21 | popd 22 | echo Finished running tests using node.js: %NODEEXE% 23 | -------------------------------------------------------------------------------- /test/testall.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set SELF=%~dp0 4 | set run32=N 5 | set run64=N 6 | 7 | if "%1"=="" set run32=Y 8 | if "%1"=="ia32" set run32=Y 9 | if "%1"=="" set run64=Y 10 | if "%1"=="x64" set run64=Y 11 | 12 | if "%run32%"=="Y" ( 13 | call "%SELF%\test.bat" ia32 6.4.0 14 | call "%SELF%\test.bat" ia32 4.1.1 15 | call "%SELF%\test.bat" ia32 5.1.0 16 | call "%SELF%\test.bat" ia32 0.12.0 17 | call "%SELF%\test.bat" ia32 0.8.22 18 | call "%SELF%\test.bat" ia32 0.10.0 19 | ) 20 | 21 | if "%run64%"=="Y" ( 22 | call "%SELF%\test.bat" x64 6.4.0 23 | call "%SELF%\test.bat" x64 4.1.1 24 | call "%SELF%\test.bat" x64 5.1.0 25 | call "%SELF%\test.bat" x64 0.12.0 26 | call "%SELF%\test.bat" x64 0.8.22 27 | call "%SELF%\test.bat" x64 0.10.0 28 | ) -------------------------------------------------------------------------------- /tools/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set SELF=%~dp0 3 | if "%1" equ "" ( 4 | echo Usage: build.bat debug^|release "{version} {version}" ... 5 | echo e.g. build.bat release "0.8.22 0.10.0" 6 | exit /b -1 7 | ) 8 | 9 | SET FLAVOR=%1 10 | shift 11 | if "%FLAVOR%" equ "" set FLAVOR=release 12 | for %%i in (node.exe) do set NODEEXE=%%~$PATH:i 13 | if not exist "%NODEEXE%" ( 14 | echo Cannot find node.exe 15 | popd 16 | exit /b -1 17 | ) 18 | for %%i in ("%NODEEXE%") do set NODEDIR=%%~dpi 19 | SET DESTDIRROOT=%SELF%\..\lib\native\win32 20 | set VERSIONS= 21 | :harvestVersions 22 | if "%1" neq "" ( 23 | set VERSIONS=%VERSIONS% %1 24 | shift 25 | goto :harvestVersions 26 | ) 27 | if "%VERSIONS%" equ "" set VERSIONS=0.10.0 28 | pushd %SELF%\.. 29 | for %%V in (%VERSIONS%) do call :build ia32 x86 %%V 30 | for %%V in (%VERSIONS%) do call :build x64 x64 %%V 31 | popd 32 | 33 | exit /b 0 34 | 35 | :build 36 | 37 | set DESTDIR=%DESTDIRROOT%\%1\%3 38 | if exist "%DESTDIR%\node.exe" goto gyp 39 | if not exist "%DESTDIR%\NUL" mkdir "%DESTDIR%" 40 | echo Downloading node.exe %2 %3... 41 | node "%SELF%\download.js" %2 %3 "%DESTDIR%" 42 | if %ERRORLEVEL% neq 0 ( 43 | echo Cannot download node.exe %2 v%3 44 | exit /b -1 45 | ) 46 | 47 | :gyp 48 | 49 | echo Building edge.node %FLAVOR% for node.js %2 v%3 50 | set NODEEXE=%DESTDIR%\node.exe 51 | set GYP=%APPDATA%\npm\node_modules\node-gyp\bin\node-gyp.js 52 | if not exist "%GYP%" ( 53 | echo Cannot find node-gyp at %GYP%. Make sure to install with npm install node-gyp -g 54 | exit /b -1 55 | ) 56 | 57 | "%NODEEXE%" "%GYP%" configure build --target=1.6.2 --dist-url=https://atom.io/download/atom-shell --msvs_version=2015 -%FLAVOR% 58 | if %ERRORLEVEL% neq 0 ( 59 | echo Error building edge.node %FLAVOR% for node.js %2 v%3 60 | exit /b -1 61 | ) 62 | 63 | echo %DESTDIR% 64 | copy /y .\build\%FLAVOR%\edge_*.node "%DESTDIR%" 65 | if %ERRORLEVEL% neq 0 ( 66 | echo Error copying edge.node %FLAVOR% for node.js %2 v%3 67 | exit /b -1 68 | ) 69 | 70 | copy /y "%DESTDIR%\..\msvcr120.dll" "%DESTDIR%" 71 | if %ERRORLEVEL% neq 0 ( 72 | echo Error copying msvcr120.dll %FLAVOR% to %DESTDIR% 73 | exit /b -1 74 | ) 75 | 76 | echo Success building edge.node %FLAVOR% for node.js %2 v%3 77 | -------------------------------------------------------------------------------- /tools/build_double.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set SELF=%~dp0 3 | if "%1" equ "" ( 4 | echo Usage: build_double.bat {node_version} 5 | echo e.g. build_double.bat 5.9.1 6 | exit /b -1 7 | ) 8 | 9 | mkdir "%SELF%\build\nuget\content\edge" > nul 2>&1 10 | mkdir "%SELF%\build\nuget\lib\net40" > nul 2>&1 11 | mkdir "%SELF%\build\nuget\lib\netstandard1.6" > nul 2>&1 12 | mkdir "%SELF%\build\nuget\tools" > nul 2>&1 13 | mkdir "%SELF%\..\src\double\Edge.js\bin\Release\net40" > nul 2>&1 14 | 15 | if not exist "%SELF%\build\download.exe" ( 16 | csc /out:"%SELF%\build\download.exe" "%SELF%\download.cs" 17 | ) 18 | 19 | rem if not exist "%SELF%\build\unzip.exe" ( 20 | rem csc /out:"%SELF%\build\unzip.exe" /r:System.IO.Compression.FileSystem.dll "%SELF%\unzip.cs" 21 | rem ) 22 | 23 | if not exist "%SELF%\build\repl.exe" ( 24 | csc /out:"%SELF%\build\repl.exe" "%SELF%\repl.cs" 25 | ) 26 | 27 | if not exist "%SELF%\build\nuget.exe" ( 28 | "%SELF%\build\download.exe" http://nuget.org/nuget.exe "%SELF%\build\nuget.exe" 29 | ) 30 | 31 | if not exist "%SELF%\build\%1.zip" ( 32 | "%SELF%\build\download.exe" https://github.com/nodejs/node/archive/v%1.zip "%SELF%\build\%1.zip" 33 | ) 34 | 35 | if not exist "%SELF%\build\node-%1" ( 36 | rem "%SELF%\build\unzip.exe" "%SELF%\build\%1.zip" "%SELF%\build" 37 | pushd "%SELF%\build\" 38 | cscript //B ..\unzip.vbs %1.zip 39 | popd 40 | ) 41 | 42 | call :build_node %1 x86 43 | if %ERRORLEVEL% neq 0 exit /b -1 44 | call :build_node %1 x64 45 | if %ERRORLEVEL% neq 0 exit /b -1 46 | 47 | if not exist "%SELF%\build\node-%1-x86\node.exe" ( 48 | "%SELF%\build\download.exe" http://nodejs.org/dist/v%1/win-x86/node.exe "%SELF%\build\node-%1-x86\node.exe" 49 | ) 50 | 51 | if not exist "%SELF%\build\node-%1-x64\node.exe" ( 52 | "%SELF%\build\download.exe" http://nodejs.org/dist/v%1/win-x64/node.exe "%SELF%\build\node-%1-x64\node.exe" 53 | ) 54 | 55 | call :build_edge %1 x86 56 | if %ERRORLEVEL% neq 0 exit /b -1 57 | call :build_edge %1 x64 58 | if %ERRORLEVEL% neq 0 exit /b -1 59 | 60 | csc /out:"%SELF%\..\src\double\Edge.js\bin\Release\net40\EdgeJs.dll" /target:library "%SELF%\..\src\double\Edge.js\dotnet\EdgeJs.cs" 61 | if %ERRORLEVEL% neq 0 exit /b -1 62 | 63 | cd "%SELF%\..\src\double\Edge.js" 64 | dotnet restore 65 | if %ERRORLEVEL% neq 0 exit /b -1 66 | dotnet build --configuration Release --framework netstandard1.6 67 | if %ERRORLEVEL% neq 0 exit /b -1 68 | dotnet pack --configuration Release --no-build 69 | 70 | if %ERRORLEVEL% neq 0 ( 71 | echo Failure building Nuget package 72 | cd "%SELF%" 73 | exit /b -1 74 | ) 75 | 76 | cd "%SELF%" 77 | copy /y "%SELF%\..\src\double\Edge.js\bin\Release\*.nupkg" "%SELF%\build\nuget" 78 | echo SUCCESS. Nuget package at %SELF%\build\nuget 79 | 80 | exit /b 0 81 | 82 | :build_edge 83 | 84 | rem takes 2 parameters: 1 - node version, 2 - x86 or x64 85 | 86 | if exist "%SELF%\build\nuget\content\edge\%2\edge_nativeclr.node" exit /b 0 87 | 88 | set NODEEXE=%SELF%\build\node-%1-%2\node.exe 89 | set GYP=%APPDATA%\npm\node_modules\node-gyp\bin\node-gyp.js 90 | 91 | pushd "%SELF%\.." 92 | 93 | "%NODEEXE%" "%GYP%" configure --msvs_version=2013 94 | "%SELF%\build\repl.exe" ./build/edge_nativeclr.vcxproj "%USERPROFILE%\.node-gyp\%1\$(Configuration)\node.lib" "%SELF%\build\node-%1-%2\node.lib" 95 | "%NODEEXE%" "%GYP%" build 96 | mkdir "%SELF%\build\nuget\content\edge\%2" > nul 2>&1 97 | copy /y build\release\edge_nativeclr.node "%SELF%\build\nuget\content\edge\%2" 98 | copy /y "%SELF%\build\node-%1-%2\node.dll" "%SELF%\build\nuget\content\edge\%2" 99 | 100 | popd 101 | 102 | exit /b 0 103 | 104 | :build_node 105 | 106 | rem takes 2 parameters: 1 - node version, 2 - x86 or x64 107 | 108 | if exist "%SELF%\build\node-%1-%2\node.lib" exit /b 0 109 | 110 | pushd "%SELF%\build\node-%1" 111 | rmdir /s /q Release 112 | 113 | ..\repl.exe node.gyp "'executable'" "'shared_library'" 114 | if %ERRORLEVEL% neq 0 ( 115 | echo Cannot update node.gyp 116 | popd 117 | exit /b -1 118 | ) 119 | 120 | call vcbuild.bat build release %2 121 | mkdir "%SELF%\build\node-%1-%2" 122 | copy /y .\Release\node.* "%SELF%\build\node-%1-%2" 123 | echo Finished building Node shared library %1 124 | 125 | popd 126 | exit /b 0 -------------------------------------------------------------------------------- /tools/buildall.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | "%~dp0\build.bat" release 0.8.22 0.10.0 0.12.0 4.1.1 5.1.0 6.4.0 3 | -------------------------------------------------------------------------------- /tools/checkplatform.js: -------------------------------------------------------------------------------- 1 | try { 2 | require('../lib/edge.js'); 3 | } 4 | catch (e) { 5 | console.log('***************************************'); 6 | console.log(e); 7 | console.log('***************************************'); 8 | } 9 | 10 | console.log('Success: platform check for edge.js: node.js ' + process.arch + ' v' + process.versions.node); 11 | -------------------------------------------------------------------------------- /tools/download.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | class Program 5 | { 6 | public static void Main(string[] args) 7 | { 8 | if (args.Length != 2) { 9 | throw new InvalidOperationException("Usage: download.exe "); 10 | } 11 | 12 | Console.WriteLine("Downloading " + args[0] + " to " + args[1] + "..."); 13 | var client = new WebClient(); 14 | client.DownloadFile(args[0], args[1]); 15 | Console.WriteLine("Done."); 16 | } 17 | } -------------------------------------------------------------------------------- /tools/download.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | 3 | var urls; 4 | if (process.argv[2] === 'x86') { 5 | urls = [ 6 | 'http://nodejs.org/dist/v' + process.argv[3] + '/node.exe', 7 | 'http://nodejs.org/dist/v' + process.argv[3] + '/win-x86/node.exe' 8 | ]; 9 | } 10 | else { 11 | urls = [ 12 | 'http://nodejs.org/dist/v' + process.argv[3] + '/x64/node.exe', 13 | 'http://nodejs.org/dist/v' + process.argv[3] + '/win-x64/node.exe' 14 | ]; 15 | } 16 | 17 | try_get(0); 18 | 19 | function try_get(i) { 20 | console.log('Trying download from', urls[i]); 21 | http.get(urls[i], function (res) { 22 | console.log('HTTP', res.statusCode); 23 | if (res.statusCode !== 200) { 24 | if (++i === urls.length) 25 | throw new Error('Unable to download node.exe'); 26 | else 27 | try_get(i); 28 | } 29 | 30 | var stream = require('fs').createWriteStream(process.argv[4] + '/node.exe'); 31 | res.pipe(stream); 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /tools/install.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | var fs = require('fs') 3 | , path = require('path') 4 | , spawn = require('child_process').spawn 5 | , whereis = require('./whereis'); 6 | 7 | if (process.platform === 'win32') { 8 | var libroot = path.resolve(__dirname, '../lib/native/win32') 9 | , lib32bit = path.resolve(libroot, 'ia32') 10 | , lib64bit = path.resolve(libroot, 'x64'); 11 | 12 | function copyFile(filePath, filename) { 13 | return function(copyToDir) { 14 | fs.writeFileSync(path.resolve(copyToDir, filename), fs.readFileSync(filePath)); 15 | }; 16 | } 17 | 18 | function isDirectory(info) { 19 | return info.isDirectory; 20 | } 21 | 22 | function getInfo(basedir) { 23 | return function(file) { 24 | var filepath = path.resolve(basedir, file); 25 | 26 | return { 27 | path: filepath, 28 | isDirectory: fs.statSync(filepath).isDirectory() 29 | }; 30 | } 31 | } 32 | 33 | function getPath(info) { 34 | return info.path; 35 | } 36 | 37 | var dest32dirs = fs.readdirSync(lib32bit) 38 | .map(getInfo(lib32bit)) 39 | .filter(isDirectory) 40 | .map(getPath); 41 | 42 | ['msvcr120.dll', 'msvcp120.dll'].forEach(function (dllname) { 43 | var dll32bit = path.resolve(lib32bit, dllname); 44 | dest32dirs.forEach(copyFile(dll32bit, dllname)); 45 | }); 46 | 47 | var dest64dirs = fs.readdirSync(lib64bit) 48 | .map(getInfo(lib64bit)) 49 | .filter(isDirectory) 50 | .map(getPath); 51 | 52 | ['msvcr120.dll', 'msvcp120.dll'].forEach(function (dllname) { 53 | var dll64bit = path.resolve(lib64bit, dllname); 54 | dest64dirs.forEach(copyFile(dll64bit, dllname)); 55 | }); 56 | 57 | var dotnetPath = whereis('dotnet', 'dotnet.exe'); 58 | 59 | if (dotnetPath) { 60 | spawn(dotnetPath, ['restore'], { stdio: 'inherit', cwd: path.resolve(__dirname, '..', 'lib', 'bootstrap') }) 61 | .on('close', function() { 62 | spawn(dotnetPath, ['build', '--configuration', 'Release'], { stdio: 'inherit', cwd: path.resolve(__dirname, '..', 'lib', 'bootstrap') }) 63 | .on('close', function() { 64 | require('./checkplatform'); 65 | }); 66 | }); 67 | } 68 | 69 | else { 70 | require('./checkplatform'); 71 | } 72 | } 73 | 74 | else { 75 | if (process.platform === 'darwin') { 76 | 77 | // Code from electron-prebuild: https://github.com/electron/electron-rebuild 78 | const possibleModuleNames = ['electron', 'electron-prebuilt', 'electron-prebuilt-compile']; 79 | 80 | function locateElectronPrebuilt () { 81 | let electronPath; 82 | 83 | // Attempt to locate modules by path 84 | let foundModule = possibleModuleNames.some((moduleName) => { 85 | electronPath = path.join(__dirname, '..', '..', moduleName); 86 | return fs.existsSync(electronPath); 87 | }); 88 | 89 | // Return a path if we found one 90 | if (foundModule) return electronPath; 91 | 92 | // Attempt to locate modules by require 93 | foundModule = possibleModuleNames.some((moduleName) => { 94 | try { 95 | electronPath = path.join(require.resolve(moduleName), '..'); 96 | } catch (e) { 97 | return false; 98 | } 99 | return fs.existsSync(electronPath); 100 | }); 101 | 102 | // Return a path if we found one 103 | if (foundModule) return electronPath; 104 | return null; 105 | } 106 | 107 | location = locateElectronPrebuilt(); 108 | version = null; 109 | electronPath = null; 110 | if (location != null) 111 | { 112 | // NB: We assume here that electron-prebuilt is a sibling package of ours 113 | pkg = null; 114 | try { 115 | let pkgJson = path.join(location, 'package.json'); 116 | 117 | pkg = require(pkgJson); 118 | 119 | version = pkg.version; 120 | } catch (e) { 121 | console.error("Unable to find electron-prebuilt's version number, either install it or specify an explicit version"); 122 | } 123 | } 124 | if (version !== null) 125 | { 126 | spawn('node-gyp', ['configure', 'build', '--target='+version, '--disturl=https://atom.io/download/atom-shell'], { stdio: 'inherit' }); 127 | } 128 | else 129 | spawn('node-gyp', ['configure', 'build'], { stdio: 'inherit' }); 130 | 131 | } 132 | else { 133 | spawn('node-gyp', ['configure', 'build'], { stdio: 'inherit' }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /tools/nuget/edge.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Edge.js 5 | 5.9.1-rc2 6 | Tomasz Janczuk 7 | Tomasz Janczuk 8 | https://raw.githubusercontent.com/tjanczuk/edge/master/LICENSE.txt 9 | https://github.com/tjanczuk/edge 10 | 11 | false 12 | Script Node.js in a .NET application. 13 | With Edge.js you can script Node.js in a .NET application. Edge.js allows you to run Node.js and .NET code in one process. You can call Node.js functions from .NET and .NET functions from Node.js. Edge.js takes care of marshalling data between CLR and V8. Edge.js also reconciles threading models of single threaded V8 and multi-threaded CLR. Edge.js ensures correct lifetime of objects on V8 and CLR heaps. Edge.js NuGet package v5.9.1 supports scripting Node.js v5.9.1 with Edge.js v5.0.2. 14 | Copyright 2015 Tomasz Janczuk 15 | node.js node .net edge edge.js v8 clr coreclr mono interop javascript 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 | -------------------------------------------------------------------------------- /tools/nuget/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | function MarkDirectoryAsCopyToOutputRecursive($item) 4 | { 5 | $item.ProjectItems | ForEach-Object { MarkFileASCopyToOutputDirectory($_) } 6 | } 7 | 8 | function MarkFileASCopyToOutputDirectory($item) 9 | { 10 | Try 11 | { 12 | Write-Host Try set $item.Name 13 | $item.Properties.Item("CopyToOutputDirectory").Value = 2 14 | } 15 | Catch 16 | { 17 | Write-Host RecurseOn $item.Name 18 | MarkDirectoryAsCopyToOutputRecursive($item) 19 | } 20 | } 21 | 22 | MarkDirectoryAsCopyToOutputRecursive($project.ProjectItems.Item("edge")) 23 | -------------------------------------------------------------------------------- /tools/repl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | class Program 5 | { 6 | public static void Main(string[] args) 7 | { 8 | if (args.Length != 3) { 9 | throw new InvalidOperationException("Usage: repl.exe "); 10 | } 11 | 12 | Console.WriteLine("Replacing " + args[1] + " with " + args[2] + " in " + args[0] + "..."); 13 | var s = File.ReadAllText(args[0]); 14 | File.WriteAllText(args[0], s.Replace(args[1], args[2])); 15 | Console.WriteLine("Done."); 16 | } 17 | } -------------------------------------------------------------------------------- /tools/runJsHint.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var jshint = require('jshint').JSHINT; 3 | 4 | var foldersToLint = [ 5 | './lib', 6 | './test' 7 | ]; 8 | 9 | var utils = { 10 | errors: 0, 11 | 12 | readFile: function (filename) { 13 | return fs.readFileSync(filename, 'utf8'); 14 | }, 15 | 16 | lintFile: function (filename, config) { 17 | var results = jshint(this.readFile(filename), config.options, config.globals); 18 | if (!results) { 19 | this.errors++; 20 | this.renderResults(filename); 21 | } 22 | }, 23 | 24 | resolveFiles: function(folders) { 25 | var files = []; 26 | folders.forEach(function (dir) { 27 | var filesInFolder = fs.readdirSync(dir); 28 | var jsFiles = filesInFolder.filter(function (file) { 29 | return file.indexOf('.js') > 0; 30 | }).map(function (js) { 31 | return dir + '/' + js; 32 | }); 33 | 34 | files = files.concat(jsFiles); 35 | }); 36 | 37 | return files; 38 | }, 39 | 40 | renderResults: function (filename) { 41 | jshint.errors.forEach(function (e) { 42 | if (!e) { 43 | return; 44 | } 45 | console.error(filename + ': ' + e.code + ' ' + e.raw + ' at line: ' + e.line + ' character: ' + e.character); 46 | }); 47 | } 48 | }; 49 | 50 | var config = JSON.parse(utils.readFile('.jshintrc')); 51 | var filesToLint = utils.resolveFiles(foldersToLint); 52 | 53 | filesToLint.forEach(function (filename) { 54 | utils.lintFile(filename, config); 55 | }); 56 | 57 | if (utils.errors > 0) { 58 | return process.exit(1); 59 | } 60 | 61 | console.log('Success: no linting errors.'); -------------------------------------------------------------------------------- /tools/test.js: -------------------------------------------------------------------------------- 1 | var spawn = require('child_process').spawn; 2 | var path = require('path'); 3 | var testDir = path.resolve(__dirname, '../test'); 4 | var input = path.resolve(testDir, 'tests.cs'); 5 | var output = path.resolve(testDir, 'Edge.Tests.dll'); 6 | var buildParameters = ['-target:library', '/debug', '-out:' + output, input]; 7 | var mocha = path.resolve(__dirname, '../node_modules/mocha/bin/mocha'); 8 | var fs = require('fs'); 9 | 10 | if (!process.env.EDGE_USE_CORECLR) { 11 | if (process.platform !== 'win32') { 12 | buildParameters = buildParameters.concat(['-sdk:4.5']); 13 | } 14 | 15 | spawn(process.platform === 'win32' ? 'csc' : 'dmcs', buildParameters, { 16 | stdio: 'inherit' 17 | }).on('close', runOnSuccess); 18 | } 19 | 20 | else { 21 | spawn(process.platform === 'win32' ? 'dotnet.exe' : 'dotnet', ['restore'], { 22 | stdio: 'inherit', 23 | cwd: testDir 24 | }).on('close', function(code, signal) { 25 | if (code === 0) { 26 | spawn(process.platform === 'win32' ? 'dotnet.exe' : 'dotnet', ['build'], { 27 | stdio: 'inherit', 28 | cwd: testDir 29 | }).on('close', runOnSuccess); 30 | } 31 | }); 32 | } 33 | 34 | function runOnSuccess(code, signal) { 35 | if (code === 0) { 36 | process.env['EDGE_APP_ROOT'] = path.join(testDir, 'bin', 'Debug', 'netcoreapp1.0'); 37 | 38 | spawn('node', [mocha, testDir, '-R', 'spec', '-t', '10000', '-gc'], { 39 | stdio: 'inherit' 40 | }).on('error', function(err) { 41 | console.log(err); 42 | }); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tools/unzip.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO.Compression; 3 | 4 | class Program 5 | { 6 | public static void Main(string[] args) 7 | { 8 | if (args.Length != 2) { 9 | throw new InvalidOperationException("Usage: unzip.exe "); 10 | } 11 | 12 | Console.WriteLine("Unziping " + args[0] + " to " + args[1] + "..."); 13 | ZipFile.ExtractToDirectory(args[0], args[1]); 14 | Console.WriteLine("Done."); 15 | } 16 | } -------------------------------------------------------------------------------- /tools/unzip.vbs: -------------------------------------------------------------------------------- 1 | ' UnZip a file script 2 | ' 3 | ' By Justin Godden 2010 4 | ' 5 | ' It's a mess, I know!!! 6 | ' 7 | 8 | ' Dim ArgObj, var1, var2 9 | Set ArgObj = WScript.Arguments 10 | 11 | If (Wscript.Arguments.Count > 0) Then 12 | var1 = ArgObj(0) 13 | Else 14 | var1 = "" 15 | End if 16 | 17 | If var1 = "" then 18 | strFileZIP = "example.zip" 19 | Else 20 | strFileZIP = var1 21 | End if 22 | 23 | 'The location of the zip file. 24 | REM Set WshShell = CreateObject("Wscript.Shell") 25 | REM CurDir = WshShell.ExpandEnvironmentStrings("%%cd%%") 26 | Dim sCurPath 27 | sCurPath = CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(".") 28 | strZipFile = sCurPath & "\" & strFileZIP 29 | 'The folder the contents should be extracted to. 30 | outFolder = sCurPath & "\" 31 | 32 | WScript.Echo ( "Extracting file " & strFileZIP) 33 | 34 | Set objShell = CreateObject( "Shell.Application" ) 35 | Set objSource = objShell.NameSpace(strZipFile).Items() 36 | Set objTarget = objShell.NameSpace(outFolder) 37 | intOptions = 256 38 | objTarget.CopyHere objSource, intOptions 39 | 40 | WScript.Echo ( "Extracted." ) 41 | 42 | ' This bit is for testing purposes 43 | REM Dim MyVar 44 | REM MyVar = MsgBox ( strZipFile, 65, "MsgBox Example" -------------------------------------------------------------------------------- /tools/whereis.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | 4 | module.exports = function() { 5 | var pathSep = process.platform === 'win32' ? ';' : ':'; 6 | 7 | var directories = process.env.PATH.split(pathSep); 8 | 9 | for (var i = 0; i < directories.length; i++) { 10 | for (var j = 0; j < arguments.length; j++) { 11 | var filename = arguments[j]; 12 | var filePath = path.join(directories[i], filename); 13 | 14 | if (fs.existsSync(filePath)) { 15 | return filePath; 16 | } 17 | } 18 | } 19 | 20 | return null; 21 | } --------------------------------------------------------------------------------