Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22bc4bb612 | ||
|
|
02ba484974 | ||
|
|
bc290e5bc6 | ||
|
|
752b9426a8 | ||
|
|
81529fdbe7 | ||
|
|
7dba037980 | ||
|
|
a7e684c720 |
No files matched your search
@@ -1,14 +1,15 @@
|
||||
namespace Spark.Console {
|
||||
using bts;
|
||||
|
||||
using mbts.config;
|
||||
|
||||
using Spark.Core;
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
class ConfigCommand {
|
||||
public static int run(ConfigCommandOptions opts) {
|
||||
Configuration.initialize(opts.sparkd);
|
||||
using var spark_init = new SparkInitializer(new(opts.sparkd));
|
||||
spark_init.init();
|
||||
var keys = opts.keys?.ToArray() ?? Array.Empty<string>();
|
||||
var excluded_keys = opts.excluded_keys?.ToArray() ?? Array.Empty<string>();
|
||||
return Configuration.run_config_query(
|
||||
|
||||
@@ -16,8 +16,10 @@ using System.Composition;
|
||||
|
||||
namespace Spark {
|
||||
class ShellServices {
|
||||
public ShellServices([Import("config_source")]string config_source) =>
|
||||
context = new(config_source);
|
||||
public ShellServices(
|
||||
[Import("config_source")] string config_source, [Import("verbose")] bool verbose) {
|
||||
context = new(config_source, verbose);
|
||||
}
|
||||
|
||||
[Export]
|
||||
public ServiceContext context { get; }
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
string user = null,
|
||||
string password = null,
|
||||
string config_source = null,
|
||||
bool? restore_workspace = null
|
||||
) : base(config_source) {
|
||||
bool? restore_workspace = null,
|
||||
bool verbose = false
|
||||
) : base(config_source, verbose) {
|
||||
// Get the LoginModel instance on this thread to make sure it performs syncronous config initialization.
|
||||
var login_model = LoginModel.init(config_source);
|
||||
// Show the dialog on a background thread so animations aren't blocked during the main application startup
|
||||
|
||||
@@ -42,6 +42,11 @@ namespace Spark.Cli {
|
||||
[Option(_SPARKD_OPT_NAME, MetaValue = "URL", HelpText = "The config server url")]
|
||||
public string? sparkd { get; set; }
|
||||
|
||||
[Option(
|
||||
"verbose",
|
||||
HelpText = "Enable verbose logging during startup (until [logging] config is loaded)")]
|
||||
public bool verbose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Conform opts to modern cli for backwards compatibility
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#nullable enable
|
||||
namespace Spark.Cli {
|
||||
using System.Composition;
|
||||
|
||||
[Export]
|
||||
class SparkCmdOptsExport {
|
||||
[Export("config_source")]
|
||||
public string? config_source { get; set; }
|
||||
|
||||
[Export("verbose")]
|
||||
public bool verbose { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ using mbts.ui.shell;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using Spark.Core;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@@ -23,12 +25,18 @@ using System.Windows.Threading;
|
||||
namespace mbts.ui.tests {
|
||||
[SetUpFixture]
|
||||
public class ApplicationSetup {
|
||||
static SparkInitializer _spark_init;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public static void setup() {
|
||||
// This is required to satisfy the StaticResources in various parts of the application
|
||||
if (Application.Current == null) {
|
||||
AutoResetEvent gonow = new AutoResetEvent(false);
|
||||
Configuration.initialize();
|
||||
if (_spark_init is not null) {
|
||||
throw new InvalidOperationException("spark_init already created");
|
||||
}
|
||||
_spark_init = new(new());
|
||||
_spark_init.init();
|
||||
Thread t = new Thread(() => {
|
||||
try {
|
||||
Assert.AreEqual(Thread.CurrentThread.GetApartmentState(), ApartmentState.STA);
|
||||
@@ -61,6 +69,7 @@ namespace mbts.ui.tests {
|
||||
if (Application.Current != null && Application.Current.Dispatcher != null) {
|
||||
Application.Current.Dispatcher.InvokeShutdown();
|
||||
}
|
||||
_spark_init?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Windows.Threading;
|
||||
namespace mbts.ui {
|
||||
public abstract class BTSApplicationBootstrapper : IDisposable {
|
||||
readonly string _config_source;
|
||||
readonly bool _verbose;
|
||||
|
||||
private ShellModel _model;
|
||||
|
||||
@@ -18,8 +19,9 @@ namespace mbts.ui {
|
||||
Dispatcher.CurrentDispatcher.UnhandledException += CurrentDispatcher_HandleClipboardError;
|
||||
}
|
||||
|
||||
protected BTSApplicationBootstrapper(string config_source = null) {
|
||||
protected BTSApplicationBootstrapper(string config_source = null, bool verbose = false) {
|
||||
_config_source = config_source;
|
||||
_verbose = verbose;
|
||||
}
|
||||
|
||||
public static void CurrentDispatcher_HandleClipboardError(object sender, DispatcherUnhandledExceptionEventArgs e) {
|
||||
@@ -43,7 +45,7 @@ namespace mbts.ui {
|
||||
|
||||
public void Run() {
|
||||
_model = new ShellModel();
|
||||
_model.Initialize(_config_source);
|
||||
_model.Initialize(_config_source, _verbose);
|
||||
CreateShell(_model);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
using mbts.ui.shell;
|
||||
|
||||
using Spark.Api.Reactive;
|
||||
using Spark.Cli;
|
||||
using Spark.Core.Data;
|
||||
|
||||
using System;
|
||||
@@ -28,12 +29,6 @@
|
||||
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);
|
||||
@@ -59,8 +54,8 @@
|
||||
public ISecurityMetadataStore security_metadata_store =>
|
||||
SecurityMetadataStore.instance;
|
||||
|
||||
public void Initialize(string config_source) {
|
||||
PerformMEFComposition(config_source);
|
||||
public void Initialize(string config_source, bool verbose) {
|
||||
PerformMEFComposition(config_source, verbose);
|
||||
InitInitializers();
|
||||
}
|
||||
|
||||
@@ -99,12 +94,14 @@
|
||||
return value;
|
||||
}
|
||||
|
||||
void PerformMEFComposition(string config_source) {
|
||||
void PerformMEFComposition(string config_source, bool verbose) {
|
||||
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;
|
||||
var cmd_opts = container.GetExport<SparkCmdOptsExport>();
|
||||
cmd_opts.config_source = config_source;
|
||||
cmd_opts.verbose = verbose;
|
||||
container.SatisfyImports(this);
|
||||
} catch (ReflectionTypeLoadException rtlex) {
|
||||
var message = new StringBuilder(rtlex.ToString());
|
||||
|
||||
@@ -7,13 +7,14 @@ namespace bts.api.core {
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reflection;
|
||||
using Spark.Core;
|
||||
|
||||
public sealed class ServiceContext : Spark.Api.IServiceProvider, IDisposable {
|
||||
IntPtr _qbus;
|
||||
AuthToken? _token;
|
||||
|
||||
public ServiceContext(string? config_source = null) {
|
||||
BTS.init(config_source);
|
||||
public ServiceContext(SparkInitializer initializer) {
|
||||
initializer.init();
|
||||
_qbus = ApiNativeMethods.api_create_quickbus(null, 0);
|
||||
}
|
||||
|
||||
@@ -26,9 +27,13 @@ namespace bts.api.core {
|
||||
|
||||
internal IntPtr native_context => _qbus;
|
||||
|
||||
public static ServiceContext create(string? config_server = null) {
|
||||
public static ServiceContext create(
|
||||
string? config_server = null,
|
||||
LogLevel console_level = LogLevel.NoLog,
|
||||
LogLevel syslog_level = LogLevel.NoLog
|
||||
) {
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
BTS.init(config_server, args);
|
||||
BTS.init(config_server, console_level, syslog_level, args);
|
||||
var qbus = ApiNativeMethods.api_create_quickbus(null, 0);
|
||||
return new ServiceContext(qbus);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Spark.Core {
|
||||
using bts;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.config;
|
||||
|
||||
using Spark.Core.Threading;
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
public sealed class SparkInitializer : InstanceLimiter<SparkInitializer>, IInstanceLimiter<SparkInitializer>, IDisposable {
|
||||
readonly SparkInitializerOpts _opts;
|
||||
int _state;
|
||||
|
||||
enum State {
|
||||
Uninitialized = 0,
|
||||
Initialized = 1,
|
||||
Disposed = 2
|
||||
}
|
||||
|
||||
public SparkInitializer(SparkInitializerOpts opts) {
|
||||
_opts = opts;
|
||||
}
|
||||
|
||||
~SparkInitializer() =>
|
||||
Dispose();
|
||||
|
||||
public void init() {
|
||||
if (_opts.is_test) {
|
||||
Configuration.initialize_for_test(
|
||||
_opts.config_source ?? string.Empty, (int)LogLevel.NoLog, (int)LogLevel.NoLog);
|
||||
}
|
||||
// Only perform initialization if current state is 'Uninitialized'
|
||||
if (Interlocked.CompareExchange(
|
||||
ref _state, (int)State.Initialized, (int)State.Uninitialized) != (int)State.Uninitialized) {
|
||||
return;
|
||||
}
|
||||
BTSNativeMethods.provide_command_line(_opts.args, _opts.args.Length);
|
||||
|
||||
var buffer = new StringBuilder(4096);
|
||||
bool config_ok = BTSNativeMethods.initialize_nothrow(
|
||||
_opts.config_source ?? string.Empty,
|
||||
(int)_opts.console_level,
|
||||
(int)_opts.syslog_level,
|
||||
buffer,
|
||||
buffer.Capacity);
|
||||
if (!config_ok) {
|
||||
throw new ApplicationException(buffer.ToString());
|
||||
}
|
||||
BTSNativeMethods.init_spark_lib();
|
||||
}
|
||||
|
||||
static int IInstanceLimiter<SparkInitializer>.max_instances => 1;
|
||||
|
||||
// Idempotent, thread-safe
|
||||
public void Dispose() {
|
||||
var prev_state = Interlocked.Exchange(ref _state, (int)State.Disposed);
|
||||
switch ((State)prev_state) {
|
||||
case State.Uninitialized:
|
||||
// Nothing to dispose
|
||||
break;
|
||||
case State.Initialized:
|
||||
// Tear down spark_lib
|
||||
BTSNativeMethods.finit_spark_lib();
|
||||
break;
|
||||
default:
|
||||
// Unexpected state
|
||||
throw new InvalidOperationException(
|
||||
$"Invalid/unknown SparkInitializer state '{prev_state}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Spark.Core {
|
||||
using bts;
|
||||
|
||||
using System;
|
||||
|
||||
public readonly struct SparkInitializerOpts {
|
||||
public SparkInitializerOpts(
|
||||
string? config_source = null,
|
||||
LogLevel console_level = LogLevel.NoLog,
|
||||
LogLevel syslog_level = LogLevel.NoLog,
|
||||
bool is_test = false)
|
||||
: this(config_source, console_level, syslog_level, is_test, Environment.GetCommandLineArgs()) { }
|
||||
|
||||
public SparkInitializerOpts(
|
||||
string? config_source,
|
||||
LogLevel console_level,
|
||||
LogLevel syslog_level,
|
||||
bool is_test,
|
||||
string[] args) {
|
||||
this.config_source = config_source;
|
||||
this.console_level = console_level;
|
||||
this.syslog_level = syslog_level;
|
||||
this.is_test = is_test;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public string? config_source { get; }
|
||||
public LogLevel console_level { get; }
|
||||
public LogLevel syslog_level { get; }
|
||||
public bool is_test { get; }
|
||||
public string[] args { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Spark.Core.Threading {
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
public interface IInstanceLimiter<T> where T : IInstanceLimiter<T> {
|
||||
private static int _num_instances;
|
||||
|
||||
static virtual int max_instances { get; } = 0;
|
||||
static virtual bool decrement_on_disposed { get; } = false;
|
||||
static virtual void on_created() {
|
||||
var max_instances = T.max_instances;
|
||||
if (Interlocked.Increment(ref _num_instances) >= max_instances) {
|
||||
throw new InvalidOperationException(
|
||||
$"Only {max_instances} instances of type '{typeof(T)}' allowed at a time");
|
||||
}
|
||||
}
|
||||
static virtual void on_disposed() {
|
||||
if (!T.decrement_on_disposed) {
|
||||
return;
|
||||
}
|
||||
if (Interlocked.Decrement(ref _num_instances) < 0) {
|
||||
throw new InvalidOperationException(
|
||||
$"More instances of type '{typeof(T)}' have been destroyed than were created in " +
|
||||
"the first place (invalid internal state)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class InstanceLimiter<T> where T : IInstanceLimiter<T> {
|
||||
protected InstanceLimiter() {
|
||||
T.on_created();
|
||||
}
|
||||
|
||||
~InstanceLimiter() {
|
||||
T.on_disposed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Spark.Core.Threading {
|
||||
using System.Threading;
|
||||
|
||||
/// <summary>
|
||||
/// A thread-safe toggle that can be flipped atomically
|
||||
/// </summary>
|
||||
struct InterlockedBool {
|
||||
int _int_value;
|
||||
|
||||
public bool is_enabled => _int_value == 1;
|
||||
|
||||
public bool value {
|
||||
get => _int_value == 1;
|
||||
set => toggle_to(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the undelrying value to the specified <paramref name="value"/>
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// True if the underlying value was changed, otherwise false (meaning the underlying value
|
||||
/// was already equal to the specified <paramref name="value"/>).
|
||||
/// </returns>
|
||||
public bool toggle_to(bool value) {
|
||||
var (newval, oldval) = value ? (1, 0) : (0, 1);
|
||||
return Interlocked.CompareExchange(ref _int_value, newval, oldval) == oldval;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,12 +65,9 @@ namespace mbts.config {
|
||||
_state = State.OK;
|
||||
}
|
||||
|
||||
public static void initialize_for_test(string config = "") {
|
||||
_raw_initialize_for_test(config);
|
||||
// still need init_spark_lib
|
||||
BTS.init();
|
||||
_state = State.OK;
|
||||
}
|
||||
[DllImport("libspark")]
|
||||
public static extern void initialize_for_test(
|
||||
string buffer, int console_level, int syslog_level);
|
||||
|
||||
public static unsafe bool try_initialize(out string error) {
|
||||
_reset();
|
||||
@@ -127,9 +124,6 @@ namespace mbts.config {
|
||||
[DllImport("libspark", EntryPoint = "initialize_nothrow")]
|
||||
static extern bool _initialize_nothrow(StringBuilder buffer, int length);
|
||||
|
||||
[DllImport("libspark", EntryPoint = "initialize_for_test")]
|
||||
static extern void _raw_initialize_for_test(string buffer);
|
||||
|
||||
[DllImport("libspark", EntryPoint = "reset")]
|
||||
static extern void _reset();
|
||||
}
|
||||
|
||||
@@ -9,17 +9,29 @@ namespace bts
|
||||
{
|
||||
static int _needs_init_spark_lib = 0;
|
||||
|
||||
public static void init(string config_source = null) {
|
||||
public static void init(string config_source = null, bool verbose = false) {
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
init(config_source, args);
|
||||
var (console_level, syslog_level) = verbose ?
|
||||
(LogLevel.Info, LogLevel.Diag) :
|
||||
(LogLevel.NoLog, LogLevel.NoLog);
|
||||
init(config_source, console_level, syslog_level, args);
|
||||
}
|
||||
|
||||
public static void init(string config_source = null, params string[] args) {
|
||||
public static void init(
|
||||
string config_source = null,
|
||||
LogLevel console_level = LogLevel.NoLog,
|
||||
LogLevel syslog_level = LogLevel.NoLog,
|
||||
params string[] args
|
||||
) {
|
||||
utils.BTSNativeMethods.provide_command_line(args, args.Length);
|
||||
|
||||
var buffer = new StringBuilder(4096);
|
||||
bool config_ok = utils.BTSNativeMethods.initialize_nothrow(
|
||||
config_source ?? string.Empty, buffer, buffer.Capacity);
|
||||
config_source ?? string.Empty,
|
||||
(int)console_level,
|
||||
(int)syslog_level,
|
||||
buffer,
|
||||
buffer.Capacity);
|
||||
if (!config_ok) {
|
||||
throw new ApplicationException(buffer.ToString());
|
||||
}
|
||||
@@ -34,34 +46,6 @@ namespace bts
|
||||
// };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or replaces the '-configserver' argument with <paramref name="config_server"/>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TODO: Clean up the cli, or consider getting rid of it and simply using config files as
|
||||
/// the exclusive means to pass arguments. The configserver override is particularly awkward
|
||||
/// because it is processed independently in c++ (see ConfigurationState::settings_path).
|
||||
/// </remarks>
|
||||
public static IEnumerable<string> set_config_arg(
|
||||
string[] args, string config_server) {
|
||||
const string CONFIG_SERVER_OPTION = "-configserver";
|
||||
bool has_emitted_cfg_server = false;
|
||||
for (int i = 0; i < args.Length;) {
|
||||
yield return args[i];
|
||||
if (args[i] == CONFIG_SERVER_OPTION) {
|
||||
has_emitted_cfg_server = true;
|
||||
yield return config_server;
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!has_emitted_cfg_server) {
|
||||
yield return CONFIG_SERVER_OPTION;
|
||||
yield return config_server;
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<string> remove_config_arg(string[] args) {
|
||||
int skip = 0;
|
||||
foreach (var arg in args) {
|
||||
|
||||
@@ -28,6 +28,10 @@ namespace bts.utils
|
||||
|
||||
[DllImport("libspark")]
|
||||
public static extern bool initialize_nothrow(
|
||||
string config_source, StringBuilder buffer, int length);
|
||||
string config_source,
|
||||
int console_level,
|
||||
int syslog_level,
|
||||
StringBuilder buffer,
|
||||
int length);
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,8 @@ CAPI Quickbus *api_create_quickbus(const char *qbconfig, long length) {
|
||||
// If config hasn't been initialized yet do it now and suppress exceptions.
|
||||
// When we're called from a nuget package we may not have defaults which can
|
||||
// cause errors
|
||||
config::initialize_nothrow("", nullptr, 0);
|
||||
config::initialize_nothrow(
|
||||
"", bts::Error.ordinal, bts::Warn.ordinal, nullptr, 0);
|
||||
|
||||
config::QuickbusNodeCfg cfg;
|
||||
if (length > 0 && qbconfig != nullptr &&
|
||||
|
||||
@@ -6,17 +6,8 @@ namespace bts {
|
||||
namespace config {
|
||||
namespace internal {
|
||||
|
||||
struct ConfigLog::PImpl {
|
||||
PImpl()
|
||||
: print_errors(true), logger_hub("config_logger"),
|
||||
logger(logger_hub.make_logger()) {}
|
||||
|
||||
bool print_errors;
|
||||
log::LoggerHub logger_hub;
|
||||
log::Logger &logger;
|
||||
};
|
||||
|
||||
ConfigLog::ConfigLog() : me(new PImpl()) {
|
||||
static log::LoggingConfig mk_config(
|
||||
log::Level console_level, log::Level syslog_level) {
|
||||
log::LoggingConfig cfg;
|
||||
cfg.level_names = {{Diag, "Diag"}, {Info, "Info"}, {Warn, "Warn"},
|
||||
{Error, "Error"}, {Fatal, "Fatal"}, {Sys, "Sys"}};
|
||||
@@ -29,12 +20,31 @@ ConfigLog::ConfigLog() : me(new PImpl()) {
|
||||
l = Warn;
|
||||
|
||||
cfg.deployment_type = "Config";
|
||||
f[log::Cfg.ordinal] = Warn;
|
||||
f[log::Cfg.ordinal] = console_level;
|
||||
cfg.sinks["console"] = std::make_pair(log::console_sink(cfg), f);
|
||||
f[log::Cfg.ordinal] = Info;
|
||||
f[log::Cfg.ordinal] = syslog_level;
|
||||
cfg.sinks["syslog"] = std::make_pair(log::syslog_sink(cfg), f);
|
||||
me->logger_hub.config(cfg);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
struct ConfigLog::PImpl {
|
||||
PImpl()
|
||||
: is_enabled(true), logger_hub("config_logger"),
|
||||
logger(logger_hub.make_logger()) {}
|
||||
|
||||
bool is_enabled;
|
||||
log::LoggerHub logger_hub;
|
||||
log::Logger &logger;
|
||||
};
|
||||
|
||||
ConfigLog::ConfigLog(bool verbose)
|
||||
: ConfigLog(verbose ? Diag : Warn, verbose ? Diag : Info, verbose) {}
|
||||
|
||||
ConfigLog::ConfigLog(
|
||||
bts::log::Level console_level, bts::log::Level syslog_level, bool is_enabled)
|
||||
: me(std::make_unique<PImpl>()) {
|
||||
me->is_enabled = is_enabled;
|
||||
me->logger_hub.config(mk_config(console_level, syslog_level));
|
||||
start();
|
||||
}
|
||||
|
||||
@@ -42,25 +52,28 @@ void ConfigLog::start() { me->logger_hub.start(); }
|
||||
|
||||
ConfigLog::~ConfigLog() { me->logger.mark_inactive(); }
|
||||
|
||||
bool ConfigLog::print_errors() const { return me->print_errors; }
|
||||
void ConfigLog::set_print_errors(bool value) { me->print_errors = value; }
|
||||
bool ConfigLog::is_enabled() const { return me->is_enabled; }
|
||||
void ConfigLog::set_is_enabled(bool value) { me->is_enabled = value; }
|
||||
|
||||
void ConfigLog::info(const std::string &msg) {
|
||||
if (me->print_errors)
|
||||
if (me->is_enabled) {
|
||||
me->logger.enqueue(
|
||||
log::log_ts(), log::Cfg, Info, __FILE__, __LINE__, "{0}", msg);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigLog::error(const std::string &msg) {
|
||||
if (me->print_errors)
|
||||
if (me->is_enabled) {
|
||||
me->logger.enqueue(
|
||||
log::log_ts(), log::Cfg, Error, __FILE__, __LINE__, "{0}", msg);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigLog::warning(const std::string &msg) {
|
||||
if (me->print_errors)
|
||||
if (me->is_enabled) {
|
||||
me->logger.enqueue(
|
||||
log::log_ts(), log::Cfg, Warn, __FILE__, __LINE__, "{0}", msg);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/logging/Common.h"
|
||||
#include "lib/utils/bts_no_copy.h"
|
||||
|
||||
#include <memory>
|
||||
@@ -22,15 +23,20 @@ class IConfigLog {
|
||||
// To allow config diagnostic logging
|
||||
class ConfigLog : public IConfigLog {
|
||||
public:
|
||||
ConfigLog();
|
||||
explicit ConfigLog(bool verbose = false);
|
||||
ConfigLog(
|
||||
bts::log::Level console_level,
|
||||
bts::log::Level syslog_level,
|
||||
bool is_enabled);
|
||||
|
||||
~ConfigLog();
|
||||
|
||||
void info(const std::string &msg);
|
||||
void error(const std::string &msg);
|
||||
void warning(const std::string &msg);
|
||||
|
||||
bool print_errors() const;
|
||||
void set_print_errors(bool value);
|
||||
bool is_enabled() const;
|
||||
void set_is_enabled(bool value);
|
||||
|
||||
private:
|
||||
void start();
|
||||
|
||||
@@ -97,7 +97,8 @@ void run_config_query(
|
||||
void ConfigQuerier::init_(bool verbose) {
|
||||
char buffer[4096] = {0};
|
||||
utils::TimeStamp start = utils::TimeStamp::now();
|
||||
bool success = config::initialize_nothrow("", buffer, sizeof(buffer));
|
||||
bool success = config::initialize_nothrow(
|
||||
"", bts::Warn.ordinal, bts::Warn.ordinal, buffer, sizeof(buffer));
|
||||
double time = (utils::TimeStamp::now() - start).seconds();
|
||||
|
||||
if (success) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lib/collections/Contains.h"
|
||||
#include "lib/core/FMT.h"
|
||||
#include "lib/io/ProtoPrinter.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/os/os.h"
|
||||
#include "lib/utils/bts_array_size.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
@@ -357,7 +358,7 @@ void check_rule(
|
||||
}
|
||||
|
||||
void ConfigurationState::check_rules() {
|
||||
initialize("");
|
||||
initialize("", bts::Error, bts::Warn);
|
||||
std::vector<std::shared_ptr<proto::Message>>::iterator iter;
|
||||
for (iter = _config_chain.begin(); iter != _config_chain.end(); ++iter) {
|
||||
proto::Message *message = (*iter).get();
|
||||
@@ -366,15 +367,16 @@ void ConfigurationState::check_rules() {
|
||||
check_rule(_defaults.get(), _rule_engine);
|
||||
}
|
||||
|
||||
void ConfigurationState::initialize_settings(string config_source) {
|
||||
void ConfigurationState::initialize_settings(
|
||||
string config_source,
|
||||
bts::log::Level console_verbosity,
|
||||
bts::log::Level syslog_verbosity) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_initialization_mutex);
|
||||
if (_is_initialized)
|
||||
return;
|
||||
|
||||
ConfigLog log;
|
||||
ConfigLog log{console_verbosity, syslog_verbosity, true};
|
||||
log.info(FMT("Initializing settings from '{}'", config_source));
|
||||
// For verbose config logs, uncomment line below
|
||||
// log.set_print_errors(true);
|
||||
initialize_defaults(log);
|
||||
|
||||
if (config_source.empty()) {
|
||||
@@ -420,7 +422,6 @@ int ConfigurationState::load(const std::string &url, IConfigLog &log) {
|
||||
std::shared_ptr<proto::Message> new_message(_prototype->New());
|
||||
|
||||
bool loaded = false;
|
||||
log.info(FMT("Loading '{}'", url));
|
||||
loaded = load_message(url, *new_message.get(), log, *_deferred_queue.get());
|
||||
if (_host.empty() || _host == "localhost") {
|
||||
const auto old_host = _host;
|
||||
@@ -450,9 +451,12 @@ int ConfigurationState::load(const std::string &url, IConfigLog &log) {
|
||||
}
|
||||
|
||||
int ConfigurationState::load_string(
|
||||
const std::string &values, bool print_errors) {
|
||||
const std::string &values,
|
||||
log::Level console_verbosity,
|
||||
log::Level syslog_verbosity) {
|
||||
ConfigLog log;
|
||||
log.set_print_errors(print_errors);
|
||||
log.set_is_enabled(
|
||||
console_verbosity != bts::NoLog || syslog_verbosity != bts::NoLog);
|
||||
initialize_defaults(log);
|
||||
|
||||
std::shared_ptr<proto::Message> new_message(_prototype->New());
|
||||
@@ -939,7 +943,7 @@ int load_directory(
|
||||
IConfigLog &log,
|
||||
ConfigValueQueue &lookup) {
|
||||
LogAggregator aggregate_log(log);
|
||||
aggregate_log.info(FMT("Loading config dir from '{}'", url));
|
||||
aggregate_log.info(FMT("Loading config dir '{}'", url));
|
||||
|
||||
const char last_char = url.at(url.length() - 1);
|
||||
if (last_char != '/') {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ConfigurationException.h"
|
||||
#include "lib/expression/ExpressionEvaluator.h"
|
||||
#include "lib/expression/Value.h"
|
||||
#include "lib/logging/logging.h"
|
||||
|
||||
#include "text_format/text_format.h"
|
||||
#include <google/protobuf/descriptor.h>
|
||||
@@ -60,10 +61,16 @@ class ConfigurationState {
|
||||
* @param config_source The source from which to load values. Can be a path
|
||||
* (file or dir), or URL (config server).
|
||||
*/
|
||||
void initialize_settings(std::string config_source = "");
|
||||
void initialize_settings(
|
||||
std::string config_source = "",
|
||||
bts::log::Level console_verbosity = bts::NoLog,
|
||||
bts::log::Level syslog_verbosity = bts::NoLog);
|
||||
|
||||
int load(const std::string &url, IConfigLog &);
|
||||
int load_string(const std::string &values, bool print_errors = false);
|
||||
int load_string(
|
||||
const std::string &values,
|
||||
log::Level console_verbosity = bts::NoLog,
|
||||
log::Level syslog_verbosity = bts::NoLog);
|
||||
void reset();
|
||||
|
||||
std::vector<const proto::FieldDescriptor *> get_fields(
|
||||
|
||||
+31
-10
@@ -20,6 +20,8 @@ namespace bts {
|
||||
namespace config {
|
||||
|
||||
using std::string;
|
||||
using std::int32_t;
|
||||
using LogLevel = bts::log::Level;
|
||||
|
||||
internal::ConfigurationState config_state;
|
||||
|
||||
@@ -27,18 +29,32 @@ internal::ConfigurationState config_state;
|
||||
// Public API
|
||||
//////////////////////////////////////////
|
||||
|
||||
extern "C" BTS_EXPORT void initialize(const char *config_source) {
|
||||
config_state.initialize_settings(string{config_source});
|
||||
extern "C" BTS_EXPORT void initialize(
|
||||
const char *config_source, int32_t console_level, int32_t syslog_level) {
|
||||
initialize(
|
||||
string{config_source}, log::log_level_from_int32(console_level),
|
||||
log::log_level_from_int32(syslog_level));
|
||||
}
|
||||
|
||||
void initialize(
|
||||
const string &config_source,
|
||||
LogLevel console_level,
|
||||
LogLevel syslog_level) {
|
||||
config_state.initialize_settings(config_source, console_level, syslog_level);
|
||||
}
|
||||
|
||||
extern "C" BTS_EXPORT bool initialize_nothrow(
|
||||
const char *config_source, char *error_message, size_t len) {
|
||||
const char *config_source,
|
||||
int32_t console_level,
|
||||
int32_t syslog_level,
|
||||
char *error_message,
|
||||
std::size_t length) {
|
||||
try {
|
||||
initialize(config_source);
|
||||
initialize(config_source, console_level, syslog_level);
|
||||
} catch (std::exception &e) {
|
||||
std::string msg = e.what();
|
||||
if (msg.size() < len) {
|
||||
os::strncpy(error_message, msg.c_str(), len);
|
||||
if (msg.size() < length) {
|
||||
os::strncpy(error_message, msg.c_str(), length);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -103,12 +119,17 @@ namespace internal {
|
||||
// Functions used in testing
|
||||
//////////////////////////////////////////
|
||||
|
||||
extern "C" BTS_EXPORT void initialize_for_test(const char *config) {
|
||||
initialize_for_test(std::string(config), false);
|
||||
extern "C" BTS_EXPORT void initialize_for_test(
|
||||
const char *config, int32_t console_level, int32_t syslog_level) {
|
||||
initialize_for_test(
|
||||
string(config), bts::log::log_level_from_int32(console_level),
|
||||
bts::log::log_level_from_int32(syslog_level));
|
||||
}
|
||||
void initialize_for_test(const std::string &values, bool print_errors) {
|
||||
|
||||
void initialize_for_test(
|
||||
const string &values, LogLevel console_level, LogLevel syslog_level) {
|
||||
config_state.reset();
|
||||
config_state.load_string(values, print_errors);
|
||||
config_state.load_string(values, console_level, syslog_level);
|
||||
}
|
||||
|
||||
extern "C" BTS_EXPORT void reset() { config_state.reset(); }
|
||||
|
||||
+22
-4
@@ -1,9 +1,11 @@
|
||||
#ifndef BTS_CONFIG_H_
|
||||
#define BTS_CONFIG_H_
|
||||
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/utils/bts_export.h"
|
||||
#include "lib/utils/checked_cast.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -27,12 +29,24 @@ namespace config {
|
||||
// config can result in network requests this function is available for
|
||||
// applications that want to manage pauses in execution. Ex: initialize() on a
|
||||
// background thread so that config::get<T>() is fast on a UI thread
|
||||
extern "C" BTS_EXPORT void initialize(const char *config_path);
|
||||
extern "C" BTS_EXPORT void initialize(
|
||||
const char *config_path,
|
||||
std::int32_t console_level,
|
||||
std::int32_t syslog_level);
|
||||
|
||||
void initialize(
|
||||
const std::string &config_source,
|
||||
bts::log::Level console_level = bts::Error,
|
||||
bts::log::Level syslog_level = bts::Warn);
|
||||
|
||||
// Calls initialize() but catches any thrown exception and copies it to the
|
||||
// provided buffer
|
||||
extern "C" BTS_EXPORT bool initialize_nothrow(
|
||||
const char *config_source, char *error_msg, size_t length);
|
||||
const char *config_source,
|
||||
std::int32_t console_level,
|
||||
std::int32_t syslog_level,
|
||||
char *error_message,
|
||||
size_t length);
|
||||
|
||||
std::vector<const google::protobuf::FieldDescriptor *> get_fields(
|
||||
const std::vector<std::string> keys = {},
|
||||
@@ -73,9 +87,13 @@ namespace internal {
|
||||
// Initialize configuration state from a string instead of from the filesystem.
|
||||
// defaults.conf will still be loaded. Calling this a second time clears all
|
||||
// values from previous initialization
|
||||
extern "C" BTS_EXPORT void initialize_for_test(const char *config);
|
||||
extern "C" BTS_EXPORT void initialize_for_test(
|
||||
const char *config, std::int32_t console_level, std::int32_t syslog_level);
|
||||
|
||||
void initialize_for_test(
|
||||
const std::string &configuration, bool print_errors = true);
|
||||
const std::string &values,
|
||||
log::Level console_level = Error,
|
||||
log::Level syslog_level = Warn);
|
||||
|
||||
// Releases all resources and returns config to factory defaults
|
||||
extern "C" BTS_EXPORT void reset();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../ConfigurationException.h"
|
||||
#include "../ConfigurationState.h"
|
||||
#include "../config.h"
|
||||
#include "lib/core/FMT.h"
|
||||
#include "lib/expression/ParserExceptions.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include "lib/utils/is_unittest_environment.h"
|
||||
@@ -97,7 +98,7 @@ TEST_CASE("Configuration Tests", "[config]") {
|
||||
|
||||
bool error = false;
|
||||
try {
|
||||
initialize_for_test("include: \"" + config_b.path() + "\"", false);
|
||||
initialize_for_test(FMT(R"(include: "{}")", config_b.path()));
|
||||
} catch (const ConfigurationException &err) {
|
||||
std::string what = err.what();
|
||||
bts_assert(what.find("Expected identifier.") != std::string::npos);
|
||||
@@ -331,12 +332,13 @@ TEST_CASE("Configuration Tests", "[config]") {
|
||||
}
|
||||
|
||||
SECTION("built_in_properties_test") {
|
||||
initialize_for_test("Foo { \n"
|
||||
" rule: \"SystemConfig.unittest_environment == true \"\n"
|
||||
" value {\n"
|
||||
" name: \"unit tests\"\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
initialize_for_test(
|
||||
"Foo { \n"
|
||||
" rule: \"SystemConfig.unittest_environment == true \"\n"
|
||||
" value {\n"
|
||||
" name: \"unit tests\"\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
|
||||
REQUIRE(get<Foo>().name() == "unit tests");
|
||||
}
|
||||
@@ -344,13 +346,11 @@ TEST_CASE("Configuration Tests", "[config]") {
|
||||
SECTION("nonbreaking_space_test") {
|
||||
bool parse_error = false;
|
||||
try {
|
||||
initialize_for_test(
|
||||
"Foo { "
|
||||
" value {\xA0\xA0 "
|
||||
" name: \"valid name\""
|
||||
" \xA0 }"
|
||||
"} ",
|
||||
false);
|
||||
initialize_for_test("Foo { "
|
||||
" value {\xA0\xA0 "
|
||||
" name: \"valid name\""
|
||||
" \xA0 }"
|
||||
"} ");
|
||||
} catch (const bts::config::ConfigurationException &) {
|
||||
parse_error = true;
|
||||
}
|
||||
@@ -407,42 +407,6 @@ TEST_CASE("Configuration Tests", "[config]") {
|
||||
REQUIRE(config::get<Foo>().name() == "good");
|
||||
}
|
||||
|
||||
SECTION("fallback_test") {
|
||||
// HTTPServer main;
|
||||
HTTPServer fallback;
|
||||
// std::string main_url = "http://localhost:" +
|
||||
// boost::lexical_cast<std::string>(main.port()) + "/";
|
||||
std::string main_url = "http://does_not_exist:12345/";
|
||||
// main.stop();
|
||||
std::string fallback_url =
|
||||
"http://127.0.0.1:" +
|
||||
boost::lexical_cast<std::string>(fallback.port()) + "/";
|
||||
std::string response = "HTTP/1.0 200 OK\r\n"
|
||||
"Content-Type: text/plain\r\n\r\n";
|
||||
|
||||
std::string content = "FooGroup {\n"
|
||||
" value {\n"
|
||||
" group: \"http_group\"\n"
|
||||
" foo {\n"
|
||||
" name: \"http\"\n"
|
||||
" id: 80\n"
|
||||
"}}}\n";
|
||||
|
||||
fallback.add_response("/spark.conf", response, content);
|
||||
|
||||
fallback.start();
|
||||
initialize_for_test(
|
||||
"include: '" + main_url +
|
||||
"'\n"
|
||||
"fallback: '" +
|
||||
fallback_url + "'\n",
|
||||
false);
|
||||
fallback.stop();
|
||||
|
||||
REQUIRE(get<FooGroup>().foo().name() == "http");
|
||||
REQUIRE(get<FooGroup>().foo().id() == 80);
|
||||
}
|
||||
|
||||
SECTION("macro_definition_order_test") {
|
||||
// The $is_crusible test
|
||||
// o2_cme_enabled depends on Foo which has a rule which depends on
|
||||
|
||||
@@ -11,20 +11,37 @@
|
||||
namespace bts {
|
||||
namespace log {
|
||||
|
||||
#define COMPARISON_OP(op, type, prop) \
|
||||
constexpr bool operator##op(const type &lhs, const type &rhs) { \
|
||||
return lhs.##prop op rhs.##prop; \
|
||||
}
|
||||
|
||||
struct Level {
|
||||
using Rep = uint8_t;
|
||||
constexpr static auto Max = (std::numeric_limits<Rep>::max)();
|
||||
Rep ordinal;
|
||||
bool operator<(const Level &rhs) const { return ordinal < rhs.ordinal; }
|
||||
};
|
||||
|
||||
COMPARISON_OP(==, Level, ordinal)
|
||||
COMPARISON_OP(!=, Level, ordinal)
|
||||
COMPARISON_OP(>, Level, ordinal)
|
||||
COMPARISON_OP(>=, Level, ordinal)
|
||||
COMPARISON_OP(<, Level, ordinal)
|
||||
COMPARISON_OP(<=, Level, ordinal)
|
||||
|
||||
struct Subsystem {
|
||||
using Rep = uint8_t;
|
||||
constexpr static auto Max = (std::numeric_limits<Rep>::max)();
|
||||
Rep ordinal;
|
||||
bool operator<(const Subsystem &rhs) const { return ordinal < rhs.ordinal; }
|
||||
};
|
||||
|
||||
COMPARISON_OP(==, Subsystem, ordinal)
|
||||
COMPARISON_OP(!=, Subsystem, ordinal)
|
||||
COMPARISON_OP(>, Subsystem, ordinal)
|
||||
COMPARISON_OP(>=, Subsystem, ordinal)
|
||||
COMPARISON_OP(<, Subsystem, ordinal)
|
||||
COMPARISON_OP(<=, Subsystem, ordinal)
|
||||
|
||||
using ArgBuffer = std::array<uint8_t, 156>;
|
||||
using MsgFormatter = std::string (*)(ArgBuffer const &, const char *);
|
||||
using Filter = std::array<Level, Subsystem::Max + 1>;
|
||||
@@ -45,5 +62,6 @@ inline uint64_t log_ts() {
|
||||
return result;
|
||||
}
|
||||
|
||||
#undef COMPARISON_OP
|
||||
} // namespace log
|
||||
} // namespace bts
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
|
||||
namespace bts {
|
||||
@@ -65,6 +66,8 @@ struct LoggerHandle {
|
||||
Logger *logger;
|
||||
};
|
||||
|
||||
constexpr Level log_level_from_int32(std::int32_t value);
|
||||
|
||||
struct CharPtrWrapper {
|
||||
const char *ptr;
|
||||
};
|
||||
@@ -102,6 +105,29 @@ class LoggingConfigPoller {
|
||||
|
||||
boost::filesystem::path log_path();
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Definition
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
constexpr Level log_level_from_int32(std::int32_t value) {
|
||||
switch (value) {
|
||||
case bts::Diag.ordinal:
|
||||
return Diag;
|
||||
case bts::Info.ordinal:
|
||||
return Info;
|
||||
case bts::Warn.ordinal:
|
||||
return Warn;
|
||||
case bts::Error.ordinal:
|
||||
return Error;
|
||||
case bts::Fatal.ordinal:
|
||||
return Fatal;
|
||||
case bts::Sys.ordinal:
|
||||
return Sys;
|
||||
default:
|
||||
return NoLog;
|
||||
}
|
||||
}
|
||||
|
||||
#define LOG(subsystem, level, ...) \
|
||||
bts::log::_thread_logger.logger->is_loggable(bts::log::subsystem, level) && \
|
||||
bts::log::_thread_logger.logger->enqueue( \
|
||||
|
||||
@@ -69,13 +69,8 @@ static void execute() {
|
||||
user::AuthServiceServer login_server(sc);
|
||||
|
||||
bts::md::MBOProcessor mbo_processor;
|
||||
auto *mbo_writer = config::get<config::toggles::PlacementInQueue>().enabled()
|
||||
? &mbo_processor.writer()
|
||||
: nullptr;
|
||||
bts::md::TradeSummarySignalDispatcher tss_dispatcher;
|
||||
md::cmds::Run::run(
|
||||
mbo_writer, &tss_dispatcher, md::cmds::Run::MDType::Configured, true,
|
||||
true);
|
||||
md::cmds::Run::run();
|
||||
|
||||
api::synthetic::SyntheticSecurityService synthetic_service(sc);
|
||||
bts::md::MDClient mdclient(
|
||||
|
||||
@@ -53,9 +53,9 @@ Web::Web()
|
||||
http::SparkWebServer webserver(sc, stats, perf_log, ports.config_port());
|
||||
|
||||
user::AuthServiceServer login_server(sc);
|
||||
if (_args->md)
|
||||
md::cmds::Run::run(
|
||||
nullptr, nullptr, md::cmds::Run::MDType::Configured, true, true);
|
||||
if (_args->md) {
|
||||
md::cmds::Run::run();
|
||||
}
|
||||
|
||||
bts::api::synthetic::SyntheticSecurityService synthetic_service(sc);
|
||||
bts::admin::AdminServiceServer admin_service(sc);
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "lib/os/os.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include "lib/utils/thread_manager.h"
|
||||
#include "server/sparkd/exchange_sim/ExchangeSim.h"
|
||||
#include "server/sparkd/md/platforms/IMDPlatform.h"
|
||||
#include "server/sparkd/md/platforms/ice_onixs/ICEMain.h"
|
||||
#include "server/sparkd/md/platforms/mdp3_onixs/MDP3Main.h"
|
||||
@@ -16,14 +15,6 @@
|
||||
|
||||
namespace bts::cmds::md::cmds {
|
||||
|
||||
static std::optional<std::thread> _md_thread;
|
||||
|
||||
std::string get_thread_name() {
|
||||
std::string rv;
|
||||
os::get_thread_name(&rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void boot_sleep() {
|
||||
auto conf = config::get<bts::md::MDBootDelayWindow>();
|
||||
const auto *start = &conf.standard_start();
|
||||
@@ -38,18 +29,18 @@ static void boot_sleep() {
|
||||
if (datetime::is_local_time_between(hh_start, mm_start, hh_end, mm_end)) {
|
||||
auto sleep_period = std::chrono::seconds(conf.delay_seconds());
|
||||
LOG(md, Info, "Run::boot_sleep t_id{} t_name:{} sleep_period:{}",
|
||||
os::get_thread_id(), get_thread_name(), sleep_period.count());
|
||||
os::get_thread_id(), os::get_thread_name(), sleep_period.count());
|
||||
std::this_thread::sleep_for(sleep_period);
|
||||
} else {
|
||||
LOG(md, Info, "Run::boot_sleep t_id{} t_name:{} sleep_period:{}",
|
||||
os::get_thread_id(), get_thread_name(), 2);
|
||||
os::get_thread_id(), os::get_thread_name(), 2);
|
||||
std::this_thread::sleep_for(2s);
|
||||
}
|
||||
}
|
||||
|
||||
static void run_replay() {
|
||||
LOG(md, Info, "Run::run_replay t_id:{} t_name", os::get_thread_id(),
|
||||
get_thread_name());
|
||||
os::get_thread_name());
|
||||
const auto &replay_opts = config::get<bts::md::ReplayOptions>();
|
||||
bts::md::replay_recording(
|
||||
replay_opts.url(), config::get<bts::md::RelayOptions>().naggle_ms(),
|
||||
@@ -60,7 +51,7 @@ static void run_onixs(
|
||||
bts::md::MBOWriter *mbo_writer,
|
||||
bts::md::TradeSummarySignalDispatcher *tss_dispatcher) {
|
||||
LOG(md, Info, "Run::run_onixs t_id:{} t_name", os::get_thread_id(),
|
||||
get_thread_name());
|
||||
os::get_thread_name());
|
||||
std::vector<std::shared_ptr<bts::md::IMDPlatform>> platforms;
|
||||
// get all glbx symbols
|
||||
std::vector<bts::md::UserSymbol> cme_symbols;
|
||||
@@ -92,89 +83,21 @@ static void run_onixs(
|
||||
disp.run();
|
||||
}
|
||||
|
||||
static void run_emumba() {
|
||||
// bts_assert(false);
|
||||
// LOG(md, Info, "Run::run_emumba t_id:{} t_name:{}", os::get_thread_id(),
|
||||
// get_thread_name());
|
||||
// bts::md::EmumbaMain em_main = {};
|
||||
// em_main.run();
|
||||
}
|
||||
|
||||
static void run_md_gwy() {
|
||||
LOG(md, Info, "Run::run_md_gwy t_id:{} t_name:{}", os::get_thread_id(),
|
||||
get_thread_name());
|
||||
// bts::md::CCMain cc_main = {};
|
||||
// cc_main.run();
|
||||
os::get_thread_name());
|
||||
bts::md::MarketDataGateway gwy = {};
|
||||
// this keeps going in a loop
|
||||
gwy.run();
|
||||
}
|
||||
|
||||
void Run::run(
|
||||
bts::md::MBOWriter *mbo_writer,
|
||||
bts::md::TradeSummarySignalDispatcher *tss_dispatcher,
|
||||
Run::MDType type,
|
||||
bool cleanup,
|
||||
bool run_on_md_thread) {
|
||||
void Run::run() {
|
||||
md::cmds::Cleanup::execute();
|
||||
LOG(md, Info, "Run::run cleanup:{} run_on_md_thread:{} t_id:{} t_name:{}",
|
||||
cleanup, run_on_md_thread, os::get_thread_id(), get_thread_name());
|
||||
if (type == Run::MDType::Configured &&
|
||||
!config::get<bts::md::HistoricMarketDataConfig>().use_md()) {
|
||||
LOG(md, Info, "Ignoring request to run md: 'use_md' is configured false");
|
||||
return;
|
||||
}
|
||||
|
||||
auto impl = [&mbo_writer, &tss_dispatcher, &type, &cleanup]() {
|
||||
LOG(md, Info, "Run::impl lambda t_id: {} t_name: {}", os::get_thread_id(),
|
||||
get_thread_name());
|
||||
if (cleanup)
|
||||
md::cmds::Cleanup::execute();
|
||||
if (type == Run::MDType::Configured) {
|
||||
const auto &conf = config::get<bts::md::HistoricMarketDataConfig>();
|
||||
if (conf.use_replay())
|
||||
type = Run::MDType::Replay;
|
||||
else if (conf.use_onixs())
|
||||
type = Run::MDType::Onixs;
|
||||
}
|
||||
switch (type) {
|
||||
case Run::MDType::Replay:
|
||||
run_replay();
|
||||
break;
|
||||
case Run::MDType::Onixs:
|
||||
run_onixs(mbo_writer, tss_dispatcher);
|
||||
break;
|
||||
default:
|
||||
bts_assert_msg(false, "Unexpected md type");
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
if (run_on_md_thread) {
|
||||
bts_assert(_md_thread == std::nullopt);
|
||||
|
||||
// start a thread for the md
|
||||
// _md_thread =
|
||||
// std::optional(bts::threading::make_thread("MDPublisher", impl));
|
||||
bool is_run_emumba = false;
|
||||
if (is_run_emumba) {
|
||||
threading::make_thread("Emumba", []() { run_emumba(); }).detach();
|
||||
}
|
||||
// if (bts::config::get<bts::md::HistoricMarketDataConfig>().use_sim()) {
|
||||
// threading::make_thread("ExchangeSimGLBX", [&mbo_writer]() {
|
||||
// sim::start_exchange_sim(api::Venue::VENUE_SIM, mbo_writer);
|
||||
// }).detach();
|
||||
// }
|
||||
bool is_run_md_gwy = true;
|
||||
if (is_run_md_gwy) {
|
||||
threading::make_thread("MarketDataGateway", []() {
|
||||
run_md_gwy();
|
||||
}).detach();
|
||||
}
|
||||
boot_sleep();
|
||||
} else {
|
||||
impl();
|
||||
}
|
||||
LOG(md, Info, "Run::run t_id:{} t_name:{}", os::get_thread_id(),
|
||||
os::get_thread_name());
|
||||
// start a thread for the md
|
||||
threading::make_thread("MarketDataGateway", run_md_gwy).detach();
|
||||
boot_sleep();
|
||||
}
|
||||
|
||||
Run::Run()
|
||||
@@ -187,7 +110,7 @@ Run::Run()
|
||||
add_subcommand("onixs", "Run onixs market data")->callback([] {
|
||||
run_onixs(nullptr, nullptr);
|
||||
});
|
||||
callback([] { run(nullptr, nullptr, MDType::Configured, true, true); });
|
||||
callback([] { run(); });
|
||||
}
|
||||
|
||||
} // namespace bts::cmds::md::cmds
|
||||
@@ -21,12 +21,7 @@ struct Run : public CLI::App {
|
||||
/**
|
||||
* Run market data
|
||||
*/
|
||||
static void run(
|
||||
bts::md::MBOWriter *,
|
||||
bts::md::TradeSummarySignalDispatcher *,
|
||||
MDType type,
|
||||
bool cleanup,
|
||||
bool run_on_md_thread);
|
||||
static void run();
|
||||
};
|
||||
|
||||
} // namespace bts::cmds::md::cmds
|
||||
Reference in new issue
Block a user