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 _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(); _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 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 list; lock (_engines) { list = new List(_engines.Keys); } foreach (LanguageContext item in list) { item.Shutdown(); } } }