Files
spark/src/client/spark/view/Shell/ShellModel.cs
T

191 lines
6.4 KiB
C#

namespace mbts.ui {
using bts;
using bts.api.core;
using bts.config;
using bts.core;
using bts.shell;
using bts.spark;
using mbts.config;
using mbts.persist;
using mbts.spark;
using mbts.spark.utilities;
using mbts.ui.settings;
using mbts.ui.shell;
using Spark.Api.Reactive;
using Spark.Core.Data;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Composition;
using System.Composition.Convention;
using System.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
[Export]
public class ConfigSourceExporter {
[Export("config_source")]
public string config_source { get; set; }
}
// Models a generic multi-window host
public class ShellModel : IDisposable {
Lazy<CompositionHost> _container = new Lazy<CompositionHost>(create_container);
public CompositionHost container => _container.Value;
[Import]
public ui.shell.LoginContainer login { get; set; }
[Import]
public Lazy<UserTuple> user_tuple { get; set; }
[ImportMany]
public IEnumerable<IShellDaemon> services { get; set; }
[ImportMany]
public IEnumerable<IInitializable> initializers { get; set; }
[Import]
public ObservableCollection<IShellModule> Modules { get; set; }
[Export]
public ISecurityMetadataStore security_metadata_store =>
SecurityMetadataStore.instance;
public void Initialize(string config_source) {
PerformMEFComposition(config_source);
InitInitializers();
}
public void notify_delayed_load() {
foreach (var svc in initializers.OfType<IDelayLoad>()) {
svc.loaded();
}
foreach (var svc in services.OfType<IDelayLoad>()) {
svc.loaded();
}
}
static CompositionHost create_container() {
var rules = new ConventionBuilder();
rules.ForTypesDerivedFrom(typeof(object)).Shared();
var types = typeof(ShellModel).Assembly.GetTypes().Where(t => t.Name switch {
"NullableAttribute" or "NullableContextAttribute" => false,
_ => true
});
var configuration = new ContainerConfiguration()
.WithParts(types)
.WithDefaultConventions(rules);
string plugin_path = Configuration.get<bts.config.SystemConfig>().DataPath + "/plugins/";
if (Directory.Exists(plugin_path)) {
var assemblies = Directory.GetFiles(plugin_path, "*.dll")
.Select(AssemblyLoadContext.Default.LoadFromAssemblyPath);
configuration = configuration.WithAssemblies(assemblies);
}
return configuration.CreateContainer();
}
public T create<T>() where T : class {
T value = container.GetExport<T>();
return value;
}
void PerformMEFComposition(string config_source) {
Log.Ui.info($"Generating MEF dependencies for the shell " +
$"({typeof(IInitializable)}s, {typeof(IShellModule)}s, " +
$"{typeof(IShellDaemon)}s, etc.)");
try {
container.GetExport<ConfigSourceExporter>().config_source = config_source;
container.SatisfyImports(this);
} catch (ReflectionTypeLoadException rtlex) {
var message = new StringBuilder(rtlex.ToString());
foreach (var e in rtlex.LoaderExceptions) {
message.AppendLine("============================");
message.AppendLine(e.ToString());
}
Log.assert(false, message.ToString());
} catch (Exception ex) {
Log.assert(false, ex.Message);
}
}
private void InitInitializers() {
foreach (IInitializable i in initializers.OrderBy(i => i.priority)) {
Log.Ui.info("Initializing {0} prority {1}".fmt(i.GetType().ToString(), i.priority));
i.initialize();
}
}
public void Dispose() {
Modules.empty_if_null().Reverse().DisposeAll();
Modules = null;
services.empty_if_null().OfType<IDisposable>().DisposeAll();
services = null;
}
// This set of types is useful for troubleshooting MEF composition,
// specifically when a task calls for adding particular types to the
// composition host, rather than all types in this assembly.
static HashSet<Type> _base_dep_injection_types() => new() {
typeof(shell.LoginContainer),
typeof(WindowFactory),
typeof(ServiceContext),
typeof(Spark.ShellServices),
typeof(shell.LauncherVM),
typeof(OrdersModel),
typeof(SimpleBus),
typeof(ShellModuleCollection),
typeof(UserSettingsHub),
typeof(shell.WindowManager),
typeof(OrderFactory),
typeof(AlgoProviderFactory),
typeof(SecurityResolver),
typeof(AdminModel),
typeof(AlgoStudioFlatDefinitionModel),
typeof(AlgoTemplateMetadataService),
typeof(SpreaderModel),
typeof(MarketDataAuxiliaryModel),
typeof(UserUISettings),
typeof(BookmarksModel),
typeof(ShellThreadFactory),
typeof(WorkspacesModel),
typeof(mbts.ui.settings.SettingsCollector),
typeof(UndoModel),
typeof(NotificationService),
// The INotifier impl is private. Make it public to include it in
// this set and generate it in mef composition host.
// typeof(mbts.ui.BTSToastNotificationBox.Notifier),
// daemons
typeof(ErrorReporter),
typeof(MDDaemon),
typeof(SecurityPickerDaemon),
typeof(AnalyticsShellModule),
typeof(DeleteSyntheticDaemon),
typeof(OopsDaemon),
typeof(RecenterDaemon),
typeof(AnalyticsDaemon),
typeof(DiagnosticDaemon),
typeof(ModifyOrderDaemon),
typeof(OrderTicketDaemon),
typeof(GlobalAlertsDaemon),
typeof(RFQDaemon),
// modules
typeof(MarketShellModule),
typeof(TradingShellModule),
typeof(Spark.Trading.PositionModel),
typeof(ShellModel)
};
}
}