191 lines
6.4 KiB
C#
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)
|
|
};
|
|
}
|
|
}
|