aspclassic-core/AspClassic.Scripting/Hosting/ScriptRuntime.cs
Jelle Luteijn 484dbfc9d9 progress
2022-05-15 11:19:49 +02:00

309 lines
8.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.IO;
using System.Reflection;
using System.Security.Permissions;
using System.Threading;
using AspClassic.Scripting.Runtime;
using AspClassic.Scripting.Utils;
namespace AspClassic.Scripting.Hosting;
public sealed class ScriptRuntime : MarshalByRefObject
{
private readonly Dictionary<LanguageContext, ScriptEngine> _engines;
private readonly ScriptDomainManager _manager;
private readonly InvariantContext _invariantContext;
private readonly ScriptIO _io;
private readonly ScriptHost _host;
private readonly ScriptRuntimeSetup _setup;
private readonly object _lock = new object();
private ScriptScope _globals;
private Scope _scopeGlobals;
private ScriptEngine _invariantEngine;
internal ScriptDomainManager Manager => _manager;
public ScriptHost Host => _host;
public ScriptIO IO => _io;
public ScriptRuntimeSetup Setup => _setup;
public ScriptScope Globals
{
get
{
Scope globals = _manager.Globals;
if (_scopeGlobals == globals)
{
return _globals;
}
lock (_lock)
{
if (_scopeGlobals != globals)
{
_globals = new ScriptScope(InvariantEngine, globals);
_scopeGlobals = globals;
}
return _globals;
}
}
set
{
ContractUtils.RequiresNotNull(value, "value");
lock (_lock)
{
_globals = value;
_manager.Globals = value.Scope;
}
}
}
public ObjectOperations Operations => InvariantEngine.Operations;
internal ScriptEngine InvariantEngine
{
get
{
if (_invariantEngine == null)
{
_invariantEngine = GetEngine(_invariantContext);
}
return _invariantEngine;
}
}
public ScriptRuntime(ScriptRuntimeSetup setup)
{
ContractUtils.RequiresNotNull(setup, "setup");
DlrConfiguration configuration = setup.ToConfiguration();
_setup = setup;
try
{
_host = (ScriptHost)Activator.CreateInstance(setup.HostType, Utils.CollectionExtensions.ToArray(setup.HostArguments));
}
catch (TargetInvocationException ex)
{
throw new InvalidImplementationException(Strings.InvalidCtorImplementation(setup.HostType, ex.InnerException.Message), ex.InnerException);
}
catch (Exception ex2)
{
throw new InvalidImplementationException(Strings.InvalidCtorImplementation(setup.HostType, ex2.Message), ex2);
}
ScriptHostProxy hostingProvider = new ScriptHostProxy(_host);
_manager = new ScriptDomainManager(hostingProvider, configuration);
_invariantContext = new InvariantContext(_manager);
_io = new ScriptIO(_manager.SharedIO);
_engines = new Dictionary<LanguageContext, ScriptEngine>();
_globals = new ScriptScope(GetEngineNoLockNoNotification(_invariantContext, out var _), _manager.Globals);
_host.SetRuntime(this);
if (!setup.Options.TryGetValue("NoDefaultReferences", out var value) || !Convert.ToBoolean(value))
{
LoadAssembly(typeof(string).Assembly);
LoadAssembly(typeof(Debug).Assembly);
}
}
public static ScriptRuntime CreateFromConfiguration()
{
return new ScriptRuntime(ScriptRuntimeSetup.ReadConfiguration());
}
public static ScriptRuntime CreateRemote(AppDomain domain, ScriptRuntimeSetup setup)
{
ContractUtils.RequiresNotNull(domain, "domain");
return (ScriptRuntime)domain.CreateInstanceAndUnwrap(typeof(ScriptRuntime).Assembly.FullName, typeof(ScriptRuntime).FullName, ignoreCase: false, BindingFlags.Default, null, new object[1] { setup }, null, null);
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
public override object InitializeLifetimeService()
{
return null;
}
public ScriptEngine GetEngine(string languageName)
{
ContractUtils.RequiresNotNull(languageName, "languageName");
if (!TryGetEngine(languageName, out var engine))
{
throw new ArgumentException($"Unknown language name: '{languageName}'");
}
return engine;
}
public ScriptEngine GetEngineByTypeName(string assemblyQualifiedTypeName)
{
ContractUtils.RequiresNotNull(assemblyQualifiedTypeName, "assemblyQualifiedTypeName");
return GetEngine(_manager.GetLanguageByTypeName(assemblyQualifiedTypeName));
}
public ScriptEngine GetEngineByFileExtension(string fileExtension)
{
ContractUtils.RequiresNotNull(fileExtension, "fileExtension");
if (!TryGetEngineByFileExtension(fileExtension, out var engine))
{
throw new ArgumentException($"Unknown file extension: '{fileExtension}'");
}
return engine;
}
public bool TryGetEngine(string languageName, out ScriptEngine engine)
{
if (!_manager.TryGetLanguage(languageName, out var language))
{
engine = null;
return false;
}
engine = GetEngine(language);
return true;
}
public bool TryGetEngineByFileExtension(string fileExtension, out ScriptEngine engine)
{
if (!_manager.TryGetLanguageByFileExtension(fileExtension, out var language))
{
engine = null;
return false;
}
engine = GetEngine(language);
return true;
}
internal ScriptEngine GetEngine(LanguageContext language)
{
ScriptEngine engineNoLockNoNotification;
bool freshEngineCreated;
lock (_engines)
{
engineNoLockNoNotification = GetEngineNoLockNoNotification(language, out freshEngineCreated);
}
if (freshEngineCreated && !object.ReferenceEquals(language, _invariantContext))
{
_host.EngineCreated(engineNoLockNoNotification);
}
return engineNoLockNoNotification;
}
private ScriptEngine GetEngineNoLockNoNotification(LanguageContext language, out bool freshEngineCreated)
{
if (freshEngineCreated = !_engines.TryGetValue(language, out var value))
{
value = new ScriptEngine(this, language);
Thread.MemoryBarrier();
_engines.Add(language, value);
}
return value;
}
public ScriptScope CreateScope()
{
return InvariantEngine.CreateScope();
}
public ScriptScope CreateScope(string languageId)
{
return GetEngine(languageId).CreateScope();
}
public ScriptScope CreateScope(IDynamicMetaObjectProvider storage)
{
return InvariantEngine.CreateScope(storage);
}
public ScriptScope CreateScope(string languageId, IDynamicMetaObjectProvider storage)
{
return GetEngine(languageId).CreateScope(storage);
}
[Obsolete("IAttributesCollection is obsolete, use CreateScope(IDynamicMetaObjectProvider) instead")]
public ScriptScope CreateScope(IAttributesCollection dictionary)
{
return InvariantEngine.CreateScope(dictionary);
}
[Obsolete("IAttributesCollection is obsolete, use CreateScope(string, IDynamicMetaObjectProvider) instead")]
public ScriptScope CreateScope(string languageId, IAttributesCollection storage)
{
return GetEngine(languageId).CreateScope(storage);
}
public ScriptScope ExecuteFile(string path)
{
ContractUtils.RequiresNotEmpty(path, "path");
string extension = Path.GetExtension(path);
if (!TryGetEngineByFileExtension(extension, out var engine))
{
throw new ArgumentException($"File extension '{extension}' is not associated with any language.");
}
return engine.ExecuteFile(path);
}
public ScriptScope UseFile(string path)
{
ContractUtils.RequiresNotEmpty(path, "path");
string extension = Path.GetExtension(path);
if (!TryGetEngineByFileExtension(extension, out var engine))
{
throw new ArgumentException($"File extension '{extension}' is not associated with any language.");
}
ICollection<string> searchPaths = engine.GetSearchPaths();
if (searchPaths.Count == 0)
{
throw new InvalidOperationException($"No search paths defined for language '{engine.Setup.DisplayName}'");
}
foreach (string item in searchPaths)
{
string path2 = Path.Combine(item, path);
ScriptScope scope = engine.GetScope(path2);
if (scope != null)
{
return scope;
}
}
foreach (string item2 in searchPaths)
{
string path3 = Path.Combine(item2, path);
if (_manager.Platform.FileExists(path3))
{
return ExecuteFile(path3);
}
}
string arg = Utils.CollectionExtensions.Aggregate(searchPaths ,(string x, string y) => x + ", " + y);
throw new FileNotFoundException($"File '{path}' not found in language's search path: {arg}");
}
public void LoadAssembly(Assembly assembly)
{
_manager.LoadAssembly(assembly);
}
public ObjectOperations CreateOperations()
{
return InvariantEngine.CreateOperations();
}
public void Shutdown()
{
List<LanguageContext> list;
lock (_engines)
{
list = new List<LanguageContext>(_engines.Keys);
}
foreach (LanguageContext item in list)
{
item.Shutdown();
}
}
}