Compare commits

..
Author SHA1 Message Date
John Colvin 8e8d46354e Put cme config url in GlbxMarketDataConfig proto
Instead of using magic strings
2024-10-14 15:51:45 +00:00
John Colvin 10a68fba30 refactor: Change raw IDGenerator ptr to shared_ptr 2024-10-14 15:51:45 +00:00
John Colvin 01d677d8b0 refactor: Return row id in IStore::retrieve_one
This is a prerequisite to synchronizing security ids stored via IDGenerator
(the "new" way to store ids, added when we implemented Deribit), and
SecurityDB (the original way from spark days). The problem was that these
2 implementations were using separate databases. We need to unify the
interfaces between these storage services to avoid breaking existing code.
2024-10-14 15:51:45 +00:00
John Colvin 474d8747dc Add database dir and file fns to SparkDataDirectory 2024-10-14 15:51:45 +00:00
John Colvin dab8e939d5 Interpret db strng param as name or path in SqliteStore ctr 2024-10-14 15:51:45 +00:00
John Colvin 7fd501369e refactor: Normalize sec key indexing for old md sources
Now both old and new (domain) md sources index securities by
the same string format.
2024-10-14 15:51:45 +00:00
John Colvin d9838fd394 Add ostream operator for Venue 2024-10-14 15:51:45 +00:00
John Colvin 531498394b Add ostream operator for SecurityType 2024-10-14 15:51:44 +00:00
John Colvin 9d08ddfa53 refactor: Normalize sec key indexing for new (domain) md sources
This is part of a larger effort to unify the way we index securities in order
to generate unique ids. Older md sources (e.g., MDP3Listener) use
SecurityIDRecorder to generate ids, which uses a different database and
different key-string formatting than the IDGenerator used by the newer md
sources (e.g., GeneralMarketDataListener and various ccapi-based sources).
2024-10-14 15:51:44 +00:00
John Colvin 98f85b90ee refactor: Replace ConfigDownloader w/ lib_http fns
Essentially all it did was fetch config files via http GET. I ported some http
fns over from the cme-websocket-connector repo, which uses curlpp instead of
curl, and also supports async requests (coroutines) via the 'concurrencpp'

https://github.com/David-Haim/concurrencpp
2024-10-14 15:51:44 +00:00
John Colvin 752e2bac82 cleanup: Get rid of another Security type aliases 2024-10-14 15:51:44 +00:00
John Colvin eb12f4e582 cleanup: Remove unused code in Security.h/cpp 2024-10-14 15:51:44 +00:00
John Colvin 9ede4bb6eb Fix typo in 'Quantity' FMT_IMPL
I didn't realize the "value()" function rounded out the decimal,
so I replaced it with a call to "full_value()".
2024-10-14 15:51:44 +00:00
John Colvin 2c56ab2578 diag: Log when sqlite db is created 2024-10-14 15:51:44 +00:00
John Colvin 517d155c4a diag: Log when an MDProducer is created 2024-10-14 15:51:44 +00:00
John Colvin bf6fdcada7 diag: Add logs around synthetic security discovery in MDConsumer 2024-10-14 15:51:44 +00:00
John Colvin c8abb64538 refactor: Break shared mem md code up into smaller files
For easier reading/navigation
2024-10-14 15:51:44 +00:00
John Colvin 345a281a47 refactor: Break md relay/query server code up into smaller files
To make code navigation easier. This was a difficulty which I recently
confronted, while investigating a bug that prevented synthetics from
showing up the ui.
2024-10-14 15:51:44 +00:00
John Colvin de98e99a96 refactor: Get rid of 'TimeStamp' typedef in MDStructure.h
Before this commit, we had 4 different TimeStamp types/identifiers, which is
confusing enough as it is:

* bts::core::TimeStamp
  - in system/time_stamp.h
* bts::utils::TimeStamp
  - in spark/utils/TimeStamp.h
* bts::TimeStamp
  - in system/bts_chrono.h
  - alias for std::chrono::system_clock::time_point
* bts::md::TimeStamp
  - in spark/md/Shm/MDStructure.h
  - alias for bts::utils::TimeStamp
  - removed in this commit

Additional aliases for these TimeStamps only adds to the confusion (esp
when the alias comes from a nested include).
2024-10-14 15:51:44 +00:00
John Colvin dc0fd3d137 Make security 'formattable'
So it can be used as a param in LOG statements
2024-10-14 15:51:44 +00:00
John Colvin 01e73f93b3 refactor: Change refs/raw ptrs to smart ptrs in md gateway 2024-10-14 15:51:44 +00:00
John Colvin 22a225820d Fix typo in market_data.conf 2024-10-14 15:51:44 +00:00
John Colvin 2ca8c72eb8 Fix typo in namespace, co2 -> md::MDConsumerChannel
Not sure how this happened...
2024-10-14 15:51:44 +00:00
John Colvin 04b70f36c4 Add BTC and ETH to VENUE_SIM in symbols.conf 2024-10-14 15:51:44 +00:00
John Colvin a378fdb862 fix: Resolve main logging dir in new SparkDataDirectory class 2024-10-14 15:51:44 +00:00
John Colvin 25396d70ff refactor: Replace if/else with switch cases 2024-10-14 15:51:44 +00:00
John Colvin c3f88bd505 fix: Resolve onixs log & data dirs relative to app data root
When our logging code moved to lib_system, it lost access to the config
system. As a result, the "log_path" function, which was used by ICEMain
and MDP3Main, broke. I added a new class, SparkDataDirectory, to be the
central/common authority on paths to local storage.
2024-10-14 15:51:44 +00:00
John Colvin c7f3819b3c cleanup: Remove over-engineered subcommands
We don't need explicit subcommands to 'run onixs' md (just use config).
2024-10-14 15:51:44 +00:00
John Colvin 88de4ab76a webapp check pt? 2024-10-14 15:51:44 +00:00
John Colvin 7697f311f0 fix: Ensure IDGenerator instance is created before deref 2024-10-14 15:51:44 +00:00
John Colvin 8cd2bb3d49 fix: Expand undefined vars to empty string
Bugs (fixed):
  * Md shared memory file names have unexpanded variable: '${BTS_SHARED_MEMORY_PREFIX}'
2024-10-14 15:51:44 +00:00
John Colvin 5e62b42404 fix: Emplace MDConsumerHandle instead of copy assign 2024-10-14 15:51:44 +00:00
John Colvin 8665d2137f Generate c++ protos w/ relative paths
We shouldn't be generating protos defined outside of the current CMakeLists.txt dir.
2024-10-14 15:51:44 +00:00
John Colvin 811dee2d04 fix build: Make venue conversion constexpr 2024-10-14 15:51:44 +00:00
John Colvin 373b377da4 build: Use new/robust init_library fn in lib_domain 2024-10-14 15:51:44 +00:00
John Colvin 11afb0ff40 refactor: Move config services to lib_system
The proto files are still in lib_spark, w/ the exception of
system_config.proto, since that is a dep of ConfigurationState.
2024-10-14 15:51:44 +00:00
John Colvin 01b0ebe01d refactor: Move logging into lib_system
This is a fundamental part of our application suite, so system seems
like a sensible home.

Also moved a few logging deps (to lib_system):
* bts_chrono.h
* bts_no_copy.h
* defer.h
* dispatcher.h/cpp
* file_utils.h/cpp
* type_name.h
2024-10-14 15:20:47 +00:00
John Colvin 8bc692605f build: Move http code into its own lib 2024-10-14 15:19:20 +00:00
John Colvin 80da994a14 refactor: Move thread_manager to lib_system 2024-10-13 20:42:19 +00:00
John Colvin e5ba13eded build (linux): Migrate catch2 dep to vcpkg (from externals) 2024-10-13 20:42:19 +00:00
John Colvin bc8ca9afd8 build (linux): Migrate fmt dep to vcpkg (from externals)
Now both linux and windows use vcpkg's fmt
2024-10-13 20:41:37 +00:00
John Colvin 17d6a64df8 cleanup: Remove unnecessary includes 2024-10-13 19:38:42 +00:00
John Colvin ca4e796560 refactor: Move threads.proto to lib_system 2024-10-13 19:38:38 +00:00
John Colvin 32691e8c9c refactor: Move warn_ctrl.h into lib_system
This is another logging dep
2024-10-12 19:54:51 +00:00
John Colvin 0be0501716 build: Link boost_filesystem in lib_system 2024-10-12 19:54:51 +00:00
John Colvin 1e2c361231 refactor: Move os.h/cpp and deps to lib_system
This is a prerequisite for the next objective: move logging into its own lib.
As logging is a core dependency for so much of our system, this will enable
us to move more complex services (like md providers) into smaller libs.
2024-10-12 19:54:51 +00:00
John Colvin f4b7f4fd88 cleanup: Remove unused code 2024-10-12 19:54:51 +00:00
John Colvin 05af82fefc cleanup: Remove more unnecessary includes 2024-10-12 19:54:51 +00:00
John Colvin 7de36a877f refactor: Move SecurityMarketDataStatistics to lib_domain 2024-10-12 19:54:51 +00:00
John Colvin 732ed02dea cleanup: Remove unnecessary code 2024-10-12 19:54:51 +00:00
John Colvin bdf4ea595d cleanup: Remove empty header FTXSecurity.h 2024-10-12 19:54:51 +00:00
John Colvin dc90f2b79a cleanup: Remove temporary redirect headers
These were used to make code migration smoother (to the new lib_system and lib_domain)

* spark/algorithm/TryCatch.h -> system/algorithm/try_catch.h
* spark/core/BoolName.h -> system/bool_name.h
* spark/core/EnumMacros.h -> system/enum_macros.h
* spark/core/FMT.h -> system/FMT.h
* spark/core/FMT_IMPL.h -> system/FMT_IMPL.h
* spark/core/TimeSpan.h -> system/time_span.h
* spark/core/TimeStamp.h -> system/time_stamp.h
* spark/domain/Price.h -> domain/price.h
* spark/io/JsonReader.h -> system/json/json_reader.h
* spark/io/JsonDumper.h -> system/json/json_dumper.h
2024-10-12 19:54:49 +00:00
John Colvin 07b3947738 refactor: Move RFQ to lib_domain 2024-10-12 19:53:27 +00:00
John Colvin cc8e0bd6a9 refactor: Move AggressorSide proto to lib_domain
Get rid of non-proto AggressorSide enum while we're at it (consolidate to 1 type)
2024-10-12 19:53:27 +00:00
John Colvin 5959538aca cleanup: Remove more unused code 2024-10-12 19:53:27 +00:00
John Colvin 65f435598c refactor: Move a few Order types to lib_domain 2024-10-12 19:53:27 +00:00
John Colvin 70d89e5bc1 refactor: Move TimeInForce to lib_domain 2024-10-12 19:53:27 +00:00
John Colvin 87722765db cleanup: Remove unused code 2024-10-12 19:53:27 +00:00
John Colvin b6961f558a refactor: Move TradeRecord into lib_domain 2024-10-12 19:53:27 +00:00
John Colvin 351fca18e1 refactor: Move TradingStatus enum to lib_domain 2024-10-12 19:53:27 +00:00
John Colvin 13a5f78ab1 build: Update webpack-cli in admin webapp 2024-10-12 19:53:27 +00:00
John Colvin 8735187963 build: Configure admin webapp build entirely in CMakeLists
Get rid of build_admin_web_app.py
2024-10-12 19:53:27 +00:00
John Colvin edda8ae20c refactor: Move domain types into new lib_domain
Also rename files in snake_case (standard naming convention for protos)
https://protobuf.dev/programming-guides/style/
2024-10-12 19:53:26 +00:00
John Colvin b48bfbae79 refactor: Move collections into lib_system 2024-10-12 19:30:05 +00:00
John Colvin 465b293e54 refactor: Move a handful of types/utils to lib_system 2024-10-12 19:30:04 +00:00
John Colvin 7b37c67568 build: Add preset to build with 6 jobs (-j 6)
Otherwise the devcontainer may hog too much cpu and cause the container to freeze
2024-10-12 19:30:04 +00:00
John Colvin a57e1d5cf3 cleanup: Remove unused includes
Mostly collection macro headers
2024-10-12 19:30:04 +00:00
John Colvin 97b99f87d1 cleanup (build): Move protobuf service generation cmake into lib_spark
Because lib_spark owns all the services
2024-10-12 19:30:04 +00:00
John Colvin d071021305 refactor: Rename protobuf out dir "include" -> "protobufs"
This is a more accurate and precise name. The dir contains c++ code generated
from .proto files - both sources (.cc) and headers (.pb.h).
2024-10-12 19:30:04 +00:00
John Colvin f2553695ea refactor: Move ValueWrapper into lib_system
So other projects can use it
2024-10-12 19:30:04 +00:00
John Colvin a2fab4afaf Include bts_assert.h in bts_fatal.h
We shouldn't have to include bts_assert.h when we're already including bts_fatal.h
2024-10-12 19:30:04 +00:00
John Colvin 32a8b82cd4 refactor: Split MarketDataGateway up into providers/sources
MarketDataGateway still exists, but is greatly simplified. It creates
several `IMarketDataProvider`s, each of which generates a list of
`IMarketDataSource`s. The market data sources provide market data to an
`IMarketDataListener`.

* EmumbaMarketDataProvider
* CCApiMarketDataProvider
* PyMarketDataProvider
* OnixsMarketDataProvider
* ReplayMarketDataProvider

As a side effect, individual py market data sources are now explicitly
limited to a single venue (it probably should have been this way all
along, since the shared memory writers do not expect updates to involve
multiple venues).
2024-10-12 19:30:03 +00:00
John Colvin eea830e9f8 cleanup: Remove superfluous code 2024-10-12 18:38:37 +00:00
John Colvin c5ca6ad712 improvement: Set SHARED_MEMORY_PREFIX to an environment variable
So we can effectively define it at runtime. We don't want to have to
produce different builds just to change the shared mem prefix.
2024-10-12 18:38:37 +00:00
John Colvin fee7b7bc47 fix: Always prepend proc name to shared mem prefix
Our shared memory model isn't really designed to be shared across processes.
Maybe some day it will.
2024-10-12 18:38:37 +00:00
John Colvin c06c768f76 cleanup: Remove redundant macro def 2024-10-12 18:38:37 +00:00
John Colvin 71710ae88c Skip md recording thread loop if no recorders configured to run 2024-10-12 18:38:37 +00:00
John Colvin 4671c12b6f Handle signal interrupts explicitly in sparkd
Otherwise the python interpretter, which is instantiated when we load
python md plugins, prevents the application from exiting.
2024-10-12 18:38:37 +00:00
John Colvin a5489e8fc7 feat: Add support for python md plugins 2024-10-12 18:38:36 +00:00
John Colvin 84432dd67a fix build: Ensure py scripts use unix line endings
I'm not sure why, but my sparkd build (linux) suddenly began failing to
generate cpp headers for protos. The error message indicated it was due
to an unexpected carriage return (\r) in plugin.py:

/usr/bin/env: ‘python\r’: No such file or directory
2024-10-12 18:37:16 +00:00
John Colvin b58be00de0 refactor: Add lib_system proj for common utils
Migrates the following:
* Delegate.h
* bts_array_size.h
* string_utils.h

Note: File names in the new lib are snake_case (this seems to be the
standard naming convention for c++).
2024-10-12 18:37:16 +00:00
John Colvin 427974f9cb cleanup: Trivial whitespace cleanup in sparkd CMakeLists 2024-10-12 18:37:16 +00:00
John Colvin 6ac36da920 build: Add cmake fns to symlink and install local libs
The code needed to do this (inline) is ugly and verbose
2024-10-12 18:37:16 +00:00
John Colvin fe0d1d1af1 cleanup: Use conventional UPPER_CASE var names in sparkd CMakeLists 2024-10-12 18:37:16 +00:00
John Colvin 98ecc530a0 cleanup: Trivial whitespace cleanup in Protobuf.cmake 2024-10-12 18:37:16 +00:00
John Colvin 1b71c62b0e build: Remove explicit targets from sparkd build preset
So it builds the default targets (all). They were only listed explicitly
in the first place so we could build specific targets in vs code using
the dropdown
2024-10-12 18:37:16 +00:00
John Colvin 5753e22968 build: Clean up data_files cmake proj (support --target clean) 2024-10-12 18:37:16 +00:00
John Colvin 5356b0694b refactor: Organize libspark proj w/ stuttering include
This new structure provides several benefits:

* Allows us to install multiple CMake projects in the same destination
  dir (without include path conflicts).
  - This makes shipping the trading algo sdk a trivial excercise. Simply
    copy the lib and include dirs from the install dest. That's it!
* Puts us in a position to break up the monolithic libspark into smaller
  modules, which are easier to manage.
2024-10-12 18:37:13 +00:00
John Colvin 8e59e43c39 vscode: Add debug cfg to skip sparkd build 2024-09-25 06:11:16 +00:00
John Colvin e3e6a6e794 fix build: Add ShmSegmentName.cpp to windows client sources 2024-09-25 06:11:16 +00:00
John Colvin 3eecb0e32b Make a few timestamp fns const
They should have been const in the first place
2024-09-25 06:11:16 +00:00
John Colvin b03790f9da Add config profiles to libspark
This is part of a larger effort to unify the libspark build, and eliminate
compile time differences between the builds used by our various services
2024-09-25 06:11:13 +00:00
John Colvin 2bde71f09b Add api server to docker compose 2024-09-22 18:47:05 +00:00
John Colvin af9c28a512 Rename pingtest "sparkd-ping-test", make it depend on sparkd
Add it to a "ping-test" profile, as we may add similar tests for other services
2024-09-22 18:47:05 +00:00
John Colvin d6c80ca972 cleanup: Remove unnecessary env vars from webapp docker compose 2024-09-22 18:47:05 +00:00
John Colvin bdc439df62 Change api server ports so they don't conflict w/ ds webapp 2024-09-22 18:47:05 +00:00
John Colvin c99345fee0 vscode: Fix sparkd debug config 2024-09-22 18:47:05 +00:00
John Colvin b8b2318f2e build: Resolve app data dir and shared mem prefix at runtime
We really can't define them at compile time anymore as we build multiple
exes that depend on libspark in the same dir (e.g., spark api server,
pubsub, ds-publisher, webapp, etc.). That means one libspark.so (or dll)
must serve all exes. We should compile a consistent libspark to mitigate
the risk of running an exe with the wrong version (of libspark). For
example, running pubsub with a libspark configured for spark api server,
leftover from an earlier build.
2024-09-22 18:47:04 +00:00
John Colvin 1f85b124fb Don't log "initializing spark config" if it has already been initialized 2024-09-22 18:46:10 +00:00
John Colvin 2b12479c48 vscode: Add debug cfg for spark api server 2024-09-22 18:46:10 +00:00
John Colvin d9b2db778f Use dependency injection in spark api server 2024-09-22 18:46:10 +00:00
John Colvin 2acd911e39 Add SparkLoggerAdapter for Msft ILogger 2024-09-22 18:46:10 +00:00
John Colvin 898e5b5822 Display exception stack trace w/ 1 call per line in ds webapp 2024-09-22 18:46:10 +00:00
John Colvin a3eb3ea310 Remove unused ErrorView from ds webapp 2024-09-22 18:46:10 +00:00
John Colvin 8d8da22003 Propagate ViewStream errors to webapp frontend 2024-09-22 18:46:10 +00:00
John Colvin 30636606a0 Add ErrorChanged event to propagate DataStream exceptions 2024-09-22 18:46:10 +00:00
John Colvin a1caaf9c07 Set columns to empty array rather than null in ds webapp
If no data has been received. Since the 'columns' property was marked
'required', this eliminates a warning that was being logged to console.
2024-09-22 18:46:10 +00:00
John Colvin 9bef5fd30e Improve alignment/spacing in ds webapp 2024-09-22 18:46:10 +00:00
John Colvin 45aa7c1d8f Configure datastream deployment with docker-compose
To deploy to aws, connect to our aws vpn then run:
tools/deploy-docker-compose.sh

The deploy script does the following:
* builds sparkd
* builds datastream apps (pubsub, md-publisher, and webapp)
* uploads the build to aws
* bounces all services (sparkd, pubsub, md-publisher, and webapp)

Note: the name 'md-publisher' refers to DataStreamPublisher w/ MarketData
configuration
2024-09-22 18:46:10 +00:00
John Colvin ae8fa71532 Remove "BTS Cloud Streams" title from webapp
Space is precious when viewing on phone (tbh, it didn't look that good
anyways).
2024-09-22 18:46:10 +00:00
John Colvin ac34840858 fix: Ensure md-publisher waits for pubsub and sparkd
Bugs (fixed):
  * md-publisher silently fails if it tries to connect before those services are "ready".

The Docker compose "depends_on" property ensures sparkd and pubsub
containers are up, but doesn't prevent startup race bugs (e.g., if
md-publisher and pubsub start around the same time, and md-publisher
tries to connect before pubsub has started accepting connections). To
address these race conditions, we use a nifty tool called "dockerize"

References:
  * https://github.com/jwilder/dockerize
2024-09-22 18:46:10 +00:00
John Colvin 568c59fdff Replace ErrorView component w/ robust QueryStatusView 2024-09-22 18:46:10 +00:00
John Colvin 41ebf9df20 Fix typos in query button theme 2024-09-22 18:46:10 +00:00
John Colvin 132b7c4e28 fix: Don't assert on exception in BooleanExpression.evaluate
Bugs (fixed):
  * DataStream WebApp Server sometimes crashes when the user enters a
    bad query.
2024-09-22 18:46:10 +00:00
John Colvin 21a815c78a Change VITE_DATASTREAM_WEBSOCKET_URL to localhost 2024-09-22 18:46:10 +00:00
John Colvin 96199192f6 Assert that local ip address is successfully obtained 2024-09-22 18:46:10 +00:00
John Colvin 5913992348 improvement: Resolve hostnames when comparing ip addrs
So we can to configure pubsub routes by hostname or ipv4 (ipv6 hasn't been
tested yet...so we should assume it doesn't work).
2024-09-22 18:46:10 +00:00
John Colvin 07c09b748b Assert TcpConnection endpoint matches expected 2024-09-22 18:46:10 +00:00
John Colvin e71f36d012 Fix typo in log msg (was missing interpolation '$') 2024-09-22 18:46:10 +00:00
John Colvin c320bd23d6 Catch exceptions on AsyncTCPConnector_AsyncWrapper background thread
Since it spawns a new thread on each attempt, uncaught exceptions were previously undetected,
and caused silent failures down the pipe. This should make it easier to track such bugs down.
2024-09-22 18:46:10 +00:00
John Colvin b9ba9b0430 fix: Format PubSubRoute as json in log msgs
It was previously using the default ToString, which simply returns the type name
2024-09-22 18:46:10 +00:00
John Colvin 4eb80820bf build: Upgrade packages (deps) in DataStreamTests 2024-09-22 18:46:10 +00:00
John Colvin f58b40f6cc cleanup: Remove unused ViewStreamDatabase config 2024-09-22 18:46:10 +00:00
John Colvin f941c100b7 vscode: Add PubSubServer debug cfg to skip build 2024-09-22 18:46:10 +00:00
John Colvin 314244c693 Configure apps as a distributed system via Docker compose 2024-09-22 18:46:08 +00:00
John Colvin 6798efd9f5 Remove reference to spark protobuf Config in ViewStream
We can't read spark protobuf Config until it has been initialized,
and since ViewStream doesn't have the configServer param handy it
isn't able to initialize config if necessary. In that case, it would simply
block until config was initialized by someone else. Such a risk doesn't
seem justified for this particular configuration dependency
(DataStreamConfig.UseUncopiedNewRowsInFire). For now, its hardcoded to false.
2024-09-22 18:36:36 +00:00
John Colvin d6b6ab08ac refactor: Run RemoteQueryManager as an IHostedService
This paradigm more accurately represents the RemoteQueryManager as a
Service that can be started/stopped.
2024-09-22 18:36:36 +00:00
John Colvin 13bb4d41a8 Remove inappropriate "Unable to dispose subscription" log msg 2024-09-22 18:36:36 +00:00
John Colvin 2cf72277b3 fix: Ensure spark config init and login are only performed once
As a static function that could be called from anywhere in the code
(directly or indirectly), 'Configuration.Initialize' was vulnerable to
race bugs. The "Configuration.get<T>()" method, whose calls are
ubiquitous in our code, would initialize config if it hadn't been done
so already. Without a reference to the configServer param, this param
would effectively be ignored/overridden with null.

It's important that login only be performed once, for obvious reasons
(our exes that connect to sparkd are generally designed to process data
for a single user). Furthermore, not every routine that requires a
successful login has a reference to the credentials needed to do it. To
address this, we now pass the ISparkdLoginService singleton to these
routines so they can wait until the singular login task has completed
before they begin.
2024-09-22 18:36:36 +00:00
John Colvin d81782a1b8 Move misplaced log abt initializing query text to appropriate place 2024-09-22 18:36:36 +00:00
John Colvin 64f5ed4bd6 Assert ViewStreamDatabase.instance is only created once
The instance must be initialized via ViewStreamDatabase.SetGlobalInstance
2024-09-22 18:36:36 +00:00
John Colvin 080b8177b5 cleanup: Remove unused code from ViewStreamDatabase 2024-09-22 18:36:36 +00:00
John Colvin 9ec0a5b8e5 Include subscription id in ds websocket updates 2024-09-22 18:36:36 +00:00
John Colvin aaa9995ad0 fix: Define BoooleanConstant before StringConstant
Otherwise the former masks the latter and prevents it from matching
2024-09-22 18:36:36 +00:00
John Colvin e763d79f26 Log event data in websocket open, close, error callbacks 2024-09-22 18:36:36 +00:00
John Colvin d20580cebb refactor: Bring back Material DataGrid
Fix the column resize bugs that made it previously unusable
2024-09-22 18:36:36 +00:00
John Colvin 727e6a94e6 refactor: Improve react webapp state management
* Add queryTextResetTime as part of the CannedQuery state
  (the QueryControl compares the canned query click time with the time of the
  last user input, and applies the text from the most recent change)

* Replace 'isRunning' (bool) with a 'queryState' (string) to reflect the subscription status
  value received from the server. Less indirection this way.

* Replace inappropriate useMemo call w/ useEffect
2024-09-22 18:36:36 +00:00
John Colvin d73a0de07d cleanup: Get rid of magic const (subscriptionId) in webapp App.jsx 2024-09-22 18:36:36 +00:00
John Colvin f5f9692c33 build: Copy configuration profiles to publish dir 2024-09-22 18:36:36 +00:00
John Colvin 4583a09b70 cleanup: Remove unnecessary deps from csprojs 2024-09-22 18:36:36 +00:00
John Colvin 0236bb9e58 build: Change publish_data_stream.py to publish the sln
We were publishing individual projects as a workaround for the
dependency issue (bug) that caused some projects to incorrectly target
net8.0. The fact that publishing individual projects "just worked" was
probably dumb luck. Now that the underlying issue has been addressed, we
can resume publishing the sln as a whole.
2024-09-22 18:36:36 +00:00
John Colvin b29f32e75d dev: Install docker in devcontainer
So we can start various services like sparkd, pubsub, ds publishers, ds
webapp, etc. from inside the devcontainer.
2024-09-22 18:36:36 +00:00
John Colvin 9d1c00f4d6 dev: Remove dotnet8 from devcontainer
We'll upgrade to dotnet8 eventually, but now isn't the time (too much
more important work to be done).
2024-09-22 18:36:36 +00:00
John Colvin 361da57419 dev: Run devcontainer on host network
So we don't need to worry about publishing the right ports (and don't
need to rebuild the container everytime the list of ports changes).
2024-09-22 18:36:36 +00:00
John Colvin ce8ae14a54 fix: Downgrade Microsoft.Extensions.Hosting to 7.0.1
A handful of csprojs were referencing version 8.0.0. Since that version
targets net8.0, I have no idea why it didn't cause the build to fail.
Instead, this framework mismatch led to a mysterious runtime crash with
the following error, despite the dll in question being present in the
build dir:

Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'System.Diagnostics.DiagnosticSource, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
The system cannot find the file specified.

It is worth noting that this crash would only happen for exes published
as part of the DataStreamSuite.sln with the "--self-contained" flag. For
example, the Bts.DataStreamSuite.Server exe would always fail if
published via:

dotnet publish --configuration Release --sc --framework net7.0 --runtime linux-x64 <DataStreamSuite.sln>
2024-09-22 18:36:36 +00:00
John Colvin 0e7b7c5599 Add HttpsRedirection middleware first in the webapp pipeline
Middleware handlers are invoked in the order in which they are added. Any middleware
that is added before HttpsRedirection may can prevent the request from being redirected.
As of now, only development-specific middleware is added ahead of HttpsRedircetion.
2024-09-22 18:36:36 +00:00
John Colvin 2fecb73e88 build: Copy configuration profiles to build dir
So they are readily available to publish/deploy scripts.
2024-09-22 18:36:36 +00:00
John Colvin b45d93342e Fix benign typo in Scanner/Parser msbuild targets
The output path referenced a non-existant msbuild metadata prop "RelativeOutputDir"
(the actual prop is called "RelativeDir"). Also, the OutputFile path is relative to the
project dir (the 'MSBuildProjectDir' prop), not the file being included.
2024-09-22 18:36:36 +00:00
John Colvin 048834c2c4 fix: Catch exception when creating TcpClient 2024-09-22 18:36:36 +00:00
John Colvin ba6938b09a fix: Catch WebSocketException in DataStreamSubscription 2024-09-22 18:36:36 +00:00
John Colvin 52eaa5622b fix: Add null check to NonIncGroupByStream 2024-09-22 18:36:36 +00:00
John Colvin 012ddeff7e fix: Add null check to TableAccumulator2 2024-09-22 18:36:36 +00:00
John Colvin 727235950f fix: Add self-signed certificate to Dockerfile for ds webapp 2024-09-22 18:36:36 +00:00
John Colvin 8b779597db fix: Make SystemSubscriptionMapPublisher threadsafe
The PubSubState.onTagMapChanged event may not be invoked on
the same thread as doWork.
2024-09-22 18:36:36 +00:00
John Colvin 5eecd2ffbc fix: Add null check in TimeBasedFilter.cs 2024-09-22 18:36:36 +00:00
John Colvin b12c28a074 Reduce task wait/timeout code in AsyncTCPConnector 2024-09-22 18:36:36 +00:00
John Colvin 02d19c522d Add a few canned queries to AwsProd.json for ds webapp 2024-09-22 18:36:36 +00:00
John Colvin a00e849192 fix: Copy canned queries to clipboard on click
Instead of trying to update the text directly, which causes the front end
to overwrite the user's changes everytime the data updates from then on.
2024-09-22 18:36:36 +00:00
John Colvin d0601ad32d fix: Convert invalid doubles to nan in ds webapp serializer 2024-09-22 18:36:36 +00:00
John Colvin 149ab49212 Increase datagrid maxheight in ds webapp to 1000px 2024-09-22 18:36:36 +00:00
John Colvin 23c9f0a9de Improve error display in ds webapp 2024-09-22 18:36:36 +00:00
John Colvin 22b04c8ec8 fix: Dispose existing sub on subscribe req in ds webapp
Even if new sub has parse error. This fixes a bug where the previous
subscription would continue firing and updating the frontend, when it
should just display the error info to the user and cease updates.
2024-09-22 18:36:36 +00:00
John Colvin fdba4601ab fix: Get rid of "UseSpa" calls in webapp Production environment
This was leftover from a misguided attempt to fix a bug that turned out
to be due to an omitted environment var:
ASPNETCORE_HOSTINGSTARTUPASSEMBLIES=Microsoft.AspNetCore.SpaProxy
2024-09-22 18:36:35 +00:00
John Colvin dd2dffd337 Define webapp specific env vars in generic datastream app deploy script
For now, this makes things easier, as I don't need to write a special script just for the webapp
2024-09-22 18:36:35 +00:00
John Colvin 2c58415a4f Add config profile and Dockerfile args to deploy script 2024-09-22 18:36:35 +00:00
John Colvin f85f57d2a5 Copy DataStream WebApp 'dist' to 'wwwroot' in deploy script 2024-09-22 18:36:35 +00:00
John Colvin 4d5f87df33 Tweak DataGrid style in DataStream WebApp 2024-09-22 18:36:35 +00:00
John Colvin bc22d0f2e7 Add AwsProd config for DataStream WebApp 2024-09-22 18:36:35 +00:00
John Colvin 2020c93915 fix: Add VITE_ prefix to imported env vars
For the DataStream WebApp client
2024-09-22 18:36:35 +00:00
John Colvin e92c4a7089 Fix urls for DataStreamPublisher AwsProd.json 2024-09-22 18:36:35 +00:00
John Colvin 234d1c7b31 Add benzinga news streams to AwsProd.json
This is a config profile for DataStreamPublisher, designed to be deployed
to aws (on public internet).
2024-09-22 18:36:35 +00:00
John Colvin ec0d0a5ec4 fix build warnings: Make props nullable strings in SharedStreamConfig 2024-09-22 18:36:35 +00:00
John Colvin ad2671e199 whitespace: Format PubSubServer.json (indentation issues) 2024-09-22 18:36:35 +00:00
John Colvin 8e42651433 fix import from environment variable 2024-09-22 18:36:35 +00:00
John Colvin daee227d5b Add a few tasks to run DataStream WebApp 2024-09-22 18:36:35 +00:00
John Colvin 17b2711357 fix: Import websocket url from environment var 2024-09-22 18:36:35 +00:00
John Colvin 42022bad0b Add scripts to deploy data stream apps 2024-09-22 18:36:35 +00:00
John Colvin 15b8a2189b Add SpaServer to Production environment
For Bts.DataStreamWebApp.Server
2024-09-22 18:33:42 +00:00
John Colvin 64ce742e2a Change DirectoryBrowser requestPath to "/browse"
So we can view a psuedo file explorer for the webapp by requesting the "/browse" path
(only activated in Development environment).
2024-09-22 18:33:42 +00:00
John Colvin 38d2145a78 Publish Bts.DataStreamWebApp.Server along with PubSub & DataStream 2024-09-22 18:33:42 +00:00
John Colvin 171d786a49 cleanup: Remove unused code in Bts.DataStreamWebApp.Client 2024-09-22 18:33:42 +00:00
John Colvin 45ae320324 Capture OperationCanceledException (instead of TaskCanceledException)
The former is the base class for the latter, so this will widen the umbrella to catch a few corner cases
that would otherwise been handled by the generic "Exception" catch block. One corner case I know
of is when an op is canceled via "CancellationToken.ThrowIfCancellationRequested". In that case,
an OperationCanceledException is thrown (not a TaskCanceledException).

https://stackoverflow.com/questions/34359129/operationcanceledexception-vs-taskcanceledexception-when-task-is-canceled
2024-09-22 18:33:42 +00:00
John Colvin fc16ed7194 Hardcode webSocketUrl to aws server in DataStreamWebApp client 2024-09-22 18:33:42 +00:00
John Colvin f4584afdf0 Assert that System publishers 'doWork' is always called on same thread 2024-09-22 18:33:42 +00:00
John Colvin 4fc0eec13c fix: Make InternalPublisherQueue thread safe 2024-09-22 18:33:42 +00:00
John Colvin c5e851d0aa Improve error reporting in DataStreamWebSocketServer 2024-09-22 18:33:42 +00:00
John Colvin 402cac2d03 data stream web app client check pt 2024-09-22 18:33:42 +00:00
John Colvin 79673b7a01 fix build: Fix Spark build after making config init async 2024-09-22 18:33:42 +00:00
John Colvin 2cf7826e4d fix Change Configuration.initialize to be async 2024-09-22 18:33:42 +00:00
John Colvin 8bb67dfba2 refactor: Tweak SparkCoreServices to synchronize Configuration.init globally 2024-09-22 18:33:42 +00:00
John Colvin f922215cae refactor: Change Configuration.initialize to be async 2024-09-22 18:33:42 +00:00
John Colvin d9e804b4e1 vscode: Add 'isSparkApiEnabled' input to launch.json 2024-09-22 18:33:42 +00:00
John Colvin 8194a07a8e SparkApiService check pt 2024-09-22 18:33:42 +00:00
John Colvin d8e4c6e601 pubsub server checkpt 2024-09-22 18:33:42 +00:00
John Colvin a8d3528125 pubsub checkpt 2024-09-22 18:33:42 +00:00
John Colvin 655329fec8 datastreamwebapp server checkpt 2024-09-22 18:33:41 +00:00
John Colvin 7d7c868f87 datastream webapp client check pt 2024-09-22 18:33:41 +00:00
John Colvin c14bade720 fix add pubsub services 2024-09-22 18:33:41 +00:00
John Colvin 104de5df7b Remove unused PubSubConfig props 2024-09-22 18:33:41 +00:00
John Colvin bd52ef0a8e Fix dsqa config json 2024-09-19 20:03:31 +00:00
John Colvin a015ff98e4 fix: Always call 'handle_internal_pubs' in PubSubMessageReactor main loop 2024-09-19 20:03:31 +00:00
John Colvin 12fc295825 improvement: Accept CancellationToken, catch exceptions when running ds websocket server 2024-09-19 20:03:31 +00:00
John Colvin 587e853f21 Fix mismatched types in PubSubServerTagStatsStream schema 2024-09-19 20:03:31 +00:00
John Colvin 909c8f5bcd Add DataStreamPublisher service modules designed for Dependency Injection
* Change DataStreamPublisher json fields to match cs class property names verbatim
* Rename Publishers -> PublisherNodes in DataStreamPublisherConfig
2024-09-19 20:03:31 +00:00
John Colvin 448d49f38d refactor: Decouple ViewPublisher from IPubTableBroker impl 2024-09-19 20:03:31 +00:00
John Colvin f67c24f7f5 Add PubSub service modules designed for Dependency Injection
* Get rid of JsonPropertyName attributes in PubSubConfig
  - The Dependency Injection framework (based around dotnet ApplicationBuilder)
    does not support this attribute, and maps property names verbatim to json fields.

* Change PubSubServer json fields to match cs class property names verbatim
2024-09-19 20:03:31 +00:00
John Colvin 69a72a1035 refactor: Decouple RemoteQueryManager from IManagedSubscriber, IPubTableBroker impl 2024-09-19 20:03:31 +00:00
John Colvin 819a8f6c22 refactor: Decouple ManagedSubscriber from ISubscriberCore impl 2024-09-19 20:03:31 +00:00
John Colvin 42db20316b refactor: Only support 1 tag type in IPubSubServerTagHandler 2024-09-19 20:03:31 +00:00
John Colvin 633a8590a1 refactor: Decouple PubTableBroker from IPublisherCore impl
Reference interface rather than the PublisherCore impl.
2024-09-19 20:03:31 +00:00
John Colvin eff979fb2b improvement: Accept CancellationToken in JsonRpcRequestObservable 2024-09-19 20:03:31 +00:00
John Colvin 23771909fd fix: Dispose market data sub in various md streams 2024-09-19 20:03:31 +00:00
John Colvin 9de21a3116 cleanup: Remove unused pubsub tag handler code
* Removed 'IPubSubServerTagHandler.register'
  - All implementations of this function were empty
* Removed 'IPubSubServerTagHandler.supportedTagTypes'
  - This property wasn't referenced anywhere
* Remove IWorker inheritance from IPubSubServerTagHandler
  - No reason these interfaces have to be tied together
2024-09-19 20:03:31 +00:00
John Colvin 8d231ce46c refactor: Rename CloudStreamManager.cs -> RemoteQueryManager.cs
This matches the file name
2024-09-19 20:03:31 +00:00
John Colvin fc9d5ab04f Change pub sub schema prefix 'bluto://' -> 'bts-cloud://'
In config json files (not actual code change)
2024-09-19 20:03:29 +00:00
John Colvin 3562f6848e fix build: Fix prop names after refactoring PubSubRoute
* Change 'server_address' -> 'ServerAddress'
* Change 'tag_reg_exp' -> 'TagRegExp'
2024-09-19 20:02:09 +00:00
John Colvin 1511bcf252 build: Add scripts to publish data stream apps 2024-09-19 20:02:09 +00:00
John Colvin b4c902c023 Fix typo in log msg 2024-09-19 20:02:09 +00:00
John Colvin 438ea44c88 Fix build scripts so they propagate the exit code back to the shell
I noticed this was broken because launch.json configurations would still start the debugger
even when the preLaunchTask (build) failed!
2024-09-19 20:02:09 +00:00
John Colvin 75acf12ef3 vscode: Add DataStreamPublisher debug cfg to skip build 2024-09-19 20:02:09 +00:00
John Colvin be407e3e1e build: Use separate cmd to build DataStreamSuite/QueryAnalyzer.sln
The DataStreamSuite.sln builds the new webapp now, which will
(eventually) replace DSQA. We'll keep it around for now, but with a
clean separation from the main build.
2024-09-19 20:02:09 +00:00
John Colvin 2dfa44c1e4 feat: Add DataStream WebApp
Included in DataStreamSuite.sln, but not DataStreamQueryAnalyzer.sln
2024-09-19 20:02:09 +00:00
John Colvin 022cad3122 Add spark service modules designed for Dependency Injection 2024-09-19 20:02:09 +00:00
John Colvin 5c42b4fe8b build: Copy libspark to all dotnet dirs in single cmake target
This is cleaner than the previous impl, which used separate build
targets to copy libspark to "net7.0", and "net7.0-windows" (dirs).
2024-09-19 20:02:09 +00:00
John Colvin 9f81c0ab39 fix: Parse ServerAddress as normal string
The "JsonValueOrArrayConverter<T>" doesn't work the way I thought it
would. When it is associated with a property via the JsonConverter
attribute, dotnet json parsing code throws an exception if "T" isn't
assignable to the property type.
2024-09-19 20:02:09 +00:00
John Colvin c941fa78d2 fix build (api server): Change namespace to bts.websocket_core 2024-09-19 20:02:09 +00:00
John Colvin e6f2c8d1a5 Remove docker submodules again 2024-09-19 20:02:09 +00:00
John Colvin faf296254e Change externals url from ssh to https style
So we don't need ssh keys to clone it (the builtin credential manager
makes https authentication safe/easy)
2024-09-19 20:02:09 +00:00
John Colvin 41712c774f cleanup: Fix benign typos in build scripts
Change BUILD_SPARK_PY var name to BUILD_PY (because these scripts to actually build 'spark')
2024-09-19 20:02:09 +00:00
John Colvin 565c70bb92 fix build (warn): Only use Registry on windows 2024-09-19 20:02:09 +00:00
John Colvin 97bc186110 cleanup: Fix numerous build warnings in DataStreamSuite
Nearly all warnings were due to nullability issues, since the concept of
nullable reference types did not exist when the DataStream code was
originally written.

* PubSubClientMessage
  - Normalize indentation/whitespace
  - Fix some typos
  - Address nullability issues to fix build warnings
  - Modernize code

* Compression related files
  - ZipEntry
  - ZipFile
  - ZipInputStream
  - TarHeader

* RemoteMessage
  - make 'message' nullable to resolve warnings elsewhere (in calling code)

* PubSubSingleTagStateEvent.cs
* PubSubMessageReactor
* PubSubState
* SystemHeartbeatPublisher
* SystemStatsPublisher
* SingleTagData
* ManagedTCPMessageHub
* PubsubDeserializationController
* PublisherCore
* InflaterHuffmanTree
* AsyncTCPConnection_APM
* ThreadSafeQueue
* ManagedSubscriber
* SubscriberCore
* PubSubServerManagedTCPConnection
* AsyncTCPConnection_APM
* SuperMapStream
* MapStream
* TradeBarsStream
2024-09-19 20:02:09 +00:00
John Colvin 158f4fb6c8 cleanup: Normalize indentation in TradeBarsStream 2024-09-19 20:02:09 +00:00
John Colvin c7961f53c0 cleanup: Disable nullability warnings
* BZip2InputStream
* TarInputStream
* Inflater
* InflaterDynHeader
* BZip2OutputStream
* DeflaterHuffman
* ParallelJoinTest
2024-09-19 20:02:09 +00:00
John Colvin 6e89f42bc8 cleanup: Modernize PubSubRoute code, json parsing 2024-09-19 20:02:09 +00:00
John Colvin 0ee450b12a cleanup: Remove unused DateTime grammar from exp parser 2024-09-19 20:02:09 +00:00
John Colvin b2e3a6bf82 Add JsonRpcRequestObservable, AsyncEnumerable 2024-09-19 20:02:09 +00:00
John Colvin f87aa6c4b6 Add json facilities for DataStream websocket api 2024-09-19 20:02:09 +00:00
John Colvin 40a46dd6d7 refactor: Add handy WebsocketExtensions
* IsSocketStateOpen
* IsClosedProperly
2024-09-19 20:02:09 +00:00
John Colvin 75d04b2cd2 feat: Add JsonRpc types for websocket paradigm 2024-09-19 20:02:09 +00:00
John Colvin 423e20ae41 cleanup: Remove empty file (clearly added by accident) 2024-09-19 20:02:09 +00:00
John Colvin de439579cf fix: Fix improper 'OfType' linq cast
Previously, animations were expressed through polymorphism (derived from the
base class CellAnimation), but the new impl uses composition. This 'OfType' call
was leftover from the polymorphism implementation, an attempt to linq cast
elements of base class (CellAnimation) to BackgroundAnimation.
2024-09-19 20:02:09 +00:00
John Colvin adbe72258b editorconfig: Use standard c# capitalization rules
* Use 'PascalCase' for public members (instead of 'snake_case')
* Use 'camelCase' for private members (instead of '_snake_case')
2024-09-19 20:02:09 +00:00
John Colvin 13646a5a16 refactor: Add WebsocketClient class
Basically an ISubject (I/O) wrapper for IWebsocketConnectionGateway
2024-09-19 20:02:09 +00:00
John Colvin 9a1e51eacf refactor: Change WebsocketServerConfig.port to uint32
It should always be a number between 1-65535
2024-09-19 20:02:09 +00:00
John Colvin 9982bd2203 refactor: Rename WebsocketServerConfig proto pkg 'bts.websocket_core'
This matches the namespace used in spark_websocket csproj. Eventually,
I'd like to use conventional capitalization (TitleCase namespaces/types,
etc.), but let's shelf that until we have enough time/energy to do a
more comprehensive refactoring.
2024-09-19 20:02:09 +00:00
John Colvin e7d7352941 refactor: Remove nullability constraint in GetValueOrDefault 2024-09-19 20:02:09 +00:00
John Colvin d2efe037f9 refactor: Use events to avoid circular deps for ws sync/gateway 2024-09-19 20:02:09 +00:00
John Colvin 67e6147633 refactor: Let caller specify nullability of T in json parse fn 2024-09-19 20:02:09 +00:00
537 changed files with 7211 additions and 20031 deletions

No files matched your search

+1 -7
View File
@@ -25,12 +25,6 @@
"commands": [
"fake"
]
},
"dotnet-t4": {
"version": "3.0.0",
"commands": [
"t4"
]
}
}
}
}
-81
View File
@@ -1,81 +0,0 @@
# This file defines the global default configuration for docker deployments.
# It is tracked in source control. For temporary modifications, please create
# a separate file called ".env.local" (it's in .gitignore, so won't be tracked).
# If a variable is defined in both files, the value in .env.local will be used.
#
# About the deployment procedure:
# We use Docker Compose to build images and launch containers for various services
# that make up our software suite:
# - sparkd
# - pubsub
# - md-publisher
# - webapp (DSQA on the web)
# - api-server (websocket based)
# From inside a devcontainer, you can launch all services in separate containers
# on your machine by running:
#
# tools/deploy.sh
#
# This script builds release versions for each service, packaged (generally) in
# self-contained directories. Next, it runs a few "docker compose" commands to
# build docker images loaded with the self-contained binaries from the previous
# step, and start containers with those images to run each service. To view the
# commands that deploy.sh runs internally (without actually running them), run:
#
# tools/deploy.sh --dry-run
#
# For additional information/help, run:
#
# tools/deploy.sh --help
#
### Sparkd ###
# The internal image for sparkd to use. For more info, view:
# src/app_sparkd/Dockerfile
SPARKD__IMAGE=sparkd
# The 'spark.conf' for this service to use
SPARKD__CONF_FILE=src/app_sparkd/spark.conf
# To run replay md, put recorded md files in SPARKD__MD_RECORDING_DIR, and use:
# SPARKD__IMAGE=sparkd_md_replay
# SPARKD__CONF_FILE=src/app_sparkd/spark.local.conf
# (configure which md to replay in the new SPARKD__CONF_FILE)
SPARKD__MD_RECORDING_DIR=.md_recording
SPARKD__SOURCE_DIR=install/sparkd-release-gcc
SPARKD__CONFIG_PORT=8000
SPARKD__QUICKBUS_PORT=8001
SPARKD__SIM_FIX_PORT=8002
### Pubsub ###
# The 'spark.conf' for this service to use
PUBSUB__CONF_FILE=src/DataStreamSuite/PubSubServer/spark.conf
PUBSUB__CS_SOURCE_DIR=build/Release/bin/net7.0/linux-x64/publish
PUBSUB__CPP_SOURCE_DIR=install/data-stream-suite-linux
# The appsettings to load at runtime. Expects a file named:
# src/DataStreamSuite/PubSub/appsettings.${PUBSUB__DOTNET_ENVIRONMENT}.json
PUBSUB__DOTNET_ENVIRONMENT=Staging
### Md Publisher ###
# The 'spark.conf' for this service to use
MD_PUBLISHER__CONF_FILE=src/DataStreamSuite/DataStreamPublisher/spark.conf
MD_PUBLISHER__SOURCE_DIR=build/Release/bin/net7.0/linux-x64/publish
# Determines which appsettings to load at runtime. Expects a file named:
# src/DataStreamSuite/DataStreamPublisher/appsettings.${MD_PUBLISHER__DOTNET_ENVIRONMENT}.json
MD_PUBLISHER__DOTNET_ENVIRONMENT=MarketData
### Webapp (DSQA on the web) ###
# The 'spark.conf' for this service to use
WEBAPP__CONF_FILE=src/client/spark_api_server/spark.conf
WEBAPP__SOURCE_DIR=build/Release/bin/net7.0/linux-x64/publish
WEBAPP__WEB_ROOT=build/Bts.DataStreamWebApp.Client/production/dist
# Determines which appsettings to load at runtime. Expects a file named:
# src/DataStreamSuite/Bts.DataStreamWebApp.Server/appsettings.${WEBAPP__ASPNETCORE_ENVIRONMENT}.json
WEBAPP__ASPNETCORE_ENVIRONMENT=Staging
### Api Server ###
# The 'spark.conf' for this service to use
API_SERVER__CONF_FILE=src/client/spark_api_server/spark.conf
API_SERVER__CS_SOURCE_DIR=build/Release/bin/net7.0/linux-x64/publish
API_SERVER__CPP_SOURCE_DIR=install/spark-api-server-linux
# Determines which appsettings to load at runtime. Expects a file named:
# src/client/spark_api_server/appsettings.${API_SERVER__ASPNETCORE_ENVIRONMENT}.json
API_SERVER__ASPNETCORE_ENVIRONMENT=Staging
-3
View File
@@ -59,6 +59,3 @@ trace_data/
.devcontainer/
*.Generated.cs
*.lst
src/app_sparkd/spark.local.conf
.env.local
.md_recording
+5 -62
View File
@@ -16,20 +16,11 @@
"program": "spark_api_server.exe",
"args": [
"run",
"--sparkd",
"http://127.0.0.1:8000/config"
],
"cwd": "build/Debug/bin/net7.0",
},
"linux": {
"preLaunchTask": "Build Api Server (Debug)",
"program": "spark_api_server",
"args": [
"run",
],
"cwd": "build/Debug/bin/net7.0",
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
},
"stopAtEntry": false,
"console": "integratedTerminal"
},
@@ -42,19 +33,11 @@
"program": "spark_api_server.exe",
"args": [
"run",
"--sparkd",
"http://127.0.0.1:8000/config"
],
"cwd": "build/Debug/bin/net7.0",
},
"linux": {
"program": "spark_api_server",
"args": [
"run",
],
"cwd": "build/Debug/bin/net7.0",
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
},
"stopAtEntry": false,
"console": "integratedTerminal"
},
@@ -62,7 +45,7 @@
"name": "Bts.DataStreamWebApp.Server",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build DataStream (Debug)",
"preLaunchTask": "Build DataStream WebApp (Debug)",
"program": "${workspaceFolder}/build/Debug/bin/net7.0/Bts.DataStreamWebApp.Server.dll",
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0",
"env": {
@@ -122,18 +105,6 @@
"stopAtEntry": false,
"console": "integratedTerminal"
},
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/sparkd-debug-clang/server/sparkd",
"args": ["run"],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/sparkd-debug-clang/server",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
},
{
"name": "DataStreamQueryAnalyzer",
"type": "coreclr",
@@ -282,34 +253,6 @@
}
]
},
{
"name": "Sparkd Web (Skip Build)",
"type": "cppdbg",
"request": "launch",
"program": "",
"linux": {
"program": "${workspaceFolder}/build/sparkd-debug-clang/src/app_sparkd/sparkd",
},
"args": [
"web"
],
"cwd": "${workspaceFolder}/build/sparkd-debug-clang/src/app_sparkd",
"stopAtEntry": false,
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
},
],
"inputs": [
{
+74 -67
View File
@@ -33,85 +33,92 @@ else()
set(BUILD_ADMIN_WEB_APP ON CACHE BOOL "Build the Admin WebApp")
endif()
include_directories(BEFORE SYSTEM ${EXTERNALS_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
link_directories(${EXTERNALS_LIB})
add_compile_definitions(SHARED_MEMORY_PREFIX="${SHARED_MEMORY_PREFIX}")
if(DEFINED APP_DATA_DIR)
add_compile_definitions(APP_DATA_DIR="${APP_DATA_DIR}")
endif()
add_compile_definitions(EXPORT_MD_CONSUMER="${EXPORT_MD_CONSUMER}")
if(WIN32)
# subdirs
add_subdirectory(src/lib_spark)
else()
if(BUILD_SPARKD)
# Note: All macros that begin w/ 'CCAPI' are ccapi's macros (defined and/or
# read by their code). We override some below.
add_compile_definitions(SPARK_ENABLE_CCAPI)
if(BUILD_SPARKD)
# Note: All macros that begin w/ 'CCAPI' are ccapi's macros (defined and/or
# read by their code). We override some below.
add_compile_definitions(SPARK_ENABLE_CCAPI)
# This allows us to override hardcoded exchange-urls with ones read from
# config (i.e., resolved at runtime rather than compile-time)
add_compile_definitions(CCAPI_EXPOSE_INTERNAL)
# This allows us to override hardcoded exchange-urls with ones read from
# config (i.e., resolved at runtime rather than compile-time)
add_compile_definitions(CCAPI_EXPOSE_INTERNAL)
# Enable ccapi services
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT)
# Enable ccapi exchanges
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_COIN_FUTURES)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_US)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_USDS_FUTURES)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_COINBASE)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_DERIBIT)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_OKX)
# Enable ccapi services
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT)
# Enable ccapi exchanges
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_COIN_FUTURES)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_US)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_USDS_FUTURES)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_COINBASE)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_DERIBIT)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_OKX)
set(CCAPI_LOG_LEVEL
"Warn"
CACHE STRING "<Fatal|Error|Warn|Info|Debug|Trace> Log level for ccapi")
string(TOUPPER "${CCAPI_LOG_LEVEL}" _ccapi_log_level_upper)
add_compile_definitions("CCAPI_ENABLE_LOG_${_ccapi_log_level_upper}")
set(CCAPI_LOG_LEVEL
"Warn"
CACHE STRING "<Fatal|Error|Warn|Info|Debug|Trace> Log level for ccapi")
string(TOUPPER "${CCAPI_LOG_LEVEL}" _ccapi_log_level_upper)
add_compile_definitions("CCAPI_ENABLE_LOG_${_ccapi_log_level_upper}")
# ** Binance **
add_compile_definitions(CCAPI_BINANCE_URL_REST_BASE="https://api.binance.com")
add_compile_definitions(BINANCE_INSTRUMENTS_PATH="/api/v3/exchangeInfo")
add_compile_definitions(BINANCE_PRICE_STATS_PATH="/api/v3/ticker/24hr")
# ** Binance **
add_compile_definitions(CCAPI_BINANCE_URL_REST_BASE="https://api.binance.com")
add_compile_definitions(BINANCE_INSTRUMENTS_PATH="/api/v3/exchangeInfo")
add_compile_definitions(BINANCE_PRICE_STATS_PATH="/api/v3/ticker/24hr")
# ** Binance US **
add_compile_definitions(BINANCE_US_INSTRUMENTS_PATH="/api/v3/exchangeInfo")
add_compile_definitions(BINANCE_US_PRICE_STATS_PATH="/api/v3/ticker/24hr")
# ** Binance US **
add_compile_definitions(BINANCE_US_INSTRUMENTS_PATH="/api/v3/exchangeInfo")
add_compile_definitions(BINANCE_US_PRICE_STATS_PATH="/api/v3/ticker/24hr")
# ** Binance USDS Futures **
add_compile_definitions(CCAPI_BINANCE_USDS_FUTURES_URL_REST_BASE="https://dapi.binance.com")
add_compile_definitions(BINANCE_USDS_FUTURES_INSTRUMENTS_PATH="/dapi/v1/exchangeInfo")
add_compile_definitions(BINANCE_USDS_FUTURES_PRICE_STATS_PATH="/dapi/v1/ticker/24hr")
# ** Binance USDS Futures **
add_compile_definitions(CCAPI_BINANCE_USDS_FUTURES_URL_REST_BASE="https://dapi.binance.com")
add_compile_definitions(BINANCE_USDS_FUTURES_INSTRUMENTS_PATH="/dapi/v1/exchangeInfo")
add_compile_definitions(BINANCE_USDS_FUTURES_PRICE_STATS_PATH="/dapi/v1/ticker/24hr")
# ** Deribit **
add_compile_definitions(DERIBIT_INSTRUMENT_PATH="/api/v2/public/get_instrument")
add_compile_definitions(DERIBIT_INSTRUMENTS_PATH="/api/v2/public/get_instruments")
add_compile_definitions(DERIBIT_COMBOS_PATH="/api/v2/public/get_combos")
add_compile_definitions(DERIBIT_TICKER_PATH="/api/v2/public/ticker")
add_compile_definitions(DERIBIT_CURRENCIES_METHOD="public/get_currencies")
add_compile_definitions(DERIBIT_INSTRUMENT_METHOD="public/get_instrument")
add_compile_definitions(DERIBIT_INSTRUMENTS_METHOD="public/get_instruments")
add_compile_definitions(DERIBIT_COMBO_DETAILS_METHOD="public/get_combo_details")
add_compile_definitions(DERIBIT_COMBOS_METHOD="public/get_combos")
# ** Deribit **
add_compile_definitions(DERIBIT_INSTRUMENT_PATH="/api/v2/public/get_instrument")
add_compile_definitions(DERIBIT_INSTRUMENTS_PATH="/api/v2/public/get_instruments")
add_compile_definitions(DERIBIT_COMBOS_PATH="/api/v2/public/get_combos")
add_compile_definitions(DERIBIT_TICKER_PATH="/api/v2/public/ticker")
add_compile_definitions(DERIBIT_CURRENCIES_METHOD="public/get_currencies")
add_compile_definitions(DERIBIT_INSTRUMENT_METHOD="public/get_instrument")
add_compile_definitions(DERIBIT_INSTRUMENTS_METHOD="public/get_instruments")
add_compile_definitions(DERIBIT_COMBO_DETAILS_METHOD="public/get_combo_details")
add_compile_definitions(DERIBIT_COMBOS_METHOD="public/get_combos")
# ** Okx **
add_compile_definitions(OKX_INSTRUMENTS_PATH="/api/v5/public/instruments")
add_compile_definitions(OKX_UNDERLYING_PATH="/api/v5/public/underlying")
endif()
# ** Okx **
add_compile_definitions(OKX_INSTRUMENTS_PATH="/api/v5/public/instruments")
add_compile_definitions(OKX_UNDERLYING_PATH="/api/v5/public/underlying")
endif()
# subdirs
add_subdirectory(src/lib_system)
add_subdirectory(src/lib_domain)
add_subdirectory(src/lib_http)
if (BUILD_SPARKD)
add_subdirectory(src/lib_python_md)
add_subdirectory(src/app_sparkd)
add_subdirectory(src/data_files)
endif()
add_subdirectory(src/lib_spark)
if (BUILD_ADMIN_WEB_APP)
add_subdirectory(src/Spark.Admin.WebApp)
endif()
if(BUILD_DOCS)
add_subdirectory(doc/user)
endif()
if(BUILD_SDK)
add_subdirectory(src/sdk)
# subdirs
if (BUILD_SPARKD)
add_subdirectory(src/lib_system)
add_subdirectory(src/lib_http)
add_subdirectory(src/lib_domain)
add_subdirectory(src/lib_python_md)
add_subdirectory(src/app_sparkd)
add_subdirectory(src/data_files)
endif()
add_subdirectory(src/lib_spark)
if (BUILD_ADMIN_WEB_APP)
add_subdirectory(src/Spark.Admin.WebApp)
endif()
if(BUILD_DOCS)
add_subdirectory(doc/user)
endif()
if(BUILD_SDK)
add_subdirectory(src/sdk)
endif()
endif()
+6 -5
View File
@@ -28,7 +28,7 @@
"CMAKE_SHARED_LINKER_FLAGS_RELEASE": "/OPT:REF /OPT:ICF /LTCG",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
"EXTERNALS_ROOT": "${sourceDir}/externals/windows",
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf",
"CONFIG_DEFAULTS_PATH": "config/profiles/default/*.conf",
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0;${sourceDir}/build/$<CONFIG>/bin/net7.0-windows",
"EXPORT_MD_CONSUMER": {
"type": "BOOL",
@@ -168,8 +168,8 @@
"type": "BOOL",
"value": "ON"
},
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf",
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0",
"CONFIG_DEFAULTS_PATH": "config/profiles/default/*.conf",
"DOTNET_BINARY_DIR": "${sourceDir}/build/Spark.Api.Server/$<CONFIG>/bin/net7.0",
"EXPORT_MD_CONSUMER": {
"type": "BOOL",
"value": "ON"
@@ -207,7 +207,7 @@
"description": "Data Stream utils ported over from Edge",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf;spark/config/profiles/data_stream/*.conf",
"CONFIG_DEFAULTS_PATH": "config/profiles/default/*.conf;config/profiles/data_stream/*.conf",
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0;${sourceDir}/build/$<CONFIG>/bin/net7.0-windows"
}
},
@@ -240,7 +240,8 @@
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -DDEBUG",
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -fno-omit-frame-pointer -DNDEBUG -O3",
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf;spark/config/profiles/data_stream/*.conf",
"CONFIG_DEFAULTS_PATH": "config/profiles/default/*.conf;config/profiles/data_stream/*.conf",
"CONFIG_PROFILES": "default;data_stream",
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0;${sourceDir}/build/$<CONFIG>/bin/net8.0",
"EXPORT_MD_CONSUMER": {
"type": "BOOL",
-149
View File
@@ -14,36 +14,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spark_test", "src\client\sp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spark.Console", "src\client\Spark.Console\Spark.Console.csproj", "{89D666E6-B500-498F-B026-4D167F68ADFC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{267F81EF-A8AB-49FD-9F56-D7EC3C1F7C7C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataStreamSuite", "DataStreamSuite", "{C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStreamCore", "src\DataStreamSuite\DataStreamCore\DataStreamCore.csproj", "{EF26A475-6101-4C9C-A717-D60BB92A2302}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedStreams", "src\DataStreamSuite\SharedStreams\SharedStreams.csproj", "{911B08A3-515A-441D-84C8-8A43740B5FC1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PubSub", "src\DataStreamSuite\PubSub\PubSub.csproj", "{14140310-2233-430A-821B-F3058A25234B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseUtilities", "src\DataStreamSuite\BaseUtilities\BaseUtilities.csproj", "{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExpressionCore", "src\DataStreamSuite\ExpressionCore\ExpressionCore.csproj", "{6F22DB96-6EAB-4034-99D9-287021C36F01}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArithmeticExpressions", "src\DataStreamSuite\ArithmeticExpressions\ArithmeticExpressions.csproj", "{A5C33956-A41F-49B3-A41D-1082CBA59D02}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStreamExpressions", "src\DataStreamSuite\DataStreamExpressions\DataStreamExpressions.csproj", "{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.ColumnSortExpressions", "src\DataStreamSuite\Bts.ColumnSortExpressions\Bts.ColumnSortExpressions.csproj", "{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColumnMapExpressions", "src\DataStreamSuite\ColumnMapExpressions\ColumnMapExpressions.csproj", "{B945A183-2174-4ACB-B289-8A5C546656FE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BooleanExpressions", "src\DataStreamSuite\BooleanExpressions\BooleanExpressions.csproj", "{9F6D7DE8-185B-4C1D-B809-3314D092DF28}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.ColumnExpressions", "src\DataStreamSuite\Bts.ColumnExpressions\Bts.ColumnExpressions.csproj", "{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStream", "src\DataStreamSuite\DataStream\DataStream.csproj", "{39AEA075-6457-46C0-8821-1158BE6EFA57}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Net", "src\DataStreamSuite\Bts.Net\Bts.Net.csproj", "{CCDCB00A-CABF-4D82-8A5F-33EEC8ACE51D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -100,110 +70,6 @@ Global
{89D666E6-B500-498F-B026-4D167F68ADFC}.Release|x64.Build.0 = Release|x64
{89D666E6-B500-498F-B026-4D167F68ADFC}.RelWithDebInfo|x64.ActiveCfg = Debug|x64
{89D666E6-B500-498F-B026-4D167F68ADFC}.RelWithDebInfo|x64.Build.0 = Debug|x64
{EF26A475-6101-4C9C-A717-D60BB92A2302}.Debug|x64.ActiveCfg = Debug|Any CPU
{EF26A475-6101-4C9C-A717-D60BB92A2302}.Debug|x64.Build.0 = Debug|Any CPU
{EF26A475-6101-4C9C-A717-D60BB92A2302}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{EF26A475-6101-4C9C-A717-D60BB92A2302}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{EF26A475-6101-4C9C-A717-D60BB92A2302}.Release|x64.ActiveCfg = Release|Any CPU
{EF26A475-6101-4C9C-A717-D60BB92A2302}.Release|x64.Build.0 = Release|Any CPU
{EF26A475-6101-4C9C-A717-D60BB92A2302}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{EF26A475-6101-4C9C-A717-D60BB92A2302}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{911B08A3-515A-441D-84C8-8A43740B5FC1}.Debug|x64.ActiveCfg = Debug|Any CPU
{911B08A3-515A-441D-84C8-8A43740B5FC1}.Debug|x64.Build.0 = Debug|Any CPU
{911B08A3-515A-441D-84C8-8A43740B5FC1}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{911B08A3-515A-441D-84C8-8A43740B5FC1}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{911B08A3-515A-441D-84C8-8A43740B5FC1}.Release|x64.ActiveCfg = Release|Any CPU
{911B08A3-515A-441D-84C8-8A43740B5FC1}.Release|x64.Build.0 = Release|Any CPU
{911B08A3-515A-441D-84C8-8A43740B5FC1}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{911B08A3-515A-441D-84C8-8A43740B5FC1}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{14140310-2233-430A-821B-F3058A25234B}.Debug|x64.ActiveCfg = Debug|Any CPU
{14140310-2233-430A-821B-F3058A25234B}.Debug|x64.Build.0 = Debug|Any CPU
{14140310-2233-430A-821B-F3058A25234B}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{14140310-2233-430A-821B-F3058A25234B}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{14140310-2233-430A-821B-F3058A25234B}.Release|x64.ActiveCfg = Release|Any CPU
{14140310-2233-430A-821B-F3058A25234B}.Release|x64.Build.0 = Release|Any CPU
{14140310-2233-430A-821B-F3058A25234B}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{14140310-2233-430A-821B-F3058A25234B}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.Debug|x64.ActiveCfg = Debug|Any CPU
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.Debug|x64.Build.0 = Debug|Any CPU
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.Release|x64.ActiveCfg = Release|Any CPU
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.Release|x64.Build.0 = Release|Any CPU
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{6F22DB96-6EAB-4034-99D9-287021C36F01}.Debug|x64.ActiveCfg = Debug|Any CPU
{6F22DB96-6EAB-4034-99D9-287021C36F01}.Debug|x64.Build.0 = Debug|Any CPU
{6F22DB96-6EAB-4034-99D9-287021C36F01}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{6F22DB96-6EAB-4034-99D9-287021C36F01}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{6F22DB96-6EAB-4034-99D9-287021C36F01}.Release|x64.ActiveCfg = Release|Any CPU
{6F22DB96-6EAB-4034-99D9-287021C36F01}.Release|x64.Build.0 = Release|Any CPU
{6F22DB96-6EAB-4034-99D9-287021C36F01}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{6F22DB96-6EAB-4034-99D9-287021C36F01}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.Debug|x64.ActiveCfg = Debug|Any CPU
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.Debug|x64.Build.0 = Debug|Any CPU
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.Release|x64.ActiveCfg = Release|Any CPU
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.Release|x64.Build.0 = Release|Any CPU
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.Debug|x64.ActiveCfg = Debug|Any CPU
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.Debug|x64.Build.0 = Debug|Any CPU
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.Release|x64.ActiveCfg = Release|Any CPU
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.Release|x64.Build.0 = Release|Any CPU
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.Debug|x64.ActiveCfg = Debug|Any CPU
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.Debug|x64.Build.0 = Debug|Any CPU
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.Release|x64.ActiveCfg = Release|Any CPU
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.Release|x64.Build.0 = Release|Any CPU
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{B945A183-2174-4ACB-B289-8A5C546656FE}.Debug|x64.ActiveCfg = Debug|Any CPU
{B945A183-2174-4ACB-B289-8A5C546656FE}.Debug|x64.Build.0 = Debug|Any CPU
{B945A183-2174-4ACB-B289-8A5C546656FE}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{B945A183-2174-4ACB-B289-8A5C546656FE}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{B945A183-2174-4ACB-B289-8A5C546656FE}.Release|x64.ActiveCfg = Release|Any CPU
{B945A183-2174-4ACB-B289-8A5C546656FE}.Release|x64.Build.0 = Release|Any CPU
{B945A183-2174-4ACB-B289-8A5C546656FE}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{B945A183-2174-4ACB-B289-8A5C546656FE}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{39AEA075-6457-46C0-8821-1158BE6EFA57}.Debug|x64.ActiveCfg = Debug|Any CPU
{39AEA075-6457-46C0-8821-1158BE6EFA57}.Debug|x64.Build.0 = Debug|Any CPU
{39AEA075-6457-46C0-8821-1158BE6EFA57}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{39AEA075-6457-46C0-8821-1158BE6EFA57}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{39AEA075-6457-46C0-8821-1158BE6EFA57}.Release|x64.ActiveCfg = Release|Any CPU
{39AEA075-6457-46C0-8821-1158BE6EFA57}.Release|x64.Build.0 = Release|Any CPU
{39AEA075-6457-46C0-8821-1158BE6EFA57}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{39AEA075-6457-46C0-8821-1158BE6EFA57}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.Debug|x64.ActiveCfg = Debug|Any CPU
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.Debug|x64.Build.0 = Debug|Any CPU
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.Release|x64.ActiveCfg = Release|Any CPU
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.Release|x64.Build.0 = Release|Any CPU
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.Debug|x64.ActiveCfg = Debug|Any CPU
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.Debug|x64.Build.0 = Debug|Any CPU
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.Release|x64.ActiveCfg = Release|Any CPU
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.Release|x64.Build.0 = Release|Any CPU
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
{CCDCB00A-CABF-4D82-8A5F-33EEC8ACE51D}.Debug|x64.ActiveCfg = Debug|Any CPU
{CCDCB00A-CABF-4D82-8A5F-33EEC8ACE51D}.Debug|x64.Build.0 = Debug|Any CPU
{CCDCB00A-CABF-4D82-8A5F-33EEC8ACE51D}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{CCDCB00A-CABF-4D82-8A5F-33EEC8ACE51D}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{CCDCB00A-CABF-4D82-8A5F-33EEC8ACE51D}.Release|x64.ActiveCfg = Release|Any CPU
{CCDCB00A-CABF-4D82-8A5F-33EEC8ACE51D}.Release|x64.Build.0 = Release|Any CPU
{CCDCB00A-CABF-4D82-8A5F-33EEC8ACE51D}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
{CCDCB00A-CABF-4D82-8A5F-33EEC8ACE51D}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -214,19 +80,4 @@ Global
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C09ED521-D2DF-40BC-A76F-EB3CB870B2F6} = {267F81EF-A8AB-49FD-9F56-D7EC3C1F7C7C}
{EF26A475-6101-4C9C-A717-D60BB92A2302} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{911B08A3-515A-441D-84C8-8A43740B5FC1} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{14140310-2233-430A-821B-F3058A25234B} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{6F22DB96-6EAB-4034-99D9-287021C36F01} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{A5C33956-A41F-49B3-A41D-1082CBA59D02} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{B945A183-2174-4ACB-B289-8A5C546656FE} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{39AEA075-6457-46C0-8821-1158BE6EFA57} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{9F6D7DE8-185B-4C1D-B809-3314D092DF28} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
EndGlobalSection
EndGlobal
+1 -10
View File
@@ -72,14 +72,6 @@ function(init_library)
else()
add_library(${_name} ${${_name}_SOURCES} ${${_name}_CXX_PROTO_SOURCES})
endif()
target_include_directories(
${_name}
SYSTEM
BEFORE
PUBLIC
$<BUILD_INTERFACE:${EXTERNALS_ROOT}/include>
$<BUILD_INTERFACE:${EXTERNALS_ROOT}/include/zlib>
)
target_include_directories(
${_name}
PUBLIC
@@ -98,7 +90,6 @@ function(init_library)
${_name}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<BUILD_INTERFACE:${EXTERNALS_ROOT}/lib/$<CONFIG>>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_LIBDIR}>
)
# Install main lib
@@ -112,7 +103,7 @@ function(init_library)
)
# Add tests executable (if there are any)
if (${_name}_TEST_SOURCES AND NOT WIN32)
if (${_name}_TEST_SOURCES)
add_executable(${_name}-tests ${${_name}_TEST_SOURCES})
get_target_property(_lib_type ${_name} TYPE)
+1 -5
View File
@@ -15,11 +15,7 @@ function(protobuf_generate_cpp)
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
if (NOT DEFINED _ARGS_PROTOC)
if (WIN32)
set(_ARGS_PROTOC "${EXTERNALS_BIN}/protoc.exe")
else()
set(_ARGS_PROTOC "${EXTERNALS_BIN}/protoc")
endif()
set(_ARGS_PROTOC "${EXTERNALS_BIN}/protoc")
endif()
set(${_ARGS_CXX_SOURCES})
set(${_ARGS_CXX_HEADERS})
+1 -1
View File
@@ -33,7 +33,7 @@ function(protobuf_generate_cpp_config)
# Generate static defaults. Ideally, this would be a single string, but we use an array because
# the compiler complains if the string is longer than 65k.
set(_cfg_defaults_str "inline const char * config_static_defaults[] = { ")
set(_cfg_defaults_str "const char * config_static_defaults[] = { ")
foreach(_cfg_file_path ${_ARGS_PROTO_DEFAULTS})
file(READ ${_cfg_file_path} _cfg_file_content)
+8 -6
View File
@@ -20,14 +20,16 @@ endfunction()
function(sym_link_file)
set(_options)
set(_one_value_args SOURCE DEST INSTALL_DEST)
set(_one_value_args TARGET_NAME SOURCE DEST INSTALL_DEST)
set(_multi_value_args)
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
file(
CREATE_LINK
${_ARGS_SOURCE}
${_ARGS_DEST}
SYMBOLIC
add_custom_command(
OUTPUT ${_ARGS_DEST}
COMMAND ln ARGS -s ${_ARGS_SOURCE} ${_ARGS_DEST}
)
add_custom_target(
${_ARGS_TARGET_NAME} ALL
DEPENDS ${_ARGS_DEST}
)
if (DEFINED _ARGS_INSTALL_DEST)
install(
+1 -1
View File
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.5)
cmake_policy(SET CMP0076 NEW)
# add protos to the library to facilitate source_group
target_sources(spark PUBLIC ${Config_Protos} ${NonConfig_Protos} ${Service_Protos})
target_sources(libspark PUBLIC ${Config_Protos} ${NonConfig_Protos} ${Service_Protos})
function(assign_source_group)
foreach(_source IN ITEMS ${ARGN})
+23 -30
View File
@@ -1,59 +1,52 @@
services:
sparkd:
build:
dockerfile: src/app_sparkd/Dockerfile
args:
- IMAGE=${SPARKD__IMAGE}
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
- CONF_FILE=${SPARKD__CONF_FILE}
- MD_RECORDING_DIR=${SPARKD__MD_RECORDING_DIR}
dockerfile: src/server/sparkd/Dockerfile
command: [ "./sparkd", "run" ]
ports:
- "8000:8000"
- "8001:8001"
- "8002:8002"
ports: [ "8000:8000", "8001:8001", "8002:8002" ]
pubsub:
environment:
- DOTNET_ENVIRONMENT=${PUBSUB__DOTNET_ENVIRONMENT}
- DOTNET_ENVIRONMENT=Staging
build:
dockerfile: src/DataStreamSuite/PubSubServer/Dockerfile
args:
- CS_SOURCE_DIR=${PUBSUB__CS_SOURCE_DIR}
- CPP_SOURCE_DIR=${PUBSUB__CPP_SOURCE_DIR}
- CONF_FILE=${PUBSUB__CONF_FILE}
ports:
- "22019:22019"
- 22019:22019
command: [ "./PubSubServer" ]
md-publisher:
build:
dockerfile: src/DataStreamSuite/DataStreamPublisher/Dockerfile
args:
- SOURCE_DIR=${MD_PUBLISHER__SOURCE_DIR}
- CONF_FILE=${MD_PUBLISHER__CONF_FILE}
depends_on:
- pubsub
- sparkd
command: [ "dockerize", "-wait", "tcp://pubsub:22019", "-wait", "tcp://sparkd:8000", "-timeout", "10s", "./DataStreamPublisher" ]
command:
[
"dockerize",
"-wait",
"tcp://pubsub:22019",
"-wait",
"tcp://sparkd:8000",
"-timeout",
"10s",
"./DataStreamPublisher"
]
environment:
- DOTNET_ENVIRONMENT=${MD_PUBLISHER__DOTNET_ENVIRONMENT}
- DOTNET_ENVIRONMENT=MarketData
webapp:
ports:
- "8080:8080"
- "8443:8443"
- 8080:8080
- 8443:8443
build:
dockerfile: src/DataStreamSuite/Bts.DataStreamWebApp.Server/Dockerfile
args:
- SOURCE_DIR=${WEBAPP__SOURCE_DIR}
- WEB_ROOT=${WEBAPP__WEB_ROOT}
- CONF_FILE=${WEBAPP__CONF_FILE}
command: [ "./Bts.DataStreamWebApp.Server" ]
environment:
- ASPNETCORE_ENVIRONMENT=${WEBAPP__ASPNETCORE_ENVIRONMENT}
- ASPNETCORE_ENVIRONMENT=Staging
api-server:
profiles:
- api-server
depends_on:
- sparkd
ports:
@@ -61,9 +54,9 @@ services:
- 9443:9443
build:
dockerfile: src/client/spark_api_server/Dockerfile
command: [ "dockerize", "-wait", "tcp://sparkd:8000", "-timeout", "10s", "./spark_api_server", "run" ]
command: [ "./spark_api_server", "run" ]
environment:
- ASPNETCORE_ENVIRONMENT=${API_SERVER__ASPNETCORE_ENVIRONMENT}
- ASPNETCORE_ENVIRONMENT=Staging
sparkd-ping-test:
depends_on:
@@ -1 +1 @@
VITE_DATASTREAM_WEBSOCKET_URL=wss://localhost:8443/ws
VITE_DATASTREAM_WEBSOCKET_URL=wss://localhost:443
@@ -1 +1 @@
VITE_DATASTREAM_WEBSOCKET_URL=wss://localhost:8443/ws
VITE_DATASTREAM_WEBSOCKET_URL=wss://localhost:443
@@ -0,0 +1,32 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.3.1' } },
plugins: ['react-refresh'],
rules: {
"import/order": [
"error",
{
"groups": [
"builtin",
"external",
"internal",
["parent", "sibling", "index"]
],
"newlines-between": "always"
}
],
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
@@ -1,36 +0,0 @@
import importPlugin from "eslint-plugin-import";
import reactPkg from "eslint-plugin-react";
const { configs: reactConfigs } = reactPkg;
import js from "@eslint/js";
import defineConfig from "./vite.config.js";
export default [
js.configs.recommended,
importPlugin.flatConfigs.recommended,
reactConfigs.flat.recommended,
reactConfigs.flat["jsx-runtime"],
{
files: ["**/*.{js,jsx}"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
globals: {
console: "readonly"
}
},
settings: {
"import/resolver": {
vite: {
viteConfig: defineConfig({ mode: "development" })
}
}
},
rules: {
semi: "error",
"prefer-const": "error",
"no-unused-vars": "warn",
"import/no-dynamic-require": "warn",
"import/no-nodejs-modules": "warn",
}
}
];
File diff suppressed because it is too large. Load diff
@@ -10,37 +10,35 @@
"preview": "vite preview"
},
"dependencies": {
"@angular/material": "^18.2.8",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@fontsource/noto-sans": "^5.1.0",
"@material/data-table": "^15.0.0-canary.423edc3dc.0",
"@mui/icons-material": "^6.1.4",
"@mui/material": "^6.1.4",
"@mui/x-data-grid": "^7.20.0",
"bulma": "^1.0.2",
"@angular/material": "^18.0.4",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@fontsource/noto-sans": "^5.0.22",
"@material/data-table": "^15.0.0-canary.7f224ddd4.0",
"@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20",
"@mui/x-data-grid": "^7.7.1",
"bulma": "^1.0.1",
"classnames": "^2.5.1",
"react": "^18.3.1",
"react-data-grid": "^7.0.0-beta.47",
"react-data-grid": "^7.0.0-beta.44",
"react-data-table-component": "^7.6.2",
"react-dom": "^18.3.1",
"react-json-view-lite": "^1.5.0",
"react-json-view-lite": "^1.4.0",
"react-pro-sidebar": "^1.1.0",
"react-use-websocket": "^4.9.0",
"rpc-websockets": "^9.0.4"
"react-use-websocket": "^4.8.1",
"rpc-websockets": "^7.11.2"
},
"devDependencies": {
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.2",
"eslint": "^9.12.0",
"@eslint/js": "^9.12.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-react": "^7.37.1",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.12",
"eslint-import-resolver-vite": "^2.0.1",
"react-mui-sidebar": "^1.3.8",
"vite": "^5.4.9"
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"eslint": "^8.57.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7",
"react-mui-sidebar": "^1.3.5",
"vite": "^5.2.13"
}
}
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import { useTheme } from '@mui/material/styles';
import { DataGrid } from '@mui/x-data-grid';
import './DataGrid.css';
import './DataGrid.css'
import { useMemo, useState } from 'react';
export default function DataTable({ columns, rows }) {
@@ -23,7 +23,7 @@ export default function DataTable({ columns, rows }) {
headerName: col.name,
width: columnWidths[col.name],
};
};
}
}, [columnWidths]);
return (
@@ -12,7 +12,7 @@ const QueryStatusView = ({ queryState, details, error }) => {
let header = queryState;
let headerContent = null;
const detailElements = [];
let detailElements = [];
let severity = queryState == "Subscribed" ? "success" : "info";
let cursor = details == null ? "default" : "pointer";
if (error != null) {
@@ -20,14 +20,14 @@ const QueryStatusView = ({ queryState, details, error }) => {
cursor = "pointer";
header = `Error Code: ${error.code}`;
headerContent = error.message;
detailElements.push(<Typography key="error-msg" variant="body1">{error.data.error_message}</Typography>);
detailElements.push(<Typography key="error-details" variant="subtitle1">Stack Trace:</Typography>);
(error.data.stack_trace ?? []).forEach((line, idx) => detailElements.push(
<Typography key={`stacktrace-${idx}`} variant="body2" component="pre" sx={{ whiteSpace: 'pre-wrap' }}>
detailElements.push(<Typography variant="body1">{error.data.error_message}</Typography>);
detailElements.push(<Typography variant="subtitle1">Stack Trace:</Typography>);
(error.data.stack_trace ?? []).forEach(line => detailElements.push(
<Typography variant="body2" component="pre" sx={{ whiteSpace: 'pre-wrap' }}>
{line}
</Typography>));
} else if (details != null) {
detailElements.push(<Typography key="status-msg" variant="body1">{details}</Typography>);
detailElements.push(<Typography variant="body1">{details}</Typography>);
}
return (
<Box sx={{ margin: theme.spacing(2, 0, 0, 0) }}>
@@ -13,7 +13,7 @@ function getGridColDef(col) {
export default function ReactDataGrid({columns, rows}) {
return (
<DataGrid className={"data-grid"} rows={rows} columns={columns.map(getGridColDef)} />
);
)
}
ReactDataGrid.propTypes = {
@@ -3,7 +3,7 @@ import Button from '@mui/material/Button';
import { useTheme } from '@mui/material/styles';
import PropTypes from 'prop-types';
import Tooltip from '@mui/material/Tooltip';
import ChevronLeftRounded from "@mui/icons-material/ChevronLeftRounded";
import ChevronLeftRounded from "@mui/icons-material/ChevronLeftRounded"
import ChevronRightRounded from '@mui/icons-material/ChevronRightRounded';
import FileCopyIcon from '@mui/icons-material/FileCopy';
import './SideBar.css';
@@ -51,7 +51,7 @@ const Sidebar = ({ onSelection, onOpened, onClosed }) => {
} catch (error) {
console.error('Error fetching WebSocket config:', error);
}
};
}
fetchCannedQueries();
}, []);
@@ -1,5 +1,5 @@
import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';
import { defineConfig, loadEnv } from 'vite';
import plugin from '@vitejs/plugin-react';
import fs from 'fs';
import path from 'path';
@@ -50,25 +50,10 @@ export default defineConfig(({ $$command, mode, $$isSsrBuild, $$isPreview }) =>
server: {
proxy: {
'^/api': {
target,
secure: false,
configure: (proxy) => {
proxy.on('error', (err) => {
console.log('proxy error', err);
});
proxy.on('proxyReq', (proxyReq, req) => {
console.log(`Forwarding ${proxyReq.method} ${proxyReq.protocol}//${proxyReq.host}${proxyReq.path} to ${req.socket.remoteAddress}${req.url}`);
});
proxy.on('proxyRes', (proxyRes, req, res) => {
console.log(`Forwarding response ${req.socket.localAddress} to ${res.socket.remoteAddress}. Status=${proxyRes.statusCode}`);
});
},
},
'^/ws': {
target,
secure: false
},
'^/browse': {
'^/ws': {
target,
secure: false
}
@@ -1,21 +1,14 @@
namespace Bts.DataStreamWebApp.Server.Controllers;
using Bts.DataStream;
using Microsoft.AspNetCore.Mvc;
[Route("/ws")]
public class DataStreamSubscriptionController : ControllerBase {
readonly ILogger logger;
readonly IDataStreamFactory streamFactory;
public DataStreamSubscriptionController(ILogger<DataStreamSubscriptionController> logger, IEnumerable<IDataStreamFactory> streamFactories) {
public DataStreamSubscriptionController(ILogger<DataStreamSubscriptionController> logger) {
this.logger = logger;
logger.LogInformation("Creating {ControllerType}", GetType().Name);
var streamFactoryList = streamFactories.ToList();
streamFactory = streamFactoryList.Count == 1
? streamFactoryList[0]
: new CompositeDataStreamFactory(streamFactoryList);
}
[Route("/ws")]
@@ -28,7 +21,7 @@ public class DataStreamSubscriptionController : ControllerBase {
try {
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
logger.LogInformation("Websocket connection established.");
using var server = new DataStreamWebSocketServer(webSocket, streamFactory, logger);
using var server = new DataStreamWebSocketServer(webSocket, logger);
await server.Run(cancellationToken);
} catch (Exception ex) {
logger.LogError("DataStreamSubscriptionController.Run threw exception: {Exception}", ex);
@@ -2,7 +2,6 @@ namespace Bts.DataStreamWebApp.Server.Controllers;
using bts.websocket_core.json_rpc;
using Bts.DataStream;
using Bts.DataStreamWebApp.Server.Messages;
using System.Net.WebSockets;
@@ -14,11 +13,9 @@ public class DataStreamWebSocketServer : IDisposable, IAsyncDisposable {
readonly ILogger logger;
readonly WebSocket webSocket;
readonly Dictionary<string, DataStreamSubscription> subscriptions = new();
readonly IDataStreamFactory streamFactory;
public DataStreamWebSocketServer(WebSocket webSocket, IDataStreamFactory streamFactory, ILogger logger) {
public DataStreamWebSocketServer(WebSocket webSocket, ILogger logger) {
this.webSocket = webSocket;
this.streamFactory = streamFactory;
this.logger = logger;
}
@@ -70,7 +67,7 @@ public class DataStreamWebSocketServer : IDisposable, IAsyncDisposable {
}
var subId = subReq.SubscriptionId ?? throw new InvalidOperationException("SubscriptionId is null (parse false)");
disposeSubscription(subId);
if (!subReq.ParseQuery(streamFactory, out var vs, out parseErr, out errCode)) {
if (!subReq.ParseQuery(out var vs, out parseErr, out errCode)) {
logger.LogError("Invalid 'subscribe' request: {Reason}", parseErr);
var rpcError = JsonRpcResponse.CreateError<SubscriptionError>(
req.Id, new() { Code = (long)errCode, Message = "Failed to parse subscription request", Data = parseErr });
@@ -1,13 +1,11 @@
FROM bluetradingsystems/linux_dotnet7
ARG CS_SOURCE_DIR="build/Release/bin/net7.0/linux-x64/publish"
ARG CPP_SOURCE_DIR="install/data-stream-suite-linux"
ARG SOURCE_DIR="build/Release/bin/net7.0/linux-x64/publish"
ARG WEB_ROOT="build/Bts.DataStreamWebApp.Client/production/dist"
ARG CONF_FILE="src/DataStreamSuite/Bts.DataStreamWebApp.Server/spark.conf"
RUN dotnet dev-certs https --trust
COPY --chown=bts:bts "${CPP_SOURCE_DIR}/lib" "bin"
COPY --chown=bts:bts "${CS_SOURCE_DIR}" "bin"
COPY --chown=bts:bts "${SOURCE_DIR}" "bin"
COPY --chown=bts:bts "${WEB_ROOT}" "bin/wwwroot"
COPY --chown=bts:bts "${CONF_FILE}" ".local/share/bts/Bts.DataStreamWebApp.Server/conf/spark.conf"
WORKDIR "/home/bts/bin"
@@ -4,7 +4,6 @@ using BCG;
using bts.websocket_core.json_rpc;
using Bts.DataStream;
using Bts.DataStreamExpressions;
using System.Diagnostics.CodeAnalysis;
@@ -38,12 +37,7 @@ public class SubscribeRequest {
return true;
}
internal bool ParseQuery(
IDataStreamFactory streamFactory,
[NotNullWhen(true)] out ViewStream? stream,
[NotNullWhen(false)] out SubscriptionError? error,
out ErrorCode errorCode
) {
internal bool ParseQuery([NotNullWhen(true)] out ViewStream? stream, [NotNullWhen(false)] out SubscriptionError? error, out ErrorCode errorCode) {
stream = null;
errorCode = ErrorCode.None;
error = null;
@@ -60,7 +54,7 @@ public class SubscribeRequest {
}
Exception? exception = null;
try {
stream = exp.getView(new Dictionary<string, StatementExpression>(0), streamFactory);
stream = exp.getView(new Dictionary<string, StatementExpression>(0));
} catch (Exception ex) {
exception = ex;
}
@@ -1,6 +1,5 @@
using Bts.DataStreamCore.Services;
using Bts.PubSub.Services;
using Bts.SharedStreams.Services;
using Spark.Api.Services;
using Spark.Core.Services;
@@ -79,9 +78,5 @@ static void ConfigureServices(IServiceCollection services, IConfiguration config
.AddSparkApi(config.GetSection("SparkApi"))
.AddMasterWorker(config.GetSection("MasterWorker"))
.AddViewStreamDatabase()
.AddPrimitiveDataStreamFactory(config.GetSection("PrimitiveStreams"))
.AddOhlcvStreams(config.GetSection("StreamDatabase"))
.AddNaturalLanguageStreams(config.GetSection("NaturalLanguageStream"))
.AddCompositeDataStreamFactory()
.AddPubSubClient(config.GetSection("PubSub"));
}
@@ -1,4 +1,14 @@
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:8080"
},
"Https": {
"Url": "https://localhost:8443"
}
}
},
"PubSub": {
"Routing": {
"PublisherRoutes": [
@@ -1,45 +0,0 @@
{
"NaturalLanguagePrompt": {
"prompts": [
{
"category": "Impact of financial events on the market",
"description": "Show how trading metrics (e.g., price movement, volume) are affected by events related to finance (rate announcements, earnings reports, etc.).",
"prompt": "Show me the price movement and volume of Crude Oil futures during the 5-minute window following the last 5 OPEC meetings",
"examples": [
{
"natural_language": "Show me the price movement and volume of Crude Oil futures during the 5-minute window following the last 5 OPEC meetings",
"dsl": [
"time_idx=EventTimeIndex.OpecMeetings(which: \"last 5\", duration: \"+5min\")",
"contract_idx=ActiveFutureContracts(predicate: \"product==CL\")",
"Bars(time_index: time_idx, contract_index: contract_idx, fields: [\"price_movement\", \"volume\"])"
]
},
{
"natural_language": "How do OPEC meetings affect the price of Crude futures? Examine the 10 minutes after each meeting this year.",
"dsl": [
"time_idx=EventTimeIndex.OpecMeetings(duration: \"+10min\", predicate: \"timestamp.year==2024\")",
"contract_idx=ActiveFutureContracts(predicate: \"product==CL\")",
"Bars(time_index: time_idx, contract_index: contract_idx, fields: [\"price_movement\", \"volume\"])"
]
},
{
"natural_language": "Show me how the SP 500 price moves after FOMC rate announcements that day",
"dsl": [
"time_idx=EventTimeIndex.FomcRateAnnouncements(which: \"timestamp.year==2024\", duration: \"+10min\")",
"contract_idx=ActiveFutureContracts(predicate: \"product==ES\")",
"Bars(time_index: time_idx, contract_index: contract_idx, fields: [\"price_movement\", \"volume\"])"
]
},
{
"natural_language": "Analyze the impact of the FED's interest rate hikes in 2022 on the 10-year Treasury yield, focusing on the 2-week period following each hike.",
"dsl": [
"time_idx=FedInterestRateAnnouncements(predicate: \"timestamp.year==2022 && change_pct>0\", duration: \"+2 weeks\")",
"contract_idx=ActiveFutureContracts(predicate: \"product==ZN\")",
"Bars(time_index: time_idx, contract_index: contract_idx)"
]
}
]
}
]
}
}
@@ -30,15 +30,5 @@
"benzinga_news"
]
}
],
"Spark": {
"ConfigServer": "http://sparkd:8000/config"
},
"SparkApi": {
"IsEnabled": true,
"Credentials": {
"User": "bts",
"Password": ""
}
}
]
}
@@ -11,14 +11,8 @@
"Http": {
"Url": "http://0.0.0.0:8080"
},
"HttpIpv6": {
"Url": "http://[::1]:8080"
},
"Https": {
"Url": "https://0.0.0.0:8443"
},
"HttpsIpv6": {
"Url": "https://[::1]:8443"
}
}
},
@@ -28,358 +22,6 @@
"ViewStreamDatabase": {
"Interval": "00:00:00.1"
},
"PrimitiveStream": {
"Assemblies": [
"DataStream.dll",
"SharedStreams.dll"
],
"ExcludedTypes": [
"SettlementPriceStream",
"OHLCVStream"
]
},
"StreamDatabase": {
"Path": "/home/bts/.local/share/bts/silver_pine/store.db",
"Query": "select * from metadata"
},
"NaturalLanguageStream": {
"prompts": [
{
"category": "Settlement",
"MulitLineDescription": [
"This is a few shot learning example for an NL to DSL. The DSL function in question is Settlement (symbol_or_contract, datetime1). ",
"The first argument is a future (like CL, for crude oil) or a specific future contract like crude oil Dec 24 future (CLZ4). ",
"The second argument is the date at which the settlement is to be fetched. There is an overloaded function, Settlement ",
"(symbol_or_contract, begin_dt, end_dt) which gets the settlements for all dates from begin_dt to end_dt. This will also have ",
"datetimes expressed as Today, Yesterday, Last Friday, First Friday of the month, Last Thursday of August etc. You will need to know ",
"what Today is, since there will be referecnes to last week, yesterday etc. These examples are assuming Today is 10/11/2024, however ",
"you should use the Today's real date"
],
"prompt": "What was the settlement for SP 500 Future on June 8th?",
"examples": [
{
"natural_language": "Find Settlement price of the SP500 future on 04/22/2023.",
"dsl": "Settlement(\"ES\", 4/22/2023)"
},
{
"natural_language": "Find Settlement price of the Silver Dec 24 Future on 04/22/2023.",
"dsl": "Settlement(\"SIZ4\", 4/22/2023)"
},
{
"natural_language": "Find Yesterday's Settlement of the Crude Oil Future.",
"dsl": "Settlement(\"CL\", 10/10/2024)"
},
{
"natural_language": "Find today's settlement of the 10 year treasury future.",
"dsl": "Settlement(\"ZN\", 10/11/2024)"
},
{
"natural_language": "Find the Settlement of Natural Gas Dec 24 future on the first Friday of Sept.",
"dsl": "Settlement(\"NGZ4\", 9/6/2024)"
},
{
"natural_language": "Find the Settlement of WTI Jan 25 future in the first Week of Sept.",
"dsl": "Settlement(\"CLF5\", 9/2/2024, 9/6/2024)"
},
{
"natural_language": "Find the Settlement price for the Sp 500 Dec 24 Mar 25 spread for the first two weeks of September.",
"dsl": "Settlement(\"ESZ4-ESH5\", 9/14/2024, 9/1/2024)"
},
{
"natural_language": "Find the Settlement of Natural Gas future on the first Friday of Sept.",
"dsl": "Settlement(\"NG\", 9/6/2024)"
}
]
},
{
"category": "BBO",
"MulitLineDescription": [
"This is a few shot learning example for an NL to DSL. The DSL function in question is Bbo(args...). ",
"It accepts the following parameters: ",
"symbol (a product code such as ZN for 10 year T-Note futures), ",
"contract (a specific contract, such as ZNZ4 for the 10 Year T-Note future Dec 2024 exp), ",
"venue (name of the exchange, such as CME, NASDAQ, NYSE, NYMEX, DERIBIT etc.), ",
"interval (sample frequency of the data), ",
"begin and end (inclusive beginning and end of the time window to query, respectively), ",
"Arguments are specified by name, for example: Bbo(symbol: \"ZN\", venue: \"CME\", interval: \"PT1M\", begin: \"2024-10-10\", end: \"2024-10-11\"). ",
"Depending on the wording of the request, some arguments may be omitted. ",
"The begin, end, and interval args should be expressed in iso 8601 format. ",
"Interpret dates according to the trading schedule rather than calendar date whenever possible. ",
"In some prompts, the time window will be expressed in relative terms (e.g., \"last Monday\", or \"yesterday\") ",
"which must be translated to exact dates. To correctly interpret the dsl in the examples, assume the current time is 2024-10-11T12:00-05:00."
],
"prompt": "Show me bbo for SP 500 futures on Sep 23rd of this year.",
"examples": [
{
"natural_language": "Get SP500 future bbo from Wednesday.",
"dsl": "Bbo(symbol: \"ES\", venue: \"CME\", begin: \"2024-10-08T17:00:00-06:00\", end: \"2024-10-09T16:00:00-06:00\")"
},
{
"natural_language": "Get bbo for 10 year T-Notes in the first minute after the market opened yesterday.",
"dsl": "Bbo(symbol: \"ES\", venue: \"CME\", begin: \"2024-10-10T17:00:00-06:00\", end: \"2024-10-10T17:01:00-06:00\")"
},
{
"natural_language": "Retrieve NVIDIA L1 books from Oct 3",
"dsl": "Bbo(symbol: \"NVDA\", venue: \"NASDAQ\", begin: \"2024-10-02TT18:00:00-05:00\", end: \"2024-10-03T17:00:00-05:00\")"
},
{
"natural_language": "Show me L1 data for Crude oil futures this week",
"dsl": "Bbo(symbol: \"CL\", venue: \"CME\", begin: \"2024-10-06:T17:00:00-06:00\")"
},
{
"natural_language": "Fetch hourly bbo for Gold futures this week",
"dsl": "Bbo(symbol: \"GC\", venue: \"CME\", begin: \"2024-10-06:T17:00:00-06:00\", interval: \"PT1H\")"
},
{
"natural_language": "What was the minute by minute bbo for Tesla yesterday?",
"dsl": "Bbo(symbol: \"TSLA\", venue: \"NASDAQ\", begin: \"2024-10-09T18:00:00-05:00\", end: \"2024-10-10T17:00:00-05:00\", interval: \"PT1M\")"
}
]
},
{
"category": "Order flow imbalance",
"MulitLineDescription": [
"This is a few shot learning example for an NL to DSL. The DSL function in question is OrderImbalance(args...). ",
"It accepts the following parameters: ",
"symbol (a product code such as ZN for 10 year T-Note futures), ",
"contract (a specific contract, such as ZNZ4 for the 10 Year T-Note future Dec 2024 exp), ",
"venue (name of the exchange, such as CME, NASDAQ, NYSE, NYMEX, DERIBIT etc.), ",
"interval (sample frequency of the data), ",
"levels (the number of price levels to examine)",
"begin and end (inclusive beginning and end of the time window to query, respectively), ",
"Arguments are specified by name, for example: OrderImbalance(symbol: \"ZN\", venue: \"CME\", interval: \"PT1M\", begin: \"2024-10-10\", end: \"2024-10-11\"). ",
"Depending on the wording of the request, some arguments may be omitted. ",
"The begin, end, and interval args should be expressed in iso 8601 format. ",
"If the prompt doesn't contain an explicit interval, please choose a reasonable value depending on the duration between begin and end.",
"Interpret dates according to the trading schedule rather than calendar date whenever possible. ",
"In some prompts, the time window will be expressed in relative terms (e.g., \"last Monday\", or \"yesterday\") ",
"which must be translated to exact dates. To correctly interpret the dsl in the examples, assume the current time is 2024-10-11T12:00-05:00."
],
"examples": [
{
"natural_language": "Get SP500 order imbalance from Wednesday.",
"dsl": "OrderImbalance(symbol: \"ES\", venue: \"CME\", begin: \"2024-10-08T17:00:00-06:00\", end: \"2024-10-09T16:00:00-06:00\", \"PT1M\")"
},
{
"natural_language": "Get SP500 order imbalance from Wednesday for the top 5 price levels.",
"dsl": "OrderImbalance(symbol: \"ES\", venue: \"CME\", begin: \"2024-10-08T17:00:00-06:00\", end: \"2024-10-09T16:00:00-06:00\", levels: 5, interval: \"PT1M\")"
},
{
"natural_language": "Get orderflow imbalance for 10 year T-Notes in the first minute after the market opened yesterday.",
"dsl": "OrderImbalance(symbol: \"ES\", venue: \"CME\", begin: \"2024-10-10T17:00:00-06:00\", end: \"2024-10-10T17:01:00-06:00\", interval: \"PT1S\")"
},
{
"natural_language": "Retrieve NVIDIA order flow from Oct 3",
"dsl": "OrderImbalance(symbol: \"NVDA\", venue: \"NASDAQ\", begin: \"2024-10-02TT18:00:00-05:00\", end: \"2024-10-03T17:00:00-05:00\", interval: \"PT1S\")"
},
{
"natural_language": "Show me order imbalance for Crude oil futures this week",
"dsl": "OrderImbalance(symbol: \"CL\", venue: \"CME\", begin: \"2024-10-06:T17:00:00-06:00\", interval: \"PT1H\")"
},
{
"natural_language": "Fetch hourly orderflow for Gold futures this week",
"dsl": "OrderImbalance(symbol: \"GC\", venue: \"CME\", begin: \"2024-10-06:T17:00:00-06:00\", interval: \"PT1H\")"
},
{
"natural_language": "What was the minute by minute orderflow for Tesla yesterday?",
"dsl": "OrderImbalance(symbol: \"TSLA\", venue: \"NASDAQ\", begin: \"2024-10-09T18:00:00-05:00\", end: \"2024-10-10T17:00:00-05:00\", interval: \"PT1M\")"
}
]
},
{
"category": "VWAP",
"description": "This is a few shot learning example for an NL to DSL. The DSL function in question is VWAP (symbol_or_contract, datetime1, datetime2). The first argument is a future (like CL, for crude oil, or ES for SP 500) or a specific future contract like crude oil Dec 24 future (CLZ4) or SP 500 Dec 2024 (ESZ4). The second argument is where the VWAP has to be calculated (also the beginning of the time window), and the third argument is datetime specifying the end of the time window. So, for example, a 20-day VWAP on 9/30/2023, the first argument will be 9/30/2023, and the third argument will be 9/10/2023 (20 days prior). This will also have datetimes expressed as Today, Yesterday, Last Friday, Last Sunday, etc. For the purpose of this few-shot prompts, let's assume today is 10/11/2024.",
"prompt": "What was the VWAP for SP 500 Future over the past 30 days?",
"examples": [
{
"natural_language": "Find the 20 day VWAP of the SP future on 04/22/2023.",
"dsl": "VWAP(\"ES\", 4/22/2023, 4/02/2023)"
},
{
"natural_language": "Find Yesterday's 10 day VWAP of the Crude Oil Future.",
"dsl": "VWAP(\"CL\", 10/10/2024, 10/1/2024)"
},
{
"natural_language": "Find today's 30-day VWAP of the 10 year treasury future.",
"dsl": "VWAP(\"ZN\", 10/11/2024, 9/11/2024)"
},
{
"natural_language": "Find the 10 hour VWAP of the Natural Gas future from yesterday at 5:00 PM.",
"dsl": "VWAP(\"NG\", 9/27/2024 17:00:00, 9/27/2024 7:00:00)"
}
]
},
{
"category": "Price Diff",
"description": "This is a few shot learning example for an NL to DSL. The DSL function in question is OHLCVPriceDiff (symbol_or_contract, datetime1, datetime2). The first argument is a future (like CL, for crude oil) or a specific future contract like crude oil Dec 24 future (CLZ4). The second and third arguments are dates, that the function finds the difference of prices at. Assume today is 10/15/2024",
"prompt": "What is the difference in SP 500 Future from July 10th to July 14th?",
"examples": [
{
"natural_language": "What is the difference in ZN price from July 10th to July 14th?",
"dsl": "OHLCVPriceDiff(\"ZN\", 7/14/2024, 7/10/2024)"
},
{
"natural_language": "What is the price difference in SP Future price from Sept 10th and Sept 5th?",
"dsl": "OHLCVPriceDiff(\"ES\", 9/10/2024, 9/5/2024)"
},
{
"natural_language": "What is the price difference in Natural Gas Dec Future price from Aug 30th and Aug 20th?",
"dsl": "OHLCVPriceDiff(\"NGZ4\", 8/30/2024, 8/20/2024)"
}
]
},
{
"category": "Absolute Volume",
"description": "this is a few shot learning example for an NL to DSL. The DSL function in question is AbsVolume(symbol, ContractType, datetime1, datetime2), which computes the highest volume in the date range, specified by datetime1, and datetime2. The first argument is a future symbol (like CL for crude oil, ES for SP 500 etc). The second argument is the ContractType, which is \"Future\" for futures and \"FutureSpread\" for future spreads. the 3rd argument is the begin date and the 4th argument is the end date, between which the max volume is computed. If no future is specified use \"*\" from the first arugment. For this prompt, assume today is 10/11/2024 ",
"prompt": "Which SP 500 Future traded the most between 7/14/2024 and 7/10/2024",
"examples": [
{
"natural_language": "Which SP Future traded the most between 7/14/2024 and 7/10/2024",
"dsl": "AbsVolume(\"ES\", \"Future\", 7/14/2024, 7/10/2024)"
},
{
"natural_language": "Which Gold Spread traded the most between Today and Sept 20th",
"dsl": "AbsVolume(\"GC\", \"FutureSpread\", 10/1/2024, 9/20/2024)"
},
{
"natural_language": "Which 10 year Spread traded the highest volume last week?",
"dsl": "AbsVolume(\"ZN\", \"FutureSpread\", 9/27/2024, 9/23/2024)"
},
{
"natural_language": "Which Corn Spread traded the most today?",
"dsl": "AbsVolume(\"ZC\", \"FutureSpread\", 10/1/2024, 10/1/2024)"
},
{
"natural_language": "Which Gold Future traded the most today?",
"dsl": "AbsVolume(\"GC\", \"Future\", 9/30/2024, 9/30/2024)"
}
]
},
{
"category": "Roll",
"description": "This is a few shot learning example for an NL to DSL. The DSL function in question is FuturesRoll(symbol) which computes the rollover date for a future, ie when the highest volume swtches from one expiration to the next one. ",
"prompt": "When does the roll typically occur In SP 500?",
"examples": [
{
"natural_language": "When does the roll typically occur In CL?",
"dsl": "FuturesRoll(\"CL\")"
},
{
"natural_language": "When does the roll typically occur for 10 year treasury?",
"dsl": "FuturesRoll(\"ZN\")"
},
{
"natural_language": "When does the roll usually occur for Gold Future",
"dsl": "FuturesRoll(\"GC\")"
},
{
"natural_language": "At what date does the future rollover happens for SP500?",
"dsl": "FuturesRoll(\"ES\")"
},
{
"natural_language": "When does the future rollover happens for the Corn Future?",
"dsl": "FuturesRoll(\"ZC\")"
}
]
},
{
"category": "Daily Move",
"description": "This is a few shot learning example for an NL to DSL. ",
"prompt": "How often did Sp 500 Future settle + or - 10% over the previous day?",
"examples": [
{
"natural_language": "List all the days when the SP 500 closed + or -5% from the previous day's close",
"dsl": "ColDiff(filteredOHLCV(\"ES\"),\"ts_event\", -1, \"close\", \"close\", \"close_diff\", 5)"
},
{
"natural_language": "List all the days when the Crude Oil closed + or -2.5% from the previous day's close",
"dsl": "ColDiff(filteredOHLCV(\"CL\"),\"ts_event\", -1, \"close\", \"close\", \"close_diff\", 2.5)"
},
{
"natural_language": "Show me all the days when the Ten year Treaury Future opened + or -1% from the previous day's open",
"dsl": "ColDiff(filteredOHLCV(\"ZN\"),\"ts_event\", -1, \"open\", \"open\", \"open_diff\", 1.0)"
},
{
"natural_language": "List all the trading days when the Silver Future opened + or -1% from the previous day's close",
"dsl": "ColDiff(filteredOHLCV(\"SI\"),\"ts_event\", -1, \"open\", \"open\", \"open_diff\", 1.0)"
}
]
},
{
"category": "Average Volume",
"description": "This is a few shot learning example for an NL to DSL. For the purpose of this few shot prompts, lets assume today is 10/3/2024 ",
"prompt": "When does the most open interest typically shift from one contract to another in SP 500 Future?",
"examples": [
{
"natural_language": "When does the most open interest typically shift from one contract to another in e-minis? ",
"dsl": "FuturesRoll(\"ES\")"
},
{
"natural_language": "Usually when does the open interest move from one contract to another in WTI?",
"dsl": "FuturesRoll(\"CL\")"
}
]
},
{
"category": "Events",
"description": "This is a few shot learning example for an NL to DSL. In the NL prompt the user is asking to show the price of a future (treasury future, or SP 500 future etc) around an event type. The event type could be \"FOMC Announcement\" or \"Storage numbers\" etc. The DSL is as follows: EventsPriceAction(future_name, event_type, pre_event_window, post_event_window, number_of_events) first arg is the name of the future, (ex ES or ZN etc), the second argument is the event type, for example, \"FOMC announcement\", the 3rd argument is a time window for how much pre-event data to include in the end result, the 4th argument is how much post-event data to include in the end result. Both are strings of the form \"5d\" for 5 days, \"5h\" for 5 hours and \"120m\" for 120 minutes and so on. Usually, only one of the event periods is provided. Set the other to be half of what the user provided. The last argument is the number of events to consider. So if it’s 7, that means the most recent 7 events. If the user does not specify that, pass a large number.",
"prompt": "What did the volume and price of SP500 Future do following the release of the last 10 FOMC rates?",
"examples": [
{
"natural_language": "How did SP 500 Future do in the 5 days following the FOMC announcements?",
"dsl": "EventsPriceAction(\"ES\", \"FOMC Announcement\", \"2d\", \"5d\", 10)"
},
{
"natural_language": "How did the price of Treasury Future evolve in the 2 days following the Job Reports?",
"dsl": "EventsPriceAction(\"ZN\", \"Job Reports\", \"1d\", \"2d\", 10)"
},
{
"natural_language": "Show me the price movement and volume of Crude Oil futures during the 5-minute window following the last 5 OPEC meetings.",
"dsl": "EventsPriceAction(\"CL\", \"OPEC Meeting\", \"2m\", \"5m\", 5)"
},
{
"natural_language": "Show me the price movement and volume of SP 500 futures preceding the 10-minute window of the last 5 OPEC meetings.",
"dsl": "EventsPriceAction(\"CL\", \"OPEC Meeting\", \"10m\", \"5m\", 5)"
}
]
},
{
"category": "Indicator, Standard Deviation",
"MulitLineDescription": [
"This is a few shot learning example for an NL to DSL. In the NL prompt the user is asking to show all the days when ",
"the price of a future (treasury future, or SP 500 future etc) moved more than m times the N days standard deviation, ",
"where both m and N are provided. For example, the DSL for \"Using a 90d standard deviation, give me the dates and ",
"amounts of the last 4+ standard deviation moves in WTI futures\" would be: ",
"r=standardDeviation(\"ES\", \"90d\")\n",
"r=math(r, \"abs_daily_change = Abs(close - open) comp = std_dev * 4\")\n",
"r=filter(r,\"abs_daily_change >= comp\"). ",
"The first line, creates a stream for StandardDeviation, based on the number of days, for example 90d standard deviation, ",
"and assigned it to r, the second line takes r from the first line and passes it to a math stream that creates 2 new columns, ",
"abs_daily_change and comp. comp is the factor (4, from 4+ in the prompt) times standard deviation. The third line filters ",
"(like a sql where) of rows where abs_daily_change >= comp"
],
"prompt": "Using a 90d standard deviation, give me the dates and amounts of the last 1+ standard deviation moves in SP futures ?",
"examples": [
{
"natural_language": "Using a 90d standard deviation, give me the dates and amounts of the last 1+ standard deviation moves in WTI futures ?",
"dsl": "r=standardDeviation(\"CL\", \"90d\")\nr=math(r, \"abs_daily_change = Abs(close - open) comp = std_dev * 1.0\")\nr=filter(r,\"abs_daily_change >= comp\")"
},
{
"natural_language": "Show me the times the SP Futures moved twice the 60 day standard deviation",
"dsl": "r=standardDeviation(\"ES\", \"60d\")\nr=math(r, \"abs_daily_change = Abs(close - open) comp = std_dev * 2.0\")\nr=filter(r,\"abs_daily_change >= comp\")"
},
{
"natural_language": "List all the days the Gold Futures moved 1.5 times the 45 day standard deviation",
"dsl": "r=standardDeviation(\"GC\", \"45d\")\nr=math(r, \"abs_daily_change = Abs(close - open) comp = std_dev * 1.5\")\nr=filter(r,\"abs_daily_change >= comp\")"
},
{
"natural_language": "List all the days the 10 year treasury future moved more than twice the 1 month standard deviation",
"dsl": "r=standardDeviation(\"ZN\", \"30d\")\nr=math(r, \"abs_daily_change = Abs(close - open) comp = std_dev * 2.0\")\nr=filter(r,\"abs_daily_change >= comp\")"
}
]
}
]
},
"SparkApi": {
"IsEnabled": false,
"Credentials": {
@@ -435,7 +77,7 @@
{
"TagType": ".*",
"Assembly": "DataStreamCore",
"Class": "bts.PubsubServerGenericDataHandler"
"Class": "bts.PubsubServerGenericDataHandler"
}
]
}
@@ -18,11 +18,8 @@
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.57" />
<PackageReference Include="Microsoft.Data.Analysis" Version="0.21.1" />
<PackageReference Include="MongoDB.Bson" Version="2.23.1" />
<PackageReference Include="MongoDB.Driver" Version="2.23.1" />
<PackageReference Include="Parquet.Net" Version="5.0.1" />
<PackageReference Include="System.Data.SQLite" Version="1.0.118" />
</ItemGroup>
</Project>
@@ -2,27 +2,15 @@ namespace Bts.DataStream;
using BCG;
using bts.api.core;
using Bts.DataStreamCore;
using Microsoft.Extensions.Logging;
using Spark.Core.Disposables;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
public static class DataStreamExtensions {
public static ViewStream AsViewStream(this IObservable<DataPacket> source) =>
source as ViewStream ?? new ObservableViewStream(source);
public static ViewStream AsViewStream<T>(this IObservable<IDataPacket<T>> source, string? name = null, ILogger? logger = null) where T : IBlueRow =>
source as ViewStream ?? new ObservableViewStream(source.Select(dp => new DataPacket(dp.newRows, dp.addedRows, dp.deletedRows)), name, logger);
public static IObservable<DataPacket> AsObservable(this ViewStream source) {
return source as IObservable<DataPacket> ?? Observable.Create<DataPacket>(Subscribe);
@@ -35,100 +23,4 @@ public static class DataStreamExtensions {
$"Expected DataPacket, got {newValue?.GetType()}", nameof(newValue)));
}
}
public static IObservable<IDataPacket<T>> SelectDataPacket<T>(this IObservable<IDataPacket> source, Func<IBlueRow, T> selector) where T : IBlueRow =>
source.Select(dp => {
dp.get_new_added_deleted(out var newRows, out var addedRows, out var deletedRows);
return new DataPacket<T>(CastRows(newRows), CastRows(addedRows), CastRows(deletedRows));
IBlueRowCollection<T> CastRows(ICollection rows) =>
new BlueTableSelectorWrapper<T>(
rows as IBlueRowCollection ?? new BlueRowCollection(rows, dp.Schema), selector);
});
public static IObservable<TableUpdate<IBlueRow, int>> AsTables(this IObservable<IDataPacket> source) =>
source.AsTables<IBlueRow, int>(r => r, r => r.Id());
public static IObservable<TableUpdate<T, int>> AsTables<T>(this IObservable<IDataPacket> source, Func<IBlueRow, T> valueSelector) where T : IBlueRow =>
source.AsTables<T, int>(valueSelector, r => r.Id());
public static IObservable<TableUpdate<T, int>> AsTables<T>(
this IObservable<IDataPacket> source, Func<IBlueRow, T> valueSelector, Func<T, int> keySelector) =>
source.AsTables<T, int>(valueSelector, keySelector);
public static IObservable<TableUpdate<T, TKey>> AsTables<T, TKey>(
this IObservable<IDataPacket> source, Func<IBlueRow, T> valueSelector, Func<T, TKey> keySelector, Func<IBlueRow, TKey>? rowKeySelector = null) where TKey : IEquatable<TKey> {
rowKeySelector ??= r => keySelector(valueSelector(r));
return source.Scan(TableUpdate<T, TKey>.mk_empty(keySelector), (res, dp) => {
var bd = res.to_builder();
dp.get_new_added_deleted(out var newRows, out var addedRows, out var deletedRows);
foreach (IBlueRow r in addedRows) {
bd.add_or_update(valueSelector(r));
}
foreach (IBlueRow r in deletedRows) {
bd.remove(rowKeySelector(r));
}
return bd.to_table();
});
}
public static IObservable<IDataPacket<T>> AsDataPackets<T>(this IObservable<TableUpdate<T, int>> source, IBlueTableSchema schema) where T : IBlueRow =>
source.Scan(
(Table: new BlueTableImmutable<T>(schema), Dp: (IDataPacket<T>)DataPacket<T>.Empty(schema)),
(res, table) => {
var bd = res.Table.ToDataPacketBuilder();
foreach (var r in table.removed) {
bd.Remove(r.Id());
}
foreach (var r in table.added) {
bd.AddOrUpdate(r);
}
var resDp = bd.ToDataPacketT(out var newRows, out var addedRows, out var deletedRows);
return (newRows, resDp);
})
.Where(t => t.Dp.addedRows.Any() || t.Dp.deletedRows.Any())
.Select(t => t.Dp);
public static ViewStream AsViewStream<T>(this IObservable<TableUpdate<T, int>> source, IBlueTableSchema schema) where T : IBlueRow =>
source.AsDataPackets(schema).AsViewStream();
public static int ResolveIndices(this IBlueTableSchema schema, string name) {
var indices = ResolveIndices(schema, new[] { name });
return indices[0];
}
public static (int, int) ResolveIndices(this IBlueTableSchema schema, string name1, string name2) {
var indices = ResolveIndices(schema, new[] { name1, name2 });
return (indices[0], indices[1]);
}
public static (int, int, int) ResolveIndices(this IBlueTableSchema schema, string name1, string name2, string name3) {
var indices = ResolveIndices(schema, new[] { name1, name2, name3 });
return (indices[0], indices[1], indices[2]);
}
public static (int, int, int, int) ResolveIndices(this IBlueTableSchema schema, string name1, string name2, string name3, string name4) {
var indices = ResolveIndices(schema, new[] { name1, name2, name3, name4 });
return (indices[0], indices[1], indices[2], indices[3]);
}
public static int[] ResolveIndices(this IBlueTableSchema schema, string[] columnNames) {
var columns = schema.columnInfo;
var indices = new int[columnNames.Length];
int nResolved = 0;
for (int i = 0; i < columnNames.Length; i++) {
int origNResolved = nResolved;
for (int j = 0; j < columns.Length; j++) {
if (columns[j].colName == columnNames[i]) {
indices[i] = j;
nResolved++;
break;
}
}
if (nResolved == origNResolved) {
throw new ArgumentException($"No column named '{columnNames[i]}'", nameof(schema));
}
}
return indices;
}
}
@@ -1,33 +0,0 @@
namespace bts.SilverPine {
using System;
using BCG;
using System.Collections.Generic;
using Bts.DataStreamExpressions;
using Bts.DataStream;
// All this does is take in a dsl expression, parse it and fire the data that come out of running it.
// So for example, if an expresison is passed
[DataStreamUserRespresentation("dsl")]
public class DSLStream : ViewStream {
private readonly string _dsl;
public DSLStream(string dsl, IDataStreamFactory streamFactory) {
Log.Gen.info($"DSLStream.cons dsl: {dsl}");
_dsl = dsl;
var rs = build_stream(streamFactory, dsl);
rs = rs ?? new LiteralStream("error", $"msg:invalid dsl");
mySetRealSource(rs);
}
static ViewStream? build_stream(IDataStreamFactory streamFactory, string stream_expression) {
try {
var exp = DataStreamExpressionsInterpreter.Evaluate(stream_expression);
var rv = exp.getView(new Dictionary<string, StatementExpression>(0), streamFactory);
return rv;
} catch (Exception ex) {
Log.Gen.error($"Could not build stream: {stream_expression} ex: {ex}");
return null;
}
}
}
}
@@ -4,21 +4,14 @@ using BCG;
using bts;
using Microsoft.Extensions.Logging;
using System;
public class ObservableViewStream : ViewStream, IObservable<DataPacket>, IDisposable {
readonly IObservable<DataPacket> source;
readonly string? name;
readonly ILogger? logger;
IDisposable? subscription;
public ObservableViewStream(IObservable<DataPacket> source, string? name = null, ILogger? logger = null) {
public ObservableViewStream(IObservable<DataPacket> source) =>
this.source = source;
this.name = name;
this.logger = logger;
}
public void Dispose() {
GC.SuppressFinalize(this);
@@ -30,13 +23,7 @@ public class ObservableViewStream : ViewStream, IObservable<DataPacket>, IDispos
protected override void myOnFirstSubscriber() {
Log.isnull(subscription);
subscription = source.Subscribe(myFireEvent, OnError, OnCompleted);
void OnError(Exception exception) =>
logger?.LogError("Error in ObservableViewStream. name: {Name}, error: {Exception}", name, exception);
void OnCompleted() =>
logger?.LogInformation("ObservableViewStream completed. name: {Name}", name);
subscription = source.Subscribe(myFireEvent);
}
protected override void myOnLastSubscriber() {
@@ -34,12 +34,12 @@ namespace BCG {
view_publisher = view_publisher_;
}
}
static ViewStream? build_stream(IDataStreamFactory streamFactory, string stream_expression)
static ViewStream? build_stream(string stream_expression)
{
try
{
var exp = DataStreamExpressionsInterpreter.Evaluate(stream_expression);
var rv = exp.getView(new Dictionary<string, StatementExpression>(0), streamFactory);
var rv = exp.getView(new Dictionary<string, StatementExpression>(0));
return rv;
} catch (Exception ex) {
@@ -51,17 +51,15 @@ namespace BCG {
_stream_pub_map = new Dictionary<string, StreamPubUnit>();
readonly IPubTableBroker _broker;
readonly IManagedSubscriber _sub;
readonly IDataStreamFactory streamFactory;
readonly object syncRoot = new();
IDisposable? cloudStreamsSub;
IDisposable? remoteRequestsSub;
bool isDisposed;
public RemoteQueryManager(IManagedSubscriber managedSubscriber, IPubTableBroker pubTableBroker, IDataStreamFactory streamFactory) {
public RemoteQueryManager(IManagedSubscriber managedSubscriber, IPubTableBroker pubTableBroker) {
_sub = managedSubscriber;
_broker = pubTableBroker;
this.streamFactory = streamFactory;
}
public Task StartAsync(CancellationToken cancellationToken) {
@@ -104,11 +102,7 @@ namespace BCG {
private void _spawn_remote_stream(string name, string stream_expression, bool persist) {
bts.Log.Gen.info($"CloudStreamManager.assign name: {name} stream_expression: {stream_expression}");
var stream = build_stream(streamFactory, stream_expression);
if (stream is null) {
Log.DataFlow.error($"Failed to spawn remote stream. name: {name}; expression: {stream_expression}");
return;
}
ViewStream stream = build_stream(stream_expression);
_expose_to_ws(name, stream);
if (persist) {
stream = new PersistorStream(stream, name, "C:\\Temp\\", 1000000); // 10MBs
@@ -25,12 +25,12 @@ namespace BCG {
byte[] rem_req_bytes = rem_req.serialize();
_publisher_core.publish("System", "RemoteRequest", rem_req_bytes);
_source_str = new TableStream(_name);
_source_str.onChange += _handle_data;
_source_str.onChange += new ChangeDelegate(_handle_data);
}
protected override void myOnLastSubscriber() {
//maybe there should be a way to turn remote requests off ?
_source_str.onChange -= _handle_data;
_source_str.onChange -= new ChangeDelegate(_handle_data);
}
static string get_expression(params string[] lines) {
@@ -21,11 +21,13 @@ namespace BCG
: this (new TableStream (tableName))
{}
protected override void myOnFirstSubscriber () =>
myVS.onChange += myHandleChanges;
protected override void myOnFirstSubscriber () {
myVS.onChange += new ChangeDelegate(myHandleChanges);
}
protected override void myOnLastSubscriber () {
myVS.onChange -= new ChangeDelegate(myHandleChanges);
}
protected override void myOnLastSubscriber () =>
myVS.onChange -= myHandleChanges;
private void myHandleChanges(object newValue)
{
@@ -30,7 +30,7 @@ namespace BCG
protected override void myOnFirstSubscriber()
{
myToCrush.onChange += myToCrush_onChange;
myToCrush.onChange += new ChangeDelegate(myToCrush_onChange);
}
protected override void myOnLastSubscriber()
@@ -15,11 +15,11 @@ namespace BCG
//set up an anonymous delegate for each of the streams
//we do this so that we can unsubscribe
myDelegates = new DataStreamChangeDelegate[myToCrush.Length];
myDelegates = new ChangeDelegate[myToCrush.Length];
for (int i = 0; i < myToCrush.Length; ++i)
{
int tempI = i;
myDelegates[tempI] = new((o) => { myHandleChange(tempI, ((DataPacket)o).newRows); });
myDelegates[tempI] = new ChangeDelegate((o) => { myHandleChange(tempI, ((DataPacket)o).newRows); });
}
}
@@ -27,7 +27,7 @@ namespace BCG
private ViewStream[] myToCrush;
private ITableCrusher myCrusher;
private DataStreamChangeDelegate[] myDelegates;
private ChangeDelegate[] myDelegates;
protected override void myOnFirstSubscriber()
{
@@ -28,7 +28,7 @@ namespace BCG
protected override void myOnFirstSubscriber()
{
myDataSource.onChange += myDataSource_onChange;
myDataSource.onChange += new ChangeDelegate(myDataSource_onChange);
}
protected override void myOnLastSubscriber()
@@ -18,8 +18,7 @@ namespace bts {
_filename = filename;
}
protected override void myOnFirstSubscriber() =>
_stream.onChange += _handle_changes;
protected override void myOnFirstSubscriber() { _stream.onChange += new ChangeDelegate(_handle_changes); }
void _handle_changes(object dp_obj) {
DataPacket dp = dp_obj as DataPacket;
@@ -27,8 +26,7 @@ namespace bts {
myFireEvent(dp_obj);
}
protected override void myOnLastSubscriber() =>
_stream.onChange -= _handle_changes;
protected override void myOnLastSubscriber() { _stream.onChange -= new ChangeDelegate(_handle_changes); }
protected void _save(DataPacket dp) {
StreamIOMessage.CreateMessage cr_msg = new StreamIOMessage.CreateMessage(dp.newRows);
@@ -37,12 +37,12 @@ namespace BCG.StreamWorld.Addition
protected override void myOnFirstSubscriber()
{
myBaseStream.onChange += myHandleChanges;
myBaseStream.onChange += new ChangeDelegate(myHandleChanges);
}
protected override void myOnLastSubscriber()
{
myBaseStream.onChange -= myHandleChanges;
myBaseStream.onChange -= new ChangeDelegate(myHandleChanges);
myBaseTable.clear();
myStateTable.clear();
}
@@ -228,13 +228,13 @@ namespace BCG
#endregion
#region overridden methods
protected override void myOnFirstSubscriber() =>
myParentStream.onChange += myHandleCallbacks;
protected override void myOnFirstSubscriber()
{ myParentStream.onChange += new ChangeDelegate(myHandleCallbacks); }
protected override void myOnLastSubscriber()
{
myLastFiredRows = null;
myParentStream.onChange -= myHandleCallbacks;
myParentStream.onChange -= new ChangeDelegate(myHandleCallbacks);
}
protected override void myFireEvent(object o)
@@ -1,24 +0,0 @@
namespace bts.SilverPine {
using BCG;
using System;
public class NullFilterStream : ViewStream {
public NullFilterStream(ViewStream parent_str, string col_name)
: this(parent_str, col_name, true) { }
public NullFilterStream(ViewStream parent_str, string col_name, bool filter_out_doublenans = false) {
ViewStream rs = new FilterStream(parent_str,
r => {
bool is_dbnull = r.is_null(col_name);
if (is_dbnull) {
return false;
}
if (r.schema[col_name].type_code() == TypeCode.Double) {
return !Double.IsNaN(r.get<double>(col_name));
}
return true;
});
mySetRealSource(rs);
}
}
}
@@ -36,11 +36,11 @@ namespace BCG
get{return myIsFrozen;}
}
protected override void myOnFirstSubscriber () =>
myStreamToFreeze.onChange += myCallBack;
protected override void myOnFirstSubscriber ()
{myStreamToFreeze.onChange += new DataStream.ChangeDelegate (myCallBack);}
protected override void myOnLastSubscriber () =>
myStreamToFreeze.onChange -= myCallBack;
protected override void myOnLastSubscriber ()
{myStreamToFreeze.onChange -= new DataStream.ChangeDelegate (myCallBack);}
internal void myCallBack(object o)
{
@@ -96,15 +96,15 @@ namespace BCG
protected override void myOnFirstSubscriber()
{
myLeftSource.onChange += myLeft_onChange;
myRightSource.onChange += myRight_onChange;
this.myLeftSource.onChange += new ChangeDelegate(myLeft_onChange);
this.myRightSource.onChange += new ChangeDelegate(myRight_onChange);
this.myVsd.addWorker(this);
}
protected override void myOnLastSubscriber()
{
myLeftSource.onChange -= myLeft_onChange;
myRightSource.onChange -= myRight_onChange;
this.myLeftSource.onChange -= new ChangeDelegate(myLeft_onChange);
this.myRightSource.onChange -= new ChangeDelegate(myRight_onChange);
this.myVsd.removeWorker(this);
}
@@ -1,102 +1,102 @@
// using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// namespace BCG
// {
namespace BCG
{
// public class AverageGroupsStream : ViewStream
// {
// public AverageGroupsStream(ViewStream input, string colToAverage, string keyColumn)
// {
public class AverageGroupsStream : ViewStream
{
public AverageGroupsStream(ViewStream input, string colToAverage, string keyColumn)
{
// myColToAverage = colToAverage;
// myInput = input;
// myKeyColumn = keyColumn;
// }
myColToAverage = colToAverage;
myInput = input;
myKeyColumn = keyColumn;
}
// private ViewStream myInput;
// private string myColToAverage;
// private BlueTableSchema mySchema;
// private string myKeyColumn;
private ViewStream myInput;
private string myColToAverage;
private BlueTableSchema mySchema;
private string myKeyColumn;
// protected override void myOnFirstSubscriber()
// {
// myInput.onChange += new ChangeDelegate(myInput_onChange);
// }
// protected override void myOnLastSubscriber()
// {
// myInput.onChange -= myInput_onChange;
// }
// private void myInput_onChange(object newValue)
// {
// if (mySchema == null)
// myBuildSchema(((DataPacket)newValue).schema);
protected override void myOnFirstSubscriber()
{
myInput.onChange += new ChangeDelegate(myInput_onChange);
}
protected override void myOnLastSubscriber()
{
myInput.onChange -= myInput_onChange;
}
private void myInput_onChange(object newValue)
{
if (mySchema == null)
myBuildSchema(((DataPacket)newValue).schema);
// IBlueRowCollection newRows = myEvaluate((DataPacket)newValue);
IBlueRowCollection newRows = myEvaluate((DataPacket)newValue);
// if (myLastValue == null)
// myFireEvent(new DataPacket(newRows, newRows, new BlueTable(mySchema)));
// else
// {
// IBlueRowCollection added, deleted;
// BlueDataUtility.computeDifferences(newRows, ((DataPacket) myLastValue).newRows, out deleted, out added);
// myFireEvent(new DataPacket(newRows, added, deleted));
// }
// }
if (myLastValue == null)
myFireEvent(new DataPacket(newRows, newRows, new BlueTable(mySchema)));
else
{
IBlueRowCollection added, deleted;
BlueDataUtility.computeDifferences(newRows, ((DataPacket) myLastValue).newRows, out deleted, out added);
myFireEvent(new DataPacket(newRows, added, deleted));
}
}
// private void myBuildSchema(IBlueTableSchema schema)
// {
// List<ColumnInfo> columns = new List<ColumnInfo>();
private void myBuildSchema(IBlueTableSchema schema)
{
List<ColumnInfo> columns = new List<ColumnInfo>();
// foreach (ColumnInfo ci in schema.columnInfo)
// columns.Add(ci);
foreach (ColumnInfo ci in schema.columnInfo)
columns.Add(ci);
// columns.Add(new ColumnInfo("average_"+myColToAverage, columns.Count, typeof(double)));
// mySchema = new BlueTableSchema("average_of_" + schema.tableName, columns.ToArray());
// }
columns.Add(new ColumnInfo("average_"+myColToAverage, columns.Count, typeof(double)));
mySchema = new BlueTableSchema("average_of_" + schema.tableName, columns.ToArray());
}
// private IBlueRowCollection myEvaluate(DataPacket packet)
// {
private IBlueRowCollection myEvaluate(DataPacket packet)
{
// IDictionary<string, double> colToRunningTotal = new Dictionary<string, double>();
// IDictionary<string, int> colToCount = new Dictionary<string, int>();
// IDictionary<string, IBlueRow> colToLastRow = new Dictionary<string, IBlueRow>();
IDictionary<string, double> colToRunningTotal = new Dictionary<string, double>();
IDictionary<string, int> colToCount = new Dictionary<string, int>();
IDictionary<string, IBlueRow> colToLastRow = new Dictionary<string, IBlueRow>();
// foreach (IBlueRow r in packet.newRows)
// {
// double thisVal = Convert.ToDouble(r[myColToAverage]);
foreach (IBlueRow r in packet.newRows)
{
double thisVal = Convert.ToDouble(r[myColToAverage]);
// string keyVal = r[myKeyColumn].ToString();
// if (!colToCount.ContainsKey(keyVal))
// {
// colToRunningTotal[keyVal] = thisVal;
// colToCount[keyVal] = 1;
// }
// else
// {
// colToRunningTotal[keyVal] += thisVal;
// colToCount[keyVal] += 1;
// }
// colToLastRow[keyVal] = r;
// }
string keyVal = r[myKeyColumn].ToString();
if (!colToCount.ContainsKey(keyVal))
{
colToRunningTotal[keyVal] = thisVal;
colToCount[keyVal] = 1;
}
else
{
colToRunningTotal[keyVal] += thisVal;
colToCount[keyVal] += 1;
}
colToLastRow[keyVal] = r;
}
// BlueTable result = new BlueTable(mySchema);
// foreach (string key in colToCount.Keys)
// {
// object[] values = new object[mySchema.columnInfo.Length];
BlueTable result = new BlueTable(mySchema);
foreach (string key in colToCount.Keys)
{
object[] values = new object[mySchema.columnInfo.Length];
// colToLastRow[key].CopyTo(values, 0);
// values[values.Length - 1] = packet.newRows.Count > 0 ? colToRunningTotal[key] / packet.newRows.Count : 0.0;
// result.addRow(new BlueRow(mySchema, values));
// }
colToLastRow[key].CopyTo(values, 0);
values[values.Length - 1] = packet.newRows.Count > 0 ? colToRunningTotal[key] / packet.newRows.Count : 0.0;
result.addRow(new BlueRow(mySchema, values));
}
// return result;
// }
return result;
}
// }
// }
}
}
@@ -1,31 +0,0 @@
namespace bts.SilverPine {
using BCG;
using System;
using System.Collections.Generic;
using System.Linq;
[DataStreamUserRespresentation("Average")]
public class AverageNonIncGroupsStream : ViewStream {
public AverageNonIncGroupsStream(ViewStream parent_stream, string inp_col_name, params string[] group_by_cols) {
NonIncGroupByStream rs = new NonIncGroupByStream(parent_stream, () => group_by_cols,
(g_rows) => _find_mean(inp_col_name, g_rows));
mySetRealSource(rs);
}
private List<IBlueRow> _find_mean(string inp_col_name, List<IBlueRow> g_rows) {
IBlueRow inp_row = g_rows.ElementAt(0);
IEnumerable<double> inp_vals = BlueDataUtility.get_colvalues<double>(g_rows, inp_col_name);
double sum = 0.0;
inp_vals.ToList().ForEach(d => sum += d);
string out_col_name = $"average_{inp_col_name}";
double average = sum / inp_vals.Count();
IBlueTableSchema schema_out = inp_row.schema.add_column(TypeCode.Double, out_col_name);
MutableBlueRow out_row = new MutableBlueRow(schema_out, inp_row);
out_row.setValue(out_col_name, average);
List<IBlueRow> rv = new List<IBlueRow>();
rv.Add(out_row);
return rv;
}
}
}
@@ -1,91 +0,0 @@
namespace bts.SilverPine {
using BCG;
using System;
using System.Collections.Generic;
using System.Linq;
using ZstdSharp.Unsafe;
public enum GroupByBundleOp {
Mean,
Median,
Mode,
StdDev,
Max,
Min,
First,
Last,
Sum
}
public class GroupByBundle {
public readonly List<Tuple<string, GroupByBundleOp>> operations;
public static GroupByBundle parse(string text) {
// text is inp_col: op, inp_col: op, inp_col:op
List<Tuple<string, GroupByBundleOp>> rv = new List<Tuple<string, GroupByBundleOp>>();
string[] calcs = text.Split(',');
foreach (string c in calcs) {
string[] toks = c.Split(':');
string inp_col = toks[0].Trim();
string op_txt = toks[1].Trim();
GroupByBundleOp op = Enum.Parse<GroupByBundleOp>(op_txt, true);
rv.Add(Tuple.Create(inp_col, op));
}
return new GroupByBundle(rv);
}
public GroupByBundle(List<Tuple<string, GroupByBundleOp>> operations_) {
operations = operations_;
}
public static IBlueRow group_by(List<IBlueRow> rows, GroupByBundle parameters) {
if (rows.Count() == 0) {
return null;
}
IBlueRow ir = rows.ElementAt(0);
IBlueTableSchema in_schema = ir.schema;
IBlueTableSchema out_schema = in_schema;
IDictionary<string, Tuple<string, GroupByBundleOp>> out_col_map =
new Dictionary<string, Tuple<string, GroupByBundleOp>>();
foreach (var t in parameters.operations) {
string out_col_name = $"{t.Item1}_{t.Item2}".ToLower();
out_schema = out_schema.add_column(TypeCode.Double, out_col_name);
out_col_map[out_col_name] = t;
}
MutableBlueRow or = new MutableBlueRow(out_schema, ir);
foreach (var kv in out_col_map) {
string out_col_name = kv.Key;
string in_col_name = kv.Value.Item1;
GroupByBundleOp op = kv.Value.Item2;
IEnumerable<double> col_vals = BlueDataUtility.get_colvalues<double>(rows, in_col_name);
double comp_res = compute_op(col_vals, op);
or.setValue(out_col_name, comp_res);
}
return or;
}
public static double compute_op(IEnumerable<double> col_vals, GroupByBundleOp op) {
switch (op) {
case GroupByBundleOp.Max:
return col_vals.Max<double>();
case GroupByBundleOp.Min:
return col_vals.Min<double>();
case GroupByBundleOp.Mean:
return col_vals.Sum() / col_vals.Count();
case GroupByBundleOp.Sum:
return col_vals.Sum();
case GroupByBundleOp.First:
return col_vals.First();
case GroupByBundleOp.Last:
return col_vals.Last();
default:
// TODO
Log.assert(false);
return Double.NaN;
}
}
}
}
@@ -175,7 +175,7 @@ namespace BCG {
//gets resubscribed, we start the process of building data again, and treat the callback as the first
//callback.
myInit();
myStream.onChange -= myChangeHandler;
myStream.onChange -= new DataStream.ChangeDelegate(myChangeHandler);
}
protected override void myInit() {
@@ -10,6 +10,6 @@ namespace BCG {
}
public MaxStream(ViewStream stream, string outputCol)
: this(new AddColumnsStream(stream, "fake_col: 0"), outputCol, new string[] { "fake_col" }) { }
: this(new AddColumnsStream(stream, "fakeCol=0"), outputCol, new string[] { "fakeCol" }) { }
}
}
@@ -82,12 +82,12 @@ namespace BCG
protected override void myOnFirstSubscriber()
{
myStream.onChange += myChangeHandler;
myStream.onChange += new DataStream.ChangeDelegate (myChangeHandler);
}
protected override void myOnLastSubscriber ()
{
myStream.onChange -= myChangeHandler;
myStream.onChange -= new DataStream.ChangeDelegate (myChangeHandler);
}
}
}
@@ -1,40 +1,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.Json;
using bts;
using bts.SilverPine;
namespace BCG {
[DataStreamUserRespresentation("aggregate")]
public class NonIncGroupByStream : ViewStream {
private class DelNonIncGroupByEvaluator : INonIncGroupByEvaluator {
Func<string[]> _groupby_cols_func;
Func<List<IBlueRow>, List<IBlueRow>> _evaluate_func;
public DelNonIncGroupByEvaluator(Func<string[]> groupby_cols_func,
Func<List<IBlueRow>, List<IBlueRow>> evaluate_func) {
_groupby_cols_func = groupby_cols_func;
_evaluate_func = evaluate_func;
}
public IBlueRowCollection evaluate(IDictionary<int, List<IBlueRow>> grouped_rows) {
BlueTable rv = null;
foreach (var kv in grouped_rows) {
List<IBlueRow> g_rows = kv.Value;
List<IBlueRow> out_rows = _evaluate_func.Invoke(g_rows);
if (out_rows != null && out_rows.Count > 0) {
rv = rv ?? new BlueTable(out_rows.ElementAt(0).schema);
}
rv.addRows(out_rows);
}
return rv;
}
public string[] get_group_by_cols() {
return _groupby_cols_func();
}
}
namespace BCG
{
public class NonIncGroupByStream : ViewStream
{
private ViewStream _main_stream;
private INonIncGroupByEvaluator _groupby_func;
private BlueRowHasher _row_hasher;
@@ -42,47 +15,24 @@ namespace BCG {
private Stopwatch _timer = new();
private int _n_total_fires = 0, _n_expensive_fires = 0;
public NonIncGroupByStream(ViewStream main_stream, INonIncGroupByEvaluator groupby_func) {
public NonIncGroupByStream(ViewStream main_stream, INonIncGroupByEvaluator groupby_func)
{
_main_stream = main_stream;
_groupby_func = groupby_func;
_groupby_cols = _groupby_func.get_group_by_cols();
_row_hasher = new BlueRowHasher(_groupby_cols == null ? 0 : _groupby_cols.Length);
_row_hasher = new BlueRowHasher(_groupby_cols.Length);
}
public NonIncGroupByStream(ViewStream main_stream, Func<string[]> groupby_cols_func,
Func<List<IBlueRow>, List<IBlueRow>> evaluate_func)
: this(main_stream, new DelNonIncGroupByEvaluator(groupby_cols_func, evaluate_func)) { }
public NonIncGroupByStream(ViewStream parent_str, string groupby_col, string standard_group_by_text, string optional_sort_col = null) {
GroupByBundle std_group_by = GroupByBundle.parse(standard_group_by_text);
Func<string[]> groupby_cols_func = () => {
return String.IsNullOrEmpty(groupby_col) ? null : new string[] { groupby_col };
};
Func<List<IBlueRow>, List<IBlueRow>> evaluate_func = (group_rows) => {
if (!String.IsNullOrEmpty(optional_sort_col))
group_rows.Sort((r1, r2) => BlueDataUtility.compare_rows(r2, r1, optional_sort_col));
IBlueRow rv = GroupByBundle.group_by(group_rows, std_group_by);
return new IBlueRow[] { rv }.ToList();
};
ViewStream rs = new NonIncGroupByStream(parent_str, groupby_cols_func, evaluate_func);
mySetRealSource(rs);
}
public NonIncGroupByStream(ViewStream parent_str, string standard_group_by_text) :
this(parent_str, String.Empty, standard_group_by_text) {
}
protected override void myOnFirstSubscriber() { _main_stream.onChange += _main_stream_onchange; }
protected override void myOnLastSubscriber() { _main_stream.onChange -= _main_stream_onchange; }
private void _main_stream_onchange(object nv) {
private void _main_stream_onchange(object nv)
{
DataPacket dp = nv as DataPacket;
///grouping together
_timer.Restart();
IDictionary<int, List<IBlueRow>> grouped_rows = (_groupby_cols == null || _groupby_cols.Length == 0) ?
new Dictionary<int, List<IBlueRow>>() { { 0, dp.newRows.to_list() } } :
BlueDataUtility.group_together(dp.newRows, _groupby_cols, ref _row_hasher);
IDictionary<int, List<IBlueRow>> grouped_rows = BlueDataUtility.group_together (dp.newRows, _groupby_cols, ref _row_hasher);
_timer.Stop();
var groupElapsedMs = _timer.ElapsedMilliseconds;
if (groupElapsedMs >= 50) {
@@ -98,15 +48,14 @@ namespace BCG {
return;
}
var applyElapsedMs = _timer.ElapsedMilliseconds;
_n_total_fires++;
if (applyElapsedMs >= 50) {
_n_total_fires++;
if (applyElapsedMs >= 50)
{
_n_expensive_fires++;
Log.DataFlow.info(
$"Time to evaluate {grouped_rows.Count} groups {_timer.ElapsedMilliseconds}ms, ratio {_n_expensive_fires}/{_n_total_fires}");
}
// TODO,
if (total_state != null)
myFireEvent(new DataPacket(total_state, total_state, myLastValue == null ? new BlueTable(total_state.schema) : (myLastValue as DataPacket).newRows));
}
myFireEvent(new DataPacket(total_state, total_state, myLastValue == null ? new BlueTable(total_state.schema) : (myLastValue as DataPacket).newRows));
}
}
}
@@ -31,15 +31,15 @@ namespace BCG
{
myLeftOperand.master = this;
myRightOperand.master = this;
myLeftStream.onChange += myLeftOperand.changeHandler;
myRightStream.onChange += myRightOperand.changeHandler;
myLeftStream.onChange += new DataStream.ChangeDelegate (myLeftOperand.changeHandler);
myRightStream.onChange += new DataStream.ChangeDelegate (myRightOperand.changeHandler);
}
protected override void myOnLastSubscriber ()
{
myInit ();
myLeftStream.onChange -= myLeftOperand.changeHandler;
myRightStream.onChange -= myRightOperand.changeHandler;
myLeftStream.onChange -= new DataStream.ChangeDelegate (myLeftOperand.changeHandler);
myRightStream.onChange -= new DataStream.ChangeDelegate (myRightOperand.changeHandler);
}
public JoinOperand getOtherOperand (JoinOperand jo)
@@ -116,7 +116,7 @@ namespace BCG
IDictionary map = resolver.getMap ();
map["id"] = "id";
myPs = new ProjectStream (myIjs, map);
myPs.onChange += myProjectChangeHandler;
myPs.onChange += new DataStream.ChangeDelegate (myProjectChangeHandler);
return;
}
else
@@ -129,26 +129,26 @@ namespace BCG
private void myProjectChangeHandler (object o)
{
if (myIjs.myOnChangeDelegate.GetInvocationList().Length > 1)
myIjs.onChange -= myInternalJoinChangeHandler;
myIjs.onChange -= new DataStream.ChangeDelegate (myInternalJoinChangeHandler);
myFireEvent ((o as ICloneable).Clone());
}
protected override void myOnFirstSubscriber ()
{
myIjs.onChange += myInternalJoinChangeHandler;
myIjs.onChange += new DataStream.ChangeDelegate (myInternalJoinChangeHandler);
}
protected override void myOnLastSubscriber ()
{
// how does this relate to the -= in myProjectChangeHandler?
myIjs.onChange -= myInternalJoinChangeHandler;
myIjs.onChange -= new DataStream.ChangeDelegate (myInternalJoinChangeHandler);
// if there is a project after the ijs we need to
// unsubscribe to it otherwise references will be kept and
// a memory leak will occur
if (myPs != null)
myPs.onChange -= myProjectChangeHandler;
myPs.onChange -= new DataStream.ChangeDelegate (myProjectChangeHandler);
myPs = null;
}
@@ -1,16 +1,15 @@
using bts;
using bts.collections;
using mbts;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
namespace BCG {
public class NonIncJoinBookkeeper : IDisposable {
namespace BCG
{
public class NonIncJoinBookkeeper : IDisposable
{
public Action on_new_data;
private readonly NonIncJoinSpec _join_spec;
private readonly int _join_position;
@@ -27,71 +26,41 @@ namespace BCG {
private int[] _join_col_indices = null,
_data_col_indices = null;
public NonIncJoinBookkeeper(NonIncJoinSpec the_join_spec, int join_position, int start_index_in_output, BlueRowHasher row_hasher) {
public NonIncJoinBookkeeper(NonIncJoinSpec the_join_spec, int join_position, int start_index_in_output, BlueRowHasher row_hasher)
{
_join_spec = the_join_spec;
_join_position = join_position;
_start_index_in_output = start_index_in_output;
_row_hasher = row_hasher;
_is_left_most = _join_position == 0;
_is_tag_along = _join_spec.join_col_names.Length == 0;
}
private bool _filled_missing_data = false;
private void _fill_missing_data(DataPacket dp) {
if (_filled_missing_data)
return;
Func<string[], bool> null_or_empty = (str_arr) => {
if (str_arr == null || str_arr.Length == 0)
return true;
foreach (string s in str_arr) {
if (!String.IsNullOrEmpty(s)) {
return false;
}
}
return true;
};
Func<string[], string[]> remove_bad_cols = (col_names) => {
HashSet<string> schema_col_map = new HashSet<string>(dp.schema.columnNames);
List<string> cols_list = new List<string>(col_names);
cols_list.RemoveWhere(c => !schema_col_map.Contains(c));
return cols_list.ToArray();
};
if (null_or_empty(_join_spec.data_col_names)) {
_join_spec.data_col_names = dp.schema.columnNames;
}
_join_spec.data_col_names = remove_bad_cols(_join_spec.data_col_names);
if (null_or_empty(_join_spec.data_col_names)) {
_join_spec.data_col_names = dp.schema.columnNames;
}
if (null_or_empty(_join_spec.projected_col_names)) {
_join_spec.projected_col_names = _join_spec.data_col_names;
}
}
public void init() {
_join_spec.stream.onChange += _on_stream_cb;
}
public void _on_stream_cb(object dp_obj) {
Log.Gen.info($"NonIncJoinBookkeeper._on_stream_cb dp_obj: {dp_obj}");
public void _on_stream_cb(object dp_obj)
{
var timer = Stopwatch.StartNew();
DataPacket dp = (DataPacket)dp_obj;
_fill_missing_data(dp);
if (_schema == null) {
if (_schema == null)
{
_schema = dp.schema;
_join_col_indices = BlueDataUtility.get_column_indices(_schema, _join_spec.join_col_names);
_data_col_indices = BlueDataUtility.get_column_indices(_schema, _join_spec.data_col_names);
}
if (_is_left_most) {
if (_is_left_most)
{
_row_list.Clear();
foreach (IBlueRow r in dp.newRows)
_row_list.Add(new Pair<int, IBlueRow>(_row_hasher.get_hash(r, _join_col_indices), r));
} else {
_row_list.Add(new Pair<int, IBlueRow>(_row_hasher.get_hash(r, _join_col_indices), r));
}
else
{
if (_is_tag_along)
_solitary_row = BlueDataUtility.extractRow(dp.newRows, 0);
else {
else
{
_row_map.Clear();
foreach (IBlueRow r in dp.newRows)
_row_map[_row_hasher.get_hash(r, _join_col_indices)] = r;
@@ -110,25 +79,31 @@ namespace BCG {
public bool is_ready { get { return _schema != null; } }
public void constribute_cols_to_schema(List<ColumnInfo> cis) {
public void constribute_cols_to_schema(List<ColumnInfo> cis)
{
for (int i = 0; i < _join_spec.data_col_names.Length; i++)
cis.Add(new ColumnInfo(_join_spec.projected_col_names[i], cis.Count, _schema[_join_spec.data_col_names[i]].colType));
}
public List<Pair<int, IBlueRow>> get_list() { return _row_list; }
public void copy_master_row_to_output_row(int row_index, object[] output_row) {
public void copy_master_row_to_output_row(int row_index, object[] output_row)
{
IBlueRow this_row = _row_list[row_index].second;
BlueDataUtility.copy_to_row(this_row, _data_col_indices, output_row, _start_index_in_output);
}
public void copy_matching_row_to_output_row(int row_hash, object[] output_row) {
if (_is_tag_along) {
public void copy_matching_row_to_output_row(int row_hash, object[] output_row)
{
if (_is_tag_along)
{
if (_solitary_row != null)
BlueDataUtility.copy_to_row(_solitary_row, _data_col_indices, output_row, _start_index_in_output);
else
copy_dbnull_to_output_row(output_row);
} else {
}
else
{
IBlueRow this_row = null;
if (_row_map.TryGetValue(row_hash, out this_row))
BlueDataUtility.copy_to_row(this_row, _data_col_indices, output_row, _start_index_in_output);
@@ -137,7 +112,8 @@ namespace BCG {
}
}
private void copy_dbnull_to_output_row(object[] output_row) {
private void copy_dbnull_to_output_row(object[] output_row)
{
for (int i = 0; i < _data_col_indices.Length; i++)
output_row[i + _start_index_in_output] = DBNull.Value;
}
@@ -3,63 +3,63 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using mbts;
namespace BCG {
// this a collection of data, theres no joining logic in here
public class NonIncJoinSpec {
namespace BCG
{
public class NonIncJoinSpec
{
public ViewStream stream;
// join col names are the names on which the streams are joined (for equality),
// data col names are the names in the original stream
// projected col names are their new names, ie if its x:l_x, then x is in the
// data_col_names and l_x in projected cols
public string[] join_col_names, data_col_names, projected_col_names;
public NonIncJoinSpec() { }
public NonIncJoinSpec(ViewStream the_stream, string[] the_join_col_names, string[] the_data_col_names)
: this(the_stream, the_join_col_names, the_data_col_names, the_data_col_names) { }
: this (the_stream, the_join_col_names, the_data_col_names, the_data_col_names)
{ }
public NonIncJoinSpec(ViewStream the_stream, string[] the_join_col_names, string[] the_data_col_names, string[] the_projected_col_names) {
public NonIncJoinSpec(ViewStream the_stream, string[] the_join_col_names, string[] the_data_col_names, string[] the_projected_col_names)
{
stream = the_stream;
join_col_names = the_join_col_names;
data_col_names = the_data_col_names;
projected_col_names = the_projected_col_names;
}
public static NonIncJoinSpec[] from_triplet(params Triplet<ViewStream, string, string>[] join_specs) {
public static NonIncJoinSpec[] from_triplet(params Triplet<ViewStream, string, string>[] join_specs)
{
List<NonIncJoinSpec> rv = new List<NonIncJoinSpec>();
foreach (Triplet<ViewStream, string, string> r in join_specs) {
string[] keys = String.IsNullOrEmpty(r.second) ? new string[] { } : r.second.Split(' ');
foreach (Triplet<ViewStream, string, string> r in join_specs)
{
string[] keys = String.IsNullOrEmpty (r.second) ? new string[] {} : r.second.Split(' ');
string[] visible_cols = r.third.Split(' ');
List<string> data_col_names = new List<string>(), mapped_col_names = new List<string>();
foreach (string s in visible_cols) {
foreach (string s in visible_cols)
{
string[] toks = s.Split(':');
if (toks.Length == 1) {
if (toks.Length == 1)
{
data_col_names.Add(toks[0]);
mapped_col_names.Add(toks[0]);
} else if (toks.Length == 2) {
}
else if (toks.Length == 2)
{
data_col_names.Add(toks[0]);
mapped_col_names.Add(toks[1]);
}
}
rv.Add(new NonIncJoinSpec(r.first, keys, data_col_names.ToArray(), mapped_col_names.ToArray()));
rv.Add (new NonIncJoinSpec (r.first, keys, data_col_names.ToArray (), mapped_col_names.ToArray()));
}
return rv.ToArray();
}
public override string ToString() {
Func<string[], string> arr_txt = (a) => {
string rv = "";
foreach (string s in a) {
rv += "{s} ";
}
rv = rv.Trim();
return rv;
};
string rv = $"stream: {stream} join_col_names: {arr_txt(join_col_names)} data_col_names: {arr_txt(data_col_names)} projected_col_names: {arr_txt(projected_col_names)}";
return rv;
return rv.ToArray ();
}
}
//[DataStreamUserRespresentation("ninctest")]
//public class NonIncJoinTestStream : ViewStream
//{
// public NonIncJoinTestStream (string key_cols, string data_cols)
// {
// NonIncJoinSpec.from_triplet(new Triplet<ViewStream, string, string>(null, key_cols, data_cols));
// }
//}
}
@@ -6,9 +6,11 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace BCG {
namespace BCG
{
[DataStreamUserRespresentation("fastJoin")]
public class NonIncJoinStream : ViewStream, BCG.Utilities.General.IWorker {
public class NonIncJoinStream : ViewStream, BCG.Utilities.General.IWorker
{
private readonly NonIncJoinSpec[] _join_specs;
private readonly INonIncJoinInlineMapper _output_mapper;
private readonly BlueRowHasher _row_hasher;
@@ -26,19 +28,24 @@ namespace BCG {
{
new Triplet<ViewStream, string, string> (left, left_join_cols, left_proj),
new Triplet<ViewStream, string, string> (right, right_join_cols, right_proj)
}) { }
})
{ }
public NonIncJoinStream(params Triplet<ViewStream, string, string>[] join_specs)
: this(NonIncJoinSpec.from_triplet(join_specs), null, 0) { }
: this(NonIncJoinSpec.from_triplet(join_specs), null, 0)
{ }
public NonIncJoinStream(ViewStreamDatabase vsd, INonIncJoinInlineMapper output_mapper, int throttles_ms,
params Triplet<ViewStream, string, string>[] join_specs)
: this(vsd, NonIncJoinSpec.from_triplet(join_specs), output_mapper, throttles_ms) { }
: this(vsd, NonIncJoinSpec.from_triplet(join_specs), output_mapper, throttles_ms)
{ }
public NonIncJoinStream(NonIncJoinSpec[] join_specs, INonIncJoinInlineMapper output_mapper, int throttles_ms = 0)
: this(ViewStreamDatabase.instance, join_specs, output_mapper, throttles_ms) { }
: this(ViewStreamDatabase.instance, join_specs, output_mapper, throttles_ms)
{ }
public NonIncJoinStream(ViewStreamDatabase vsd, NonIncJoinSpec[] join_specs, INonIncJoinInlineMapper output_mapper, int throttles_ms = 0) {
public NonIncJoinStream(ViewStreamDatabase vsd, NonIncJoinSpec[] join_specs, INonIncJoinInlineMapper output_mapper, int throttles_ms = 0)
{
_join_specs = join_specs;
_output_mapper = output_mapper;
_row_hasher = new BlueRowHasher(_join_specs[0].join_col_names.Length);
@@ -46,11 +53,12 @@ namespace BCG {
_vsd = vsd;
}
protected override void myOnFirstSubscriber() {
protected override void myOnFirstSubscriber()
{
int data_col_no = 1;
for (int jp = 0; jp < _join_specs.Length; jp++) {
for (int jp = 0; jp < _join_specs.Length; jp++)
{
NonIncJoinBookkeeper s = new NonIncJoinBookkeeper(_join_specs[jp], jp, data_col_no, _row_hasher);
Log.Gen.info($"NonIncJoinStream.myOnFirstSubscriber jp: {jp} spec: {_join_specs[jp]}");
data_col_no += _join_specs[jp].data_col_names.Length;
s.on_new_data += _stream_callback;
_book_keeping_data.Add(s);
@@ -58,11 +66,10 @@ namespace BCG {
if (_output_mapper != null)
_output_mapper.onMapperChange += _on_mapper_change;
_vsd.addWorker(this);
foreach (var bkd in _book_keeping_data)
bkd.init();
}
protected override void myOnLastSubscriber() {
protected override void myOnLastSubscriber()
{
foreach (NonIncJoinBookkeeper d in _book_keeping_data)
d.Dispose();
if (_output_mapper != null)
@@ -70,26 +77,30 @@ namespace BCG {
_vsd.removeWorker(this);
}
private void _stream_callback() {
Log.Gen.info("NonIncJoinStream._stream_callback received callback");
private void _stream_callback()
{
_is_dirty = true;
doWork();
}
private void _on_mapper_change() {
private void _on_mapper_change()
{
_is_dirty = true;
doWork();
}
private bool _is_ready() {
private bool _is_ready()
{
bool rv = true;
foreach (NonIncJoinBookkeeper d in _book_keeping_data)
rv &= d.is_ready;
return rv;
}
private void _construct_schema() {
if (_output_schema == null) {
private void _construct_schema()
{
if (_output_schema == null)
{
List<ColumnInfo> cis = new List<ColumnInfo>(new ColumnInfo[] { new ColumnInfo("id", 0, typeof(int)) });
foreach (NonIncJoinBookkeeper d in _book_keeping_data)
d.constribute_cols_to_schema(cis);
@@ -98,23 +109,27 @@ namespace BCG {
}
private int _n_total_fires = 0, _n_expensive_fires = 0;
private void _form_and_fire() {
Log.Gen.info($"NonIncJoinStream._form_and_fire _is_ready(): {_is_ready()}");
if (_is_ready()) {
private void _form_and_fire()
{
if (_is_ready())
{
_construct_schema();
var timer = Stopwatch.StartNew();
IList<Pair<int, IBlueRow>> left_row_list = _book_keeping_data[0].get_list();
List<object[]> output_rows = new List<object[]>();
for (int i = 0; i < left_row_list.Count; i++) {
for (int i = 0; i < left_row_list.Count; i++)
{
object[] or = new object[_output_schema.columnInfo.Length];
or[0] = i;
output_rows.Add(or);
}
for (int ji = 0; ji < _book_keeping_data.Count; ji++) {
for (int ji = 0; ji < _book_keeping_data.Count; ji++)
{
NonIncJoinBookkeeper bk_data = _book_keeping_data[ji];
for (int i = 0; i < left_row_list.Count; i++) {
for (int i = 0; i < left_row_list.Count; i++)
{
if (ji == 0)
bk_data.copy_master_row_to_output_row(i, output_rows[i]);
else
@@ -124,20 +139,19 @@ namespace BCG {
IBlueRowCollection dp_output_rows = _apply_map(new SequentialIDBlueTable(_output_schema, output_rows));
timer.Stop();
_n_total_fires++;
//if (timer.ElapsedMilliseconds >= 250) {
_n_expensive_fires++;
string log_msg = $"Join and map time for {_book_keeping_data.Count} "
+ $"tables {timer.Elapsed.TotalMilliseconds} msecs, ratio {_n_expensive_fires}/{_n_total_fires}";
Log.Gen.info(log_msg);
//}
var dp_out = BlueDataUtility.build_dp_inc(dp_output_rows, myLastValue as DataPacket);
myFireEvent(dp_out);
//myFireEvent(new DataPacket(dp_output_rows, dp_output_rows, myLastValue == null ? new BlueTable(_output_schema) : (myLastValue as DataPacket).newRows));
if (timer.ElapsedMilliseconds >= 250) {
_n_expensive_fires++;
string log_msg = $"Join and map time for {_book_keeping_data.Count} "
+ $"tables {timer.Elapsed} ratio {_n_expensive_fires}/{_n_total_fires}";
}
myFireEvent(new DataPacket(dp_output_rows, dp_output_rows, myLastValue == null ? new BlueTable(_output_schema) : (myLastValue as DataPacket).newRows));
}
}
private IBlueRowCollection _apply_map(IBlueRowCollection unmapped_rows) {
if (_output_mapper != null) {
private IBlueRowCollection _apply_map(IBlueRowCollection unmapped_rows)
{
if (_output_mapper != null)
{
IBlueRowCollection output_rows;
var timer = Stopwatch.StartNew();
output_rows = _output_mapper.map_rows(unmapped_rows);
@@ -146,14 +160,17 @@ namespace BCG {
Log.Gen.info($"Time to map {unmapped_rows.Count} rows into {output_rows.Count} rows {timer.Elapsed}");
}
return output_rows;
} else {
}
else
{
return unmapped_rows;
}
}
public void doWork() {
Log.Gen.info($"NonIncJoinStream.doWork _last_fire_time: {_last_fire_time} _is_dirty: {_is_dirty}");
if (DateTime.Now - _last_fire_time >= _throttle_period && _is_dirty) {
public void doWork()
{
if (DateTime.Now - _last_fire_time >= _throttle_period && _is_dirty)
{
_is_dirty = false;
_last_fire_time = DateTime.Now;
_form_and_fire();
@@ -181,8 +181,8 @@ namespace BCG
protected override void myOnFirstSubscriber()
{
myVLeft.onChange += myVLeft_onChange;
myVRight.onChange += myVRight_onChange;
myVLeft.onChange += new ChangeDelegate(myVLeft_onChange);
myVRight.onChange += new ChangeDelegate(myVRight_onChange);
}
void myVRight_onChange(object newValue)
@@ -1,68 +0,0 @@
namespace bts {
using BCG;
using BCG.Utilities.General;
using System;
using System.Diagnostics;
using ZstdSharp.Unsafe;
// functon that joins the 2 rows and returns the outputput row. The function
// can return a null which means the 2 rows dont need to be joined
using JoinFunc = System.Func<BCG.IBlueRow, BCG.IBlueRow, BCG.IBlueRow>;
public class ProximityJoinStream : ViewStream, IWorker {
private ViewStream _lvs, _rvs;
private JoinFunc _join_func;
private bool _dirty = false;
private Stopwatch _stopwatch = new Stopwatch();
private ViewStreamDatabase _vsd = ViewStreamDatabase.instance;
public ProximityJoinStream(ViewStream lvs, ViewStream rvs, JoinFunc join_func) {
_lvs = lvs;
_rvs = rvs;
_join_func = join_func;
}
protected override void myOnFirstSubscriber() {
_lvs.onChange += _handle_data;
_rvs.onChange += _handle_data;
_vsd.addWorker(this);
}
protected override void myOnLastSubscriber() {
_lvs.onChange -= _handle_data;
_rvs.onChange -= _handle_data;
_vsd.removeWorker(this);
}
private void _handle_data(object dp_obj) {
_dirty = true;
doWork();
}
public void doWork() {
Func<bool> all_data_revcd = () => {
return _lvs.rows != null && _rvs.rows != null;
};
_stopwatch.Start();
if (_dirty && all_data_revcd()) {
_dirty = false;
BlueTable rv = null;
foreach (IBlueRow lr in _lvs.rows) {
foreach (IBlueRow rr in _rvs.rows) {
IBlueRow resr = _join_func(lr, rr);
if (resr == null)
continue;
rv = rv ?? new BlueTable(resr.schema);
rv.addRow(resr);
}
}
_stopwatch.Stop();
Log.Gen.info($"ProximityJoinStream left_count: {_lvs.rows.Count} right_count: {_rvs.rows.Count} result_count: {rv.Count} time: {_stopwatch.ElapsedMilliseconds} msecs");
var dp = BlueDataUtility.build_dp_inc(rv, myLastValue as DataPacket);
myFireEvent(dp);
}
}
}
}
@@ -1,47 +0,0 @@
namespace bts.SilverPine {
using BCG;
using System;
using System.CodeDom;
using System.Configuration;
using System.Reactive.Disposables;
public class TimeProximityJoinStream : ViewStream {
private int _id = 0;
public TimeProximityJoinStream(ViewStream ls, string l_time_col, ViewStream rs, string r_time_col,
string pre_join_period, string post_join_period) :
this(ls, l_time_col, rs, r_time_col, TimeBasedFilter.parse_duration(pre_join_period),
TimeBasedFilter.parse_duration(post_join_period)) { }
public TimeProximityJoinStream(ViewStream ls, string l_time_col, ViewStream rs, string r_time_col,
TimeSpan pre_join_period, TimeSpan post_join_period) {
Func<IBlueRow, IBlueRow, IBlueRow> create_row = (lr, rr) => {
var id = 0;
lock (this) {
id = _id++;
}
IBlueRow rv = BlueDataUtility.create_composite_row(lr, rr, id);
return rv;
};
Func<IBlueRow, IBlueRow, IBlueRow> join_func = (lr, rr) => {
DateTime ldt = lr.get_datetime(l_time_col);
DateTime rdt = rr.get_datetime(r_time_col);
TimeSpan diff = ldt - rdt;
if (ldt < rdt) {
if (diff.Duration() > pre_join_period) {
return null;
}
} else {
if (diff > post_join_period)
return null;
}
return create_row(lr, rr);
};
ViewStream rstr = new ProximityJoinStream(ls, rs, join_func);
mySetRealSource(rstr);
}
}
}
@@ -327,14 +327,14 @@ namespace BCG
protected override void myOnFirstSubscriber()
{
myLeftStream.onChange += myHandleLeftStreamChanges;
myRightStream.onChange += myHandleRightStreamChanges;
myLeftStream.onChange += new ChangeDelegate(myHandleLeftStreamChanges);
myRightStream.onChange += new ChangeDelegate(myHandleRightStreamChanges);
}
protected override void myOnLastSubscriber()
{
myLeftStream.onChange -= myHandleLeftStreamChanges;
myRightStream.onChange -= myHandleRightStreamChanges;
myLeftStream.onChange -= new ChangeDelegate(myHandleLeftStreamChanges);
myRightStream.onChange -= new ChangeDelegate(myHandleRightStreamChanges);
myLeftKeyToLeftRows.Clear();
myRightKeyToRightRows.Clear();
myLeftIDToResultRows.Clear();
@@ -23,15 +23,15 @@ namespace BCG
myRightOperand.master = this;
//the events are not hooked onto the operands delegate, but rather a level of indirection
//added in the form on myLeftChangeHandler
myLeftStream.onChange += myLeftChangeHandler;
myRightStream.onChange += myRightChangeHandler;
myLeftStream.onChange += new DataStream.ChangeDelegate (myLeftChangeHandler);
myRightStream.onChange += new DataStream.ChangeDelegate (myRightChangeHandler);
}
protected override void myOnLastSubscriber ()
{
myInit ();
myLeftStream.onChange -= myLeftChangeHandler;
myRightStream.onChange -= myRightChangeHandler;
myLeftStream.onChange -= new DataStream.ChangeDelegate (myLeftChangeHandler);
myRightStream.onChange -= new DataStream.ChangeDelegate (myRightChangeHandler);
}
protected override void myInit()
@@ -2,13 +2,9 @@ using System;
using System.Collections;
using System.Collections.Generic;
using Amazon.Runtime.Internal.Util;
using BCG;
using BCG.Utilities;
using bts;
namespace BCG {
public class LiteralStream : ViewStream {
@@ -26,34 +22,6 @@ namespace BCG {
return rv;
}
//literal("table1", "x:123, y:1.001, z:abc;x:123, y:1.001, z:abc")
public LiteralStream(string table_name, string rows) {
Func<string, int, IBlueRow> get_row = (json_row, id) => {
Dictionary<string, object> map = new Dictionary<string, object>();
string[] toks = json_row.Split(',', StringSplitOptions.TrimEntries);
//Logger.assert(col_vals.Length == 2);
foreach (string t in toks) {
var col_vals = t.Split(':', StringSplitOptions.TrimEntries);
string col = col_vals[0];
string val = col_vals[1];
map.Add(col, val);
}
map["id"] = id;
return new BlueRow(map);
};
string[] row_arr = rows.Split(';', StringSplitOptions.TrimEntries);
BlueTable table = null;
foreach (string json_string in row_arr) {
IBlueRow r = //BlueDataUtility.convert_json_to_row(json_string, table == null ? 0 : table.Count);
get_row(json_string, table == null ? 0 : table.Count);
table = table ?? new BlueTable(r.schema);
table.addRow(r);
}
ViewStream str = new BlueTableStream(table);
str = new SchemaGuesserStream(str);
mySetRealSource(str);
}
public LiteralStream(string tableName, string schema, string value) {
string[] columns = schema.Split(' ');
@@ -87,7 +55,7 @@ namespace BCG {
mySetRealSource(new BlueRowCollectionStaticStream(t));
}
// public LiteralStream(string schema, string value) : this("literal", schema, value) { }
public LiteralStream(string schema, string value) : this("literal", schema, value) { }
// public LiteralStream(string value) {
@@ -1,72 +0,0 @@
using BCG;
using MongoDB.Driver.Core.WireProtocol.Messages;
using System;
using System.Collections.Generic;
using System.Linq;
// the first arg is all the rows, the second arg is the index of the row that needs mapping, and
// the func returns the mapped row (ie mapped version of the index row)
using GlobalMap = System.Func<System.Collections.Generic.List<BCG.IBlueRow>, uint, BCG.IBlueRow>;
namespace bts {
// In GlobalMap, each row is mapped with the full view of all rows, ie the map functions for a row
// can use the state fo all rows.
public class GlobalMapStream : ViewStream {
private ViewStream _base_stream;
private readonly string _sort_col_name, _group_by_col;
private GlobalMap _map_func;
public GlobalMapStream(ViewStream base_stream, string sort_col_name, string group_by_col, GlobalMap map_func) {
_base_stream = base_stream;
_sort_col_name = sort_col_name;
_group_by_col = group_by_col;
_map_func = map_func;
}
public GlobalMapStream(ViewStream base_stream, string sort_col_name, GlobalMap map_func) :
this(base_stream, sort_col_name, null, map_func) {
}
protected override void myOnFirstSubscriber() {
_base_stream.onChange += _handle_stream_update;
}
protected override void myOnLastSubscriber() {
_base_stream.onChange -= _handle_stream_update;
}
void _handle_stream_update(object dp_obj) {
DataPacket dp = dp_obj as DataPacket;
IDictionary<int, List<IBlueRow>> groups = !String.IsNullOrEmpty(_group_by_col) ?
BlueDataUtility.group_together(dp.newRows, new string[] { _group_by_col })
:
new Dictionary<int, List<IBlueRow>>() { { 0, dp.newRows.to_list() } };
BlueTable out_table = null;
foreach (var kv in groups) {
List<IBlueRow> group_rows = kv.Value;
group_rows.Sort((r1, r2) => BlueDataUtility.compare_rows(r2, r1, _sort_col_name));
uint i = 0;
foreach (IBlueRow r in group_rows) {
IBlueRow nr = _map_func(group_rows, i++);
out_table = out_table ?? new BlueTable(nr.schema);
out_table.addRow(nr);
}
}
// List<IBlueRow> rows = dp.newRows.to_ienum().ToList();
// rows.Sort((r1, r2) => BlueDataUtility.compare_rows(r1, r2, _sort_col_name));
// uint i = 0;
// BlueTable out_table = null;
// foreach (IBlueRow r in rows) {
// IBlueRow nr = _map_func(rows, i++);
// out_table = out_table ?? new BlueTable(nr.schema);
// out_table.addRow(nr);
// }
DataPacket dp_out = BlueDataUtility.build_dp_inc(out_table, myLastValue as DataPacket);
myFireEvent(dp_out);
}
}
}
@@ -119,13 +119,13 @@ namespace BCG {
protected override void myOnFirstSubscriber() {
myStream.onChange += myChangeHandler;
myStream.onChange += new DataStream.ChangeDelegate(myChangeHandler);
}
protected override void myOnLastSubscriber() {
myInit();
if (myStream != null)
myStream.onChange -= myChangeHandler;
myStream.onChange -= new DataStream.ChangeDelegate(myChangeHandler);
}
protected override void myOnTableClear() {
@@ -83,11 +83,10 @@ namespace BCG {
myMapper.onMapperChange += new MapperChangeDelegate(myHandleMapChange);
}
protected override void myOnFirstSubscriber() =>
myStream.onChange += myHandleData;
protected override void myOnFirstSubscriber() { myStream.onChange += new ChangeDelegate(myHandleData); }
protected override void myOnLastSubscriber() {
myStream.onChange -= myHandleData;
myStream.onChange -= new ChangeDelegate(myHandleData);
myRows = null;
myBaseRows = null;
myMap.Clear();
@@ -16,10 +16,10 @@ namespace BCG {
}
protected override void myOnFirstSubscriber() {
_stream.onChange += _onstream_change;
_stream.onChange += new ChangeDelegate(_onstream_change);
}
protected override void myOnLastSubscriber() {
_stream.onChange -= _onstream_change;
_stream.onChange -= new ChangeDelegate(_onstream_change);
}
private void _onstream_change(object o) {
@@ -45,4 +45,4 @@ namespace BCG {
}
}
}
}
@@ -1,8 +1,9 @@
using Google.Protobuf.WellKnownTypes;
using System;
using BCG.Utilities.General;
using BCG;
namespace bts.SilverPine {
namespace BCG {
// Keeps adding changing rows to the stream, hence preserving the history
// and creating a time series, for example this can be used to make bbo updates
// into a time series of prices/qty
@@ -16,10 +17,10 @@ namespace bts.SilverPine {
}
protected override void myOnFirstSubscriber() {
_stream.onChange += _onstream_change;
_stream.onChange += new ChangeDelegate(_onstream_change);
}
protected override void myOnLastSubscriber() {
_stream.onChange -= _onstream_change;
_stream.onChange -= new ChangeDelegate(_onstream_change);
}
@@ -40,6 +41,7 @@ namespace bts.SilverPine {
}
_table.addRows(added_rows);
myFireEvent(new DataPacket(_table, added_rows, new BlueTable(_table.schema)));
}
}
@@ -137,24 +137,10 @@ namespace bts {
HashSet<string> removed_cols = new HashSet<string>();
Dictionary<string, string> mapped_to_orig_map = new Dictionary<string, string>();
Dictionary<string, string> orig_to_mapped = new Dictionary<string, string>();
// by default every col will show up, so if we have the projection as (a:a1)
// it will convert a to a1,
// examples: if a schema has cols a b c
// project(parent_str, "a:aa ") -> aa b c
// project(parent_str, "a:aa !c") -> aa b
// project(parent_str, "a:aa !") -> aa
// project(parent_str, "a:aa b = (aa*aa)!") -> aa b
bool hide_all = false;
foreach (string p_tok in project_toks) {
if (p_tok.StartsWith("!")) {
if (p_tok.Length == 1) {
// if it is a "blanket "!"=> hide all cols except the one that
// are stated explicitly
hide_all = true;
} else {
string removed_col = p_tok.Substring(1);
removed_cols.Add(removed_col);
}
string removed_col = p_tok.Substring(1);
removed_cols.Add(removed_col);
} else if (p_tok.Contains(":")) {
string[] map_toks = p_tok.Split(":");
string orig_col = map_toks[0];
@@ -169,11 +155,12 @@ namespace bts {
}
}
}
// make the new schema
List<ColumnInfo> new_cols = new List<ColumnInfo>();
foreach (ColumnInfo ci in input_schema.columnInfo) {
if (ci.colName == "id") {
// if there's a hidden col, other columns will show by default, but if cols are being
// projected epxlicitely, than others wil be hidden
ColumnInfo nc = new ColumnInfo(ci.colName, new_cols.Count, ci.colType);
new_cols.Add(nc);
continue;
@@ -185,13 +172,12 @@ namespace bts {
ColumnInfo nc = new ColumnInfo(mapped_name, new_cols.Count, ci.colType);
new_cols.Add(nc);
} else {
if (hide_all)
continue;
//if (ci.colName == "id" || removed_cols.Count > 0) {
// unless columns are explicitely hidden, all columns show up
ColumnInfo nc = new ColumnInfo(ci.colName, new_cols.Count, ci.colType);
new_cols.Add(nc);
//}
if (ci.colName == "id" || removed_cols.Count > 0) {
// if there's a hidden col, other columns will show by default, but if cols are being
// projected epxlicitely, than others wil be hidden
ColumnInfo nc = new ColumnInfo(ci.colName, new_cols.Count, ci.colType);
new_cols.Add(nc);
}
}
}
IBlueTableSchema new_schema = new BlueTableSchema(input_schema.tableName, new_cols.ToArray());
@@ -54,12 +54,12 @@ namespace BCG {
protected override void myOnFirstSubscriber()
{
myVs.onChange += myHandleChange;
myVs.onChange += new BCG.DataStream.ChangeDelegate (myHandleChange);
}
protected override void myOnLastSubscriber()
{
myVs.onChange -= myHandleChange;
myVs.onChange -= new BCG.DataStream.ChangeDelegate (myHandleChange);;
}
internal void myHandleChange (object newValue)
@@ -1,54 +0,0 @@
namespace Bts.DataStream;
using BCG;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Linq;
using System.Threading;
public class SQLiteEnumerable : IAsyncEnumerable<IBlueRowCollection> {
readonly string location;
readonly string statement;
readonly int pageSize;
public SQLiteEnumerable(string location, string statement, int pageSize = 65536) {
this.location = location;
this.statement = statement;
this.pageSize = pageSize;
}
public async IAsyncEnumerator<IBlueRowCollection> GetAsyncEnumerator(CancellationToken cancellationToken = default) {
var dataTable = new DataTable();
await using var conn = new SQLiteConnection($"Data Source={location};Version=3");
await conn.OpenAsync(cancellationToken);
await using var cmd = new SQLiteCommand(statement, conn);
await using var reader = cmd.ExecuteReader();
var schema = await reader.GetColumnSchemaAsync(cancellationToken);
var columns = schema.OrderBy(c => c.ColumnOrdinal ?? int.MaxValue)
.Select((c, i) => new ColumnInfo(c.ColumnName, c.ColumnOrdinal ?? i, c.DataType))
.Append(new ColumnInfo("id", schema.Count, typeof(int)))
.ToArray();
var blueSchema = new BlueTableSchema("anon", columns);
BlueTable? table = null;
int rowId = 1;
while (await reader.ReadAsync(cancellationToken)) {
table ??= new BlueTable(blueSchema);
var rowVals = new object[blueSchema.columnInfo.Length];
if (reader.GetValues(rowVals) != rowVals.Length - 1) {
throw new InvalidOperationException("Sqlite reader value count for single row not equal to column count");
}
rowVals[^1] = rowId++;
table.addRow(new BlueRow(blueSchema, rowVals));
if (table.Count == pageSize) {
yield return table;
table = null;
}
}
if (table is not null) {
yield return table;
}
}
}
@@ -1,122 +0,0 @@
using System;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;
using System.Collections;
using BCG;
using System.Linq;
using System.Data.Entity;
using System.Collections.Generic;
using System.Data.SQLite;
namespace bts.SilverPine {
public static class SQLiteHelper {
public static string location = "C:\\Users\\m_tah\\development\\data\\";
public static string db_name = "stream_data.db";
public static DataTable execute_select_query(string connection_string, string query) {
// Create a new DataTable to store the results
DataTable dataTable = new DataTable();
// Create and open a SQLite connection using the provided connection string
using (SQLiteConnection connection = new SQLiteConnection(connection_string)) {
try {
connection.Open();
// Create a SQLite command with the provided query
using (SQLiteCommand command = new SQLiteCommand(query, connection)) {
// Use SQLiteDataAdapter to fill the DataTable
using (SQLiteDataAdapter adapter = new SQLiteDataAdapter(command)) {
adapter.Fill(dataTable);
}
}
} catch (Exception ex) {
Console.WriteLine("An error occurred: " + ex.Message);
}
}
// Return the populated DataTable
return dataTable;
}
public static List<Dictionary<string, object>> ExecuteBulkRead(string connectionString, string query) {
var result = new List<Dictionary<string, object>>();
using (var connection = new SQLiteConnection(connectionString)) {
connection.Open();
// Begin a transaction to optimize read speed
using (var transaction = connection.BeginTransaction())
using (var command = new SQLiteCommand(query, connection, transaction))
using (var reader = command.ExecuteReader()) {
while (reader.Read()) {
var row = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++) {
string columnName = reader.GetName(i);
object columnValue = reader.IsDBNull(i) ? null : reader.GetValue(i);
row[columnName] = columnValue;
}
result.Add(row);
}
// Commit the transaction
transaction.Commit();
}
}
return result;
}
public static List<Dictionary<string, object>> get_table(string connectionString, string query) {
var result = new List<Dictionary<string, object>>();
using (var connection = new SQLiteConnection(connectionString)) {
try {
connection.Open();
using (var command = new SQLiteCommand(query, connection))
using (var reader = command.ExecuteReader()) {
while (reader.Read()) {
var row = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++) {
string columnName = reader.GetName(i);
object columnValue = reader.IsDBNull(i) ? null : reader.GetValue(i);
row[columnName] = columnValue;
}
result.Add(row);
}
}
} catch (Exception ex) {
Console.WriteLine("An error occurred: " + ex.Message);
}
}
return result;
}
public static IEnumerable<Dictionary<string, object>> get_table_2(string connectionString, string query) {
using (var connection = new SQLiteConnection(connectionString)) {
connection.Open();
using (var command = new SQLiteCommand(query, connection))
using (var reader = command.ExecuteReader()) {
while (reader.Read()) {
var row = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++) {
string columnName = reader.GetName(i);
object columnValue = reader.IsDBNull(i) ? null : reader.GetValue(i);
row[columnName] = columnValue;
}
yield return row;
}
}
}
}
}
}
@@ -1,73 +0,0 @@
namespace bts.SilverPine {
using System;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;
using System.Collections;
using BCG;
[DataStreamUserRespresentation("SQLite")]
public class SQLiteStream : ViewStream {
private readonly string _connection_string, _query;
private Stopwatch _stopwatch = new Stopwatch();
private SQLiteStream(string connection_string, string query, bool noop) {
_connection_string = connection_string;
_query = query;
}
public SQLiteStream(string db_name, string query)
:
this($"Data Source={SQLiteHelper.location}{db_name};Version=3", query, true) { }
public SQLiteStream(string query)
:
this(SQLiteHelper.db_name, query) {
}
private void _read_from_sqlite_and_fire() {
_stopwatch.Start();
DataTable dt = SQLiteHelper.execute_select_query(_connection_string, _query);
_stopwatch.Stop();
Log.Gen.info($"SQLiteStream.ExecuteSelectQuery time to read db: {_stopwatch.ElapsedMilliseconds} msecs");
_stopwatch.Restart();
#region perf measures
// SQLiteHelper.get_table(_connection_string, _query);
// _stopwatch.Stop();
// Log.Gen.info($"SQLiteStream.get_table time to read db: {_stopwatch.ElapsedMilliseconds} msecs");
// _stopwatch.Restart();
// SQLiteHelper.ExecuteBulkRead(_connection_string, _query);
// _stopwatch.Stop();
// Log.Gen.info($"SQLiteStream.ExecuteBulkRead time to read db: {_stopwatch.ElapsedMilliseconds} msecs");
// _stopwatch.Restart();
// SQLiteHelper.get_table_2(_connection_string, _query);
// _stopwatch.Stop();
// Log.Gen.info($"SQLiteStream.get_table_2 time to read db: {_stopwatch.ElapsedMilliseconds} msecs");
// _stopwatch.Restart();
#endregion
IBlueRowCollection rows = BCG.BlueDataUtility.toIBlueRowCollection(dt);
//IBlueRowCollection rows = new DataTableWrapperTable(dt);
_stopwatch.Stop();
Log.Gen.info($"SQLiteStream._read_from_sqlite_and_fire time to load into IBlueRowCollection: {_stopwatch.ElapsedMilliseconds} msecs");
DataPacket dp = BlueDataUtility.build_dp_inc(rows, myLastValue as DataPacket);
myFireEvent(dp);
}
protected override void myOnFirstSubscriber() {
_read_from_sqlite_and_fire();
}
protected override void myOnLastSubscriber() {
// this value will be cleared by the base class
// but in this particular stream this behaviour
// is not usefull since any new subscribers
// would force the query to be recreated
//myLastDP = myLastValue;
}
}
}
@@ -3,15 +3,12 @@ using System.Collections.Generic;
using System.Text;
using System.IO;
using BCG.Utilities;
using System.Diagnostics;
using Microsoft.Data.Analysis;
using Parquet;
using Parquet.Data;
namespace BCG {
namespace BCG
{
[DataStreamUserRespresentation("CSVSaver")]
public class CSVSaverStream : ViewStream, ISideEffectStream {
public class CSVSaverStream : ViewStream, ISideEffectStream
{
private IBlueTableSchema myResultSchema = new BlueTableSchema("CSVResult", new ColumnInfo("id", 0, typeof(int)),
new ColumnInfo("fileName", 1, typeof(string)),
new ColumnInfo("nWrites", 2, typeof(int)),
@@ -23,9 +20,11 @@ namespace BCG {
private int myNWrites = 0, myNMaxWrites = Int32.MaxValue;
public CSVSaverStream(ViewStream vs, string fullyQualifiedFileName)
: this(vs, fullyQualifiedFileName, true, Int32.MaxValue, false) { }
: this(vs, fullyQualifiedFileName, true, Int32.MaxValue, false)
{ }
public CSVSaverStream(ViewStream vs, string fullyQualifiedFileName, bool overwrite, int nMaxWrites, bool fireResultSnapshot) {
public CSVSaverStream(ViewStream vs, string fullyQualifiedFileName, bool overwrite, int nMaxWrites, bool fireResultSnapshot)
{
myStream = vs;
myFullyQualifiedFileName = fullyQualifiedFileName;
myOverwrite = overwrite;
@@ -33,20 +32,22 @@ namespace BCG {
myFireResultSnapshot = fireResultSnapshot;
}
protected override void myOnFirstSubscriber() =>
myStream.onChange += myHandleChanges;
protected override void myOnFirstSubscriber() { myStream.onChange += new ChangeDelegate(myHandleChanges); }
protected override void myOnLastSubscriber() =>
myStream.onChange -= myHandleChanges;
protected override void myOnLastSubscriber() { myStream.onChange -= new ChangeDelegate(myHandleChanges); }
private void myHandleChanges(object newValue) {
private void myHandleChanges(object newValue)
{
IBlueRowCollection totalState = (newValue as DataPacket).newRows;
if (totalState.Count > 0 && myNWrites < myNMaxWrites) {
if (totalState.Count > 0 && myNWrites < myNMaxWrites)
{
myNWrites++;
int i = 0;
StreamWriter writer = new StreamWriter(new FileStream(myGetNewFileName(), FileMode.Create, FileAccess.Write));
foreach (IBlueRow r in totalState) {
if (i++ == 0) {
foreach (IBlueRow r in totalState)
{
if (i++ == 0)
{
string header = String.Empty;
foreach (string col in r.schema.columnNames)
if (col != "id")
@@ -58,17 +59,20 @@ namespace BCG {
writer.Flush();
}
writer.Close();
if (myFireResultSnapshot) {
if (myFireResultSnapshot)
{
IBlueRow nr = new BlueRow(myResultSchema, 0, myFullyQualifiedFileName, myNWrites, totalState.Count);
BlueTable nRows = new BlueTable(myResultSchema);
nRows.addRow(nr);
myFireEvent(new DataPacket(nRows, nRows, new BlueTable(myLastValue == null ? new BlueTable(myResultSchema) : (myLastValue as DataPacket).newRows)));
} else
}
else
myFireEvent(newValue);
}
}
private string myGetNewFileName() {
private string myGetNewFileName()
{
string[] tags = myFullyQualifiedFileName.Split('.');
if (myOverwrite)
return tags[0] + ".csv";
@@ -76,11 +80,14 @@ namespace BCG {
return tags[0] + "_" + myFormateDateTime(DateTime.Now) + ".csv";
}
private static string myGetCSVRow(IBlueRow r) {
private static string myGetCSVRow(IBlueRow r)
{
string rv = String.Empty;
int i = 0;
foreach (string col in r.schema.columnNames) {
if (col != "id") {
foreach (string col in r.schema.columnNames)
{
if (col != "id")
{
string colText = String.Empty;
if (r[col] != null && r[col] != DBNull.Value)
colText = r[col].ToString();
@@ -92,7 +99,8 @@ namespace BCG {
return rv;
}
private string myFormateDateTime(DateTime dt) {
private string myFormateDateTime(DateTime dt)
{
return
string.Format("{0}-{1}-{2}-{3}-{4}-{5}-{6}",
dt.Year.ToString("0000"),
@@ -106,49 +114,52 @@ namespace BCG {
}
[DataStreamUserRespresentation("CSVReader")]
public class CSVReaderStream : ViewStream {
private readonly string _file_address;
Stopwatch _stopwatch = new Stopwatch();
public CSVReaderStream(string fileAddress) {
_file_address = fileAddress;
public class CSVReaderStream : ViewStream
{
private IBlueRowCollection myRows;
public CSVReaderStream(string fileAddress)
{
myRows = BlueDataUtility.createRowsFromCSVFileWithoutTypes(fileAddress);
}
protected override void myOnFirstSubscriber() {
_stopwatch.Start();
DataFrame df = DataFrame.LoadCsv(_file_address);
_stopwatch.Stop();
bts.Log.Gen.info($"CSVReaderStream.myOnFirstSubscriber stream csv load col_count: {df.Columns.Count} rows, time: {_stopwatch.ElapsedMilliseconds} msecs");
_stopwatch.Start();
IBlueRowCollection rows = BlueDataUtility.createRowsFromCSVFileWithoutTypes(_file_address);
_stopwatch.Stop();
bts.Log.Gen.info($"CSVReaderStream.myOnFirstSubscriber stream csv load count: {rows.Count} rows, time: {_stopwatch.ElapsedMilliseconds} msecs");
DataPacket dp_out = BlueDataUtility.build_dp_inc(rows, myLastValue as DataPacket);
myFireEvent(dp_out);
protected override void myOnFirstSubscriber()
{
myFireEvent(new DataPacket(myRows, myRows, new BlueTable(myRows.schema)));
}
}
[DataStreamUserRespresentation("CSVReaderStreamMapper")]
public class CSVReaderStreamMapperStream : ViewStream {
public CSVReaderStreamMapperStream(ViewStream stream, string output_schema) {
[DataStreamUserRespresentation ("CSVReaderStreamMapper")]
public class CSVReaderStreamMapperStream : ViewStream
{
public CSVReaderStreamMapperStream(ViewStream stream, string output_schema)
{
mySetRealSource(new MapStream(stream, new CSVReaderStreamMapper(output_schema)));
}
}
public class CSVReaderStreamMapper : IStreamMapper {
public class CSVReaderStreamMapper : IStreamMapper
{
private IBlueTableSchema mySchema;
private readonly string[] myOutputSchemaStringArray;
public CSVReaderStreamMapper(string outputSchema) {
public CSVReaderStreamMapper(string outputSchema)
{
myOutputSchemaStringArray = outputSchema.Split(' ');
}
public IBlueTableSchema getOutputSchema(IBlueTableSchema inputSchema) {
if (mySchema == null) {
public IBlueTableSchema getOutputSchema(IBlueTableSchema inputSchema)
{
if (mySchema == null)
{
ColumnInfo[] ci = inputSchema.columnInfo;
foreach (string col in myOutputSchemaStringArray) {
foreach (string col in myOutputSchemaStringArray)
{
string colName = col.Substring(0, col.IndexOf('\\')).ToLower();
for (int i = 0; i < ci.Length; i++) {
if (ci[i].colName.ToLower().Equals(colName)) {
for (int i = 0; i < ci.Length; i++)
{
if (ci[i].colName.ToLower().Equals(colName))
{
Type t = myGetType(col.Substring(col.IndexOf('\\') + 1));
ci[i] = new ColumnInfo(ci[i].colName, i, t);
break;
@@ -160,52 +171,74 @@ namespace BCG {
return mySchema;
}
public IBlueRow map(IBlueRow row) {
public IBlueRow map(IBlueRow row)
{
object[] vals = new object[row.schema.columnInfo.Length];
row.Values.CopyTo(vals, 0);
for (int i = 0; i < mySchema.columnInfo.Length; i++) {
for (int i = 0; i < mySchema.columnInfo.Length; i++)
{
Type t = mySchema.columnInfo[i].colType;
try {
try
{
vals[i] = System.Convert.ChangeType(vals[i], mySchema.columnInfo[i].colType, System.Globalization.CultureInfo.InvariantCulture);
} catch {
if (t.Equals(typeof(Int16))) {
}
catch
{
if (t.Equals(typeof(Int16)))
{
Int16 result;
if (Int16.TryParse((string)vals[i], out result)) {
if (Int16.TryParse((string)vals[i], out result))
{
vals[i] = result;
continue;
}
double r2;
if (Double.TryParse((string)vals[i], out r2)) {
try {
if (Double.TryParse((string)vals[i], out r2))
{
try
{
vals[i] = (Int16)r2;
continue;
} catch { }
}
catch { }
}
} else if (t.Equals(typeof(Int32))) {
}
else if (t.Equals(typeof(Int32)))
{
Int32 result;
if (Int32.TryParse((string)vals[i], out result)) {
if (Int32.TryParse((string)vals[i], out result))
{
vals[i] = result;
continue;
}
double r2;
if (Double.TryParse((string)vals[i], out r2)) {
try {
if (Double.TryParse((string)vals[i], out r2))
{
try
{
vals[i] = (Int32)r2;
continue;
} catch { }
}
catch { }
}
} else if (t.Equals(typeof(Int64))) {
}
else if (t.Equals(typeof(Int64)))
{
Int64 result;
if (Int64.TryParse((string)vals[i], out result)) {
if (Int64.TryParse((string)vals[i], out result))
{
vals[i] = result;
continue;
}
double r2;
if (Double.TryParse((string)vals[i], out r2)) {
try {
if (Double.TryParse((string)vals[i], out r2))
{
try
{
vals[i] = (Int64)r2;
continue;
} catch { }
}
catch { }
}
}
vals[i] = DBNull.Value;
@@ -214,7 +247,8 @@ namespace BCG {
return new BlueRow(mySchema, vals);
}
private Type myGetType(string type) {
private Type myGetType(string type)
{
type = type.ToLower();
if (type.Contains("int"))
return typeof(int);
@@ -1,41 +1,31 @@
using System;
using System.Collections;
using System.Reflection;
using BCG.Utilities;
namespace BCG {
// if a table needs to be fired, it can be wrapped around this
public class BlueTableStream : ViewStream {
private IBlueRowCollection _rows;
public BlueTableStream(IBlueRowCollection rows) {
_rows = rows;
namespace BCG
{
[DataStreamUserRespresentation (false)]
public class BlueRowCollectionStaticStream : ViewStream
{
public BlueRowCollectionStaticStream () {}
public BlueRowCollectionStaticStream (IBlueRowCollection rows) {loadCollection (rows);}
public void loadCollection (IBlueRowCollection rows)
{
myFireEvent (new DataPacket (rows, rows, myLastValue != null ?
new BlueTable((myLastValue as DataPacket).newRows) : new BlueTable (rows.schema)));
}
protected override void myOnFirstSubscriber() {
var dp_out = BlueDataUtility.build_dp_inc(_rows, myLastValue as DataPacket);
myFireEvent(dp_out);
}
}
[DataStreamUserRespresentation(false)]
public class BlueRowCollectionStaticStream : ViewStream {
public BlueRowCollectionStaticStream() { }
public BlueRowCollectionStaticStream(IBlueRowCollection rows) { loadCollection(rows); }
public void loadCollection(IBlueRowCollection rows) {
myFireEvent(new DataPacket(rows, rows, myLastValue != null ?
new BlueTable((myLastValue as DataPacket).newRows) : new BlueTable(rows.schema)));
}
public void crush_with_single_row(IBlueRow r) {
public void crush_with_single_row(IBlueRow r)
{
BlueTable t = new BlueTable(r.schema);
t.addRow(r);
loadCollection(t);
}
public void loadPacket(DataPacket dp) { myFireEvent(dp); }
public void loadPacket (DataPacket dp) {myFireEvent (dp);}
/// <summary>
/// Will work with streams that take ViewStream as first argument ex project, filter, distinct etc
@@ -45,16 +35,17 @@ namespace BCG {
/// <param name="streamType"></param>
/// <param name="args"></param>
/// <returns></returns>
public static IBlueRowCollection statelessOp(IBlueRowCollection rows, Type streamType, params object[] args) {
ArrayList totArgs = new ArrayList(args);
BlueRowCollectionStaticStream v1 = new BlueRowCollectionStaticStream();
totArgs.Insert(0, v1);
ViewStream retVal = Activator.CreateInstance(streamType, totArgs.ToArray()) as ViewStream;
v1.loadCollection(rows);
public static IBlueRowCollection statelessOp (IBlueRowCollection rows, Type streamType, params object[] args)
{
ArrayList totArgs = new ArrayList (args);
BlueRowCollectionStaticStream v1 = new BlueRowCollectionStaticStream ();
totArgs.Insert (0, v1);
ViewStream retVal = Activator.CreateInstance (streamType, totArgs.ToArray()) as ViewStream;
v1.loadCollection (rows);
return retVal.rows;
}
}
}
@@ -35,14 +35,14 @@ namespace BCG
#region ViewStream
protected override void myOnFirstSubscriber()
{
myStream.onChange += myStreamChange;
myStream.onChange +=new ChangeDelegate(myStreamChange);
myVsd.addWorker(this);
}
protected override void myOnLastSubscriber()
{
myVsd.removeWorker(this);
myStream.onChange -= myStreamChange;
myStream.onChange -= new ChangeDelegate(myStreamChange);
}
#endregion
@@ -28,7 +28,7 @@ namespace BCG
protected override void myOnFirstSubscriber()
{
myParentStream.onChange += myParentStreamChangeHandler;
myParentStream.onChange += new ChangeDelegate(myParentStreamChangeHandler);
myVSD.addWorker(this);
}
@@ -36,7 +36,7 @@ namespace BCG
protected override void myOnLastSubscriber()
{
myParentStream.onChange -= myParentStreamChangeHandler;
myParentStream.onChange -= new ChangeDelegate(myParentStreamChangeHandler);
myVSD.removeWorker(this);
}
@@ -53,11 +53,11 @@ namespace BCG
if (r.is_subscription)
{
_current_source_subscription = r.subscription_id;
_source_stream.onChange += _source_stream_onChange;
_source_stream.onChange += new ChangeDelegate(_source_stream_onChange);
}
else
{
_source_stream.onChange -= _source_stream_onChange;
_source_stream.onChange -= new ChangeDelegate(_source_stream_onChange);
}
}
}
@@ -80,7 +80,7 @@ namespace BCG {
public IBlueRow map(IBlueRow row) {
MutableBlueRow rv = new MutableBlueRow(getOutputSchema(row.schema), row);
rv.setValue(myConversionColName, mapDateTime(row.get_datetime(myConversionColName), myConversion));
rv.setValue(myConversionColName, mapDateTime(row[myConversionColName], myConversion));
return rv;
//return BlueDataUtility.getNewReplacedRow(row, mapDateTime(row[myConversionColName], myConversion), myConversionColName);
}
@@ -1,38 +0,0 @@
namespace bts.SilverPine {
using bts;
using BCG;
using System;
public class DateTimeExpanstionStream : ViewStream {
public DateTimeExpanstionStream(ViewStream parent_stream, string inp_col) {
Func<IBlueTableSchema, IBlueTableSchema> get_schema = (s) => {
IBlueTableSchema rv = s.add_column(System.TypeCode.DateTime, $"{inp_col}_date");
rv = rv.add_column(System.TypeCode.String, $"{inp_col}_day");
rv = rv.add_column(System.TypeCode.Int32, $"{inp_col}_day_of_month");
rv = rv.add_column(System.TypeCode.Int32, $"{inp_col}_month");
rv = rv.add_column(System.TypeCode.Int32, $"{inp_col}_hour");
rv = rv.add_column(System.TypeCode.Int32, $"{inp_col}_min");
rv = rv.add_column(System.TypeCode.Int32, $"{inp_col}_seconds_of_day");
return rv;
};
ViewStream rs = new MapStream(parent_stream,
s => get_schema(s),
r => {
DateTime dt = r.get_datetime(inp_col);
IBlueTableSchema s = get_schema(r.schema);
MutableBlueRow rv = new MutableBlueRow(s, r);
rv.setValue($"{inp_col}_date", dt.Date);
rv.setValue($"{inp_col}_day", dt.DayOfWeek.ToString());
rv.setValue($"{inp_col}_day_of_month", dt.Day);
rv.setValue($"{inp_col}_month", dt.Date.Month);
rv.setValue($"{inp_col}_hour", dt.Hour);
rv.setValue($"{inp_col}_min", dt.Minute);
rv.setValue($"{inp_col}_seconds_of_day", (dt - dt.Date).TotalSeconds);
return rv;
});
mySetRealSource(rs);
}
}
}
@@ -24,7 +24,7 @@ namespace BCG
protected override void myOnFirstSubscriber()
{
myKeyToTimeToValue = new Dictionary<string, SortedList<DateTime, double>>();
myToAverage.onChange += myToAverage_onChange;
myToAverage.onChange += new ChangeDelegate(myToAverage_onChange);
}
@@ -1,124 +0,0 @@
namespace bts.SilverPine {
using BCG;
using bts;
using bts.collections;
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
// Given 2 filters, and 2 columns, finds the different in the value of the 2 columns from the 2 rows
// so:
// f1(base_stream.rows)[col1] - f1(base_stream.rows)[col2]
[DataStreamUserRespresentation("ColDiff")]
public class ColumnDifferenceStream : ViewStream {
private readonly ViewStream _base_stream;
private readonly FilterStream.OnFilter _f1, _f2;
private readonly string _c1, _c2;
public ColumnDifferenceStream(ViewStream base_stream, FilterStream.OnFilter f1, FilterStream.OnFilter f2, string col1, string col2) {
_base_stream = base_stream;
_f1 = f1;
_f2 = f2;
_c1 = col1;
_c2 = col2;
}
public ColumnDifferenceStream(ViewStream base_stream, string f1, string f2, string col1, string col2) {
FilterStream.OnFilter f1_del = r => {
BooleanExpressionFilter rv = new BooleanExpressionFilter(f1);
return rv.filter(r);
};
FilterStream.OnFilter f2_del = r => {
BooleanExpressionFilter rv = new BooleanExpressionFilter(f2);
return rv.filter(r);
};
ViewStream rs = new ColumnDifferenceStream(base_stream, f1_del, f2_del, col1, col2);
mySetRealSource(rs);
}
// for each row, does a row[new_col_name] = row[col1] - rows[row_ffset][col2]
// we should generlize this for any math operation
public ColumnDifferenceStream(ViewStream parent_stream, string sort_col_name, int row_offset, string col1, string col2, string diff_col_name, double optional_perc_diff_filter = 0.0) {
// use GlobalMapStream
string diff_col_perc_name = $"{diff_col_name}_percentage";
System.Func<System.Collections.Generic.List<BCG.IBlueRow>, uint, BCG.IBlueRow> g_map_func = (rows, idx) => {
int minuend_idx = Convert.ToInt32(idx);
var inp_schema = rows[0].schema;
var out_schema = inp_schema.add_column(TypeCode.Double, diff_col_name);
out_schema = out_schema.add_column(TypeCode.Double, diff_col_perc_name);
// minuend - subtrahend
IBlueRow minuend_row = rows.ElementAt(minuend_idx);
MutableBlueRow rv = new MutableBlueRow(out_schema, minuend_row);
int subtrahend_index = minuend_idx + row_offset;
double diff_val = Double.NaN, diff_val_perc = Double.NaN;
if (subtrahend_index >= 0) {
try {
IBlueRow subtrahend_row = rows.ElementAt(subtrahend_index);
diff_val = minuend_row.get<double>(col1) - subtrahend_row.get<double>(col2);
diff_val_perc = 100.0 * diff_val / subtrahend_row.get<double>(col1);
} catch (Exception ex) {
Log.assert(false, ex.Message);
}
}
rv.setValue(diff_col_name, diff_val);
rv.setValue(diff_col_perc_name, diff_val_perc);
return rv;
};
ViewStream rs = new GlobalMapStream(parent_stream, sort_col_name, g_map_func);
if (optional_perc_diff_filter != 0) {
rs = new FilterStream(rs, r => {
double diff_val_perc = r.get<double>(diff_col_perc_name);
double abs_diff_val_perc = Math.Abs(diff_val_perc);
return abs_diff_val_perc >= optional_perc_diff_filter;
});
}
mySetRealSource(rs);
}
protected override void myOnFirstSubscriber() {
_base_stream.onChange += _handle_base_stream_update;
}
protected override void myOnLastSubscriber() {
_base_stream.onChange -= _handle_base_stream_update;
}
private void _handle_base_stream_update(object dp_obj) {
// could have been done with filter and cartesian prod, and then math
DataPacket dp = dp_obj as DataPacket;
List<IBlueRow> rows = dp.newRows.to_list();
var f1_rows = rows.Where(r => _f1(r));
//Log.assert(f1_rows.Count() == 1);
var f2_rows = rows.Where(r => _f2(r));
//Log.assert(f2_rows.Count() == 1);
if (f1_rows != null && f1_rows.Count() > 0 && f2_rows != null && f2_rows.Count() > 0) {
IBlueRow f1_r = f1_rows.ElementAt(0);
IBlueRow f2_r = f2_rows.ElementAt(0);
double diff = f1_r.get<double>(_c1) - f2_r.get<double>(_c2);
IBlueTableSchema out_schema = f1_r.schema.add_columns(Tuple.Create(typeof(double), "diff"));
BlueTable out_table = new BlueTable(out_schema);
MutableBlueRow out_row = new MutableBlueRow(out_schema, f1_r);
out_row.setValue("diff", diff);
out_table.addRow(out_row);
DataPacket dp_out = BlueDataUtility.build_dp(out_table, myLastValue as DataPacket);
myFireEvent(dp_out);
} else {
IBlueRow f1_r = rows.ElementAt(0);
IBlueRow f2_r = rows.ElementAt(0);
double diff = Double.NaN;
IBlueTableSchema out_schema = f1_r.schema.add_columns(Tuple.Create(typeof(double), "diff"));
BlueTable out_table = new BlueTable(out_schema);
MutableBlueRow out_row = new MutableBlueRow(out_schema, f1_r);
out_row.setValue("diff", diff);
out_table.addRow(out_row);
DataPacket dp_out = BlueDataUtility.build_dp(out_table, myLastValue as DataPacket);
myFireEvent(dp_out);
}
}
}
}
@@ -1,51 +0,0 @@
namespace bts.SilverPine {
using BCG;
using bts;
using System.Collections.Generic;
using System.Linq;
// Given a sort order, an optional group by col, it observes the values of a column
// within that group (or the whole table, if grouping not specified) and returns all rows
// where the value changes, ie row[current][col] != row[current-1][col]
// TODO: a more general way to express a filter where row[current][col] != row[previous][col],
// or even expand it to row[current][col_a] - row[previous][col_b] < 0.5
[DataStreamUserRespresentation("ColEvol")]
public class ColumnEvolutionStream : ViewStream {
private readonly ViewStream _base_stream;
private readonly string _sort_col;
private readonly string _evol_col;
public ColumnEvolutionStream(ViewStream base_stream, string sort_col, string evolution_col) {
_base_stream = base_stream;
_sort_col = sort_col;
_evol_col = evolution_col;
}
protected override void myOnFirstSubscriber() {
_base_stream.onChange += _handle_base_stream_update;
}
protected override void myOnLastSubscriber() {
base.myOnLastSubscriber();
}
private void _handle_base_stream_update(object dp_obj) {
DataPacket dp = dp_obj as DataPacket;
List<IBlueRow> rows = dp.newRows.to_list();
rows.Sort((r1, r2) => BlueDataUtility.compare_rows(r2, r1, _sort_col));
BlueTable rv = new BlueTable(dp.schema);
IBlueRow prev_row = rows.ElementAt(0);
foreach (IBlueRow r in rows) {
var cr = BlueDataUtility.compare_rows(r, prev_row, _evol_col);
if (cr != 0) {
rv.addRow(r);
}
prev_row = r;
}
DataPacket dp_out = BlueDataUtility.build_dp(rv, myLastValue as DataPacket);
myFireEvent(dp_out);
}
}
}
@@ -12,10 +12,10 @@ namespace BCG {
mySrc = src;
}
protected override void myOnFirstSubscriber() {
mySrc.onChange += mySrc_onChange;
mySrc.onChange += new ChangeDelegate(mySrc_onChange);
}
protected override void myOnLastSubscriber() {
mySrc.onChange -= mySrc_onChange;
mySrc.onChange -= new ChangeDelegate(mySrc_onChange);
}
private void mySrc_onChange(object newValue) {
DataPacket dp = (DataPacket)newValue;
@@ -28,14 +28,14 @@ namespace BCG
protected override void myOnFirstSubscriber()
{
myLeftStream.onChange += myHandleLeftChanges;
myRightstream.onChange += myHandleRightChanges;
myLeftStream.onChange += new ChangeDelegate(myHandleLeftChanges);
myRightstream.onChange += new ChangeDelegate(myHandleRightChanges);
}
protected override void myOnLastSubscriber()
{
myLeftStream.onChange -= myHandleLeftChanges;
myRightstream.onChange -= myHandleRightChanges;
myLeftStream.onChange -= new ChangeDelegate(myHandleLeftChanges);
myRightstream.onChange -= new ChangeDelegate(myHandleRightChanges);
}
private void myHandleLeftChanges (object newValue)
@@ -222,7 +222,7 @@ namespace BCG
pj = new ProjectStream(pj, "!");
myStreamIndex.Add(myMovingIndex, new Pair<ViewStream, ViewStream>(vs, pj));
if (mySubscriptionActive)
pj.onChange += myHandleStreamChanges;
pj.onChange += new ChangeDelegate(myHandleStreamChanges);
}
public void removeStream(ViewStream vs)
@@ -235,7 +235,7 @@ namespace BCG
index = p.Key;
if (mySubscriptionActive)
{
p.Value.second.onChange -= myHandleStreamChanges;
p.Value.second.onChange -= new ChangeDelegate(myHandleStreamChanges);
if (myTable != null)
{
IBlueRowCollection delRows = myTable.removeTable(p.Key);
@@ -254,14 +254,14 @@ namespace BCG
{
mySubscriptionActive = true;
foreach (KeyValuePair<int, Pair<ViewStream, ViewStream>> p in myStreamIndex)
p.Value.second.onChange += myHandleStreamChanges;
p.Value.second.onChange += new ChangeDelegate(myHandleStreamChanges);
}
protected override void myOnLastSubscriber()
{
mySubscriptionActive = false;
foreach (KeyValuePair<int, Pair<ViewStream, ViewStream>> p in myStreamIndex)
p.Value.second.onChange -= myHandleStreamChanges;
p.Value.second.onChange -= new ChangeDelegate(myHandleStreamChanges);
if (myTable != null)
myTable.clear();
}
@@ -14,11 +14,11 @@ namespace BCG {
}
protected override void myOnFirstSubscriber()
{
mySrc.onChange += mySrc_onChange;
mySrc.onChange += new ChangeDelegate(mySrc_onChange);
}
protected override void myOnLastSubscriber ()
{
mySrc.onChange -= mySrc_onChange;
mySrc.onChange -= new ChangeDelegate (mySrc_onChange);
}
private void mySrc_onChange (object newValue) {
DataPacket dp = (DataPacket)newValue;
@@ -21,15 +21,15 @@ namespace BCG
{
myLeftOp = new UnionOperand (true, this);
myRightOp = new UnionOperand (false, this);
myLeftVs.onChange += myLeftOp.myChangeHandler;
myRightVs.onChange += myRightOp.myChangeHandler;
myLeftVs.onChange += new DataStream.ChangeDelegate (myLeftOp.myChangeHandler);
myRightVs.onChange += new DataStream.ChangeDelegate (myRightOp.myChangeHandler);
}
protected override void myOnLastSubscriber ()
{
myInit ();
myLeftVs.onChange -= myLeftOp.myChangeHandler;
myRightVs.onChange -= myRightOp.myChangeHandler;
myLeftVs.onChange -= new DataStream.ChangeDelegate (myLeftOp.myChangeHandler);
myRightVs.onChange -= new DataStream.ChangeDelegate (myRightOp.myChangeHandler);
}
public void startSession ()
@@ -116,4 +116,4 @@ namespace BCG
receiveStream(dp, isLeft);
}
}
}
}
@@ -14,11 +14,11 @@ namespace BCG {
protected override void myOnFirstSubscriber() {
_vs_publisher = new ViewPublisher(_name, _broker, _main_stream);
_main_stream.onChange += _handle_update;
_main_stream.onChange += new DataStream.ChangeDelegate(_handle_update);
}
protected override void myOnLastSubscriber() {
_main_stream.onChange -= _handle_update;
_main_stream.onChange -= new DataStream.ChangeDelegate(_handle_update);
_vs_publisher.Dispose();
}
@@ -28,4 +28,4 @@ namespace BCG {
}
}
}
@@ -20,11 +20,11 @@ namespace BCG {
public ViewPublisher(string name, IPubTableBroker broker, ViewStream vs) {
_stream = String.IsNullOrEmpty(name) ? vs : new ChangeTableNameStream(vs, name);
_broker = broker;
_stream.onChange += _handle_update;
_stream.onChange += new DataStream.ChangeDelegate(_handle_update);
}
public void Dispose() {
_stream.onChange -= _handle_update;
_stream.onChange -= new DataStream.ChangeDelegate(_handle_update);
}
private void _handle_update(object o) {
@@ -1,73 +0,0 @@
namespace Bts.DataStream;
using BCG;
using bts.api.core;
using Bts.DataStreamCore;
using System;
using System.Collections;
using System.Collections.Generic;
public class TableUpdateDataPacket<T> : IDataPacket<T> where T : IBlueRow {
readonly TableUpdate<T, int> table;
readonly IBlueTableSchema schema;
public TableUpdateDataPacket(TableUpdate<T, int> table, IBlueTableSchema schema) {
this.table = table;
this.schema = schema;
}
public IBlueRowCollection<T> newRows {
get {
var rv = new BlueTableImmutable<T>(schema);
return rv;
}
}
public IBlueRowCollection<T> addedRows => throw new NotImplementedException();
public IBlueRowCollection<T> deletedRows => throw new NotImplementedException();
class MyRowCollection : IBlueRowCollection<T> {
readonly TableUpdate<T, int> table;
readonly IEnumerable<T> items;
Lazy<SortedList<int, T>> itemList;
public MyRowCollection(IEnumerable<T> items, IBlueTableSchema schema) {
this.items = items;
this.schema = schema;
itemList = new(() => {
var rv = new SortedList<int, T>();
foreach (var item in this.items) {
rv.Add(item.Id(), item);
}
return rv;
});
}
public int Count => itemList.Value.Count;
public bool IsSynchronized => false;
public object SyncRoot => this;
public T this[int id] => itemList.Value[id];
public IBlueTableSchema schema { get; }
public bool containsID(int id) =>
itemList.Value.ContainsKey(id);
public void CopyTo(Array array, int index) {
}
public IEnumerator<T> GetEnumerator() {
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator() {
throw new NotImplementedException();
}
}
}
@@ -1,127 +0,0 @@
namespace Bts.DataStreamCore;
using BCG;
using bts.utils;
using mbts.utils;
using Spark.Core;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class BlueColumnTable : IBlueRowCollection {
readonly Variant[][] columns;
readonly List<int> rowIds;
readonly int idColIndex;
public BlueColumnTable(IBlueTableSchema schema, int capacity = 4) {
ExceptionAssert.Argument.GreaterThanEqualTo(capacity, 0);
rowIds = new(capacity);
columns = new Variant[schema.columnInfo.Length][];
if (columns.Length == 0) {
throw new ArgumentException("Schema contains no columns", nameof(schema));
}
if (!schema.columnInfo.Select(c => c.colName).TryFindIndex("id", out idColIndex)) {
throw new ArgumentException("Schema contains no 'id' column", nameof(schema));
}
this.schema = schema;
for (int i = 0; i < columns.Length; i++) {
columns[schema.columnInfo[i].colNo] = new Variant[capacity];
}
}
public int Count => rowIds.Count;
public IBlueTableSchema schema { get; }
public IBlueRow this[int id] {
get {
var idx = rowIds.BinarySearch(id);
if (idx < 0) {
throw new KeyNotFoundException($"No row with id {id}");
}
return new MyRow(this, idx);
}
}
public void Add(Variant[] values) {
var id = values[idColIndex].VInt32;
var idx = rowIds.BinarySearch(id);
if (idx >= 0) {
throw new ArgumentException($"Row with id {id} already exists.", nameof(values));
}
idx = ~idx;
for (int i = 0; i < columns.Length; i++) {
int len = rowIds.Count;
ArrayHelper.Insert(ref columns[i], idx, values[i], ref len);
}
rowIds.Insert(idx, id);
}
public void AddOrUpdate(Variant[] values) {
var id = values[idColIndex].VInt32;
var idx = rowIds.BinarySearch(id);
if (idx >= 0) {
rowIds[idx] = id;
for (int i = 0; i < columns.Length; i++) {
columns[idx][i] = values[i];
}
return;
}
idx = ~idx;
int len;
for (int i = 0; i < columns.Length; i++) {
len = rowIds.Count;
ArrayHelper.Insert(ref columns[i], idx, values[i], ref len);
}
rowIds.Insert(idx, id);
}
public void Clear() =>
rowIds.Clear();
public bool Remove(int id) {
var idx = rowIds.BinarySearch(id);
if (idx < 0) {
return false;
}
rowIds.RemoveAt(idx);
for (int i = 0; i < columns.Length; i++) {
ArrayHelper.remove_at(ref columns[i], idx);
}
return true;
}
public void Trim() {
for (int i = 0; i < columns.Length; i++) {
ArrayHelper.trim(ref columns[i], rowIds.Count);
}
}
public bool containsID(int id) =>
rowIds.BinarySearch(id) >= 0;
public IEnumerator GetEnumerator() {
var count = rowIds.Count;
for (int i = 0; i < count; i++) {
yield return new MyRow(this, i);
}
}
class MyRow : IBlueRow {
readonly BlueColumnTable table;
readonly int rowIdx;
public MyRow(BlueColumnTable table, int rowIdx) {
this.table = table;
this.rowIdx = rowIdx;
}
public object this[int colNo] => table.columns[colNo][rowIdx].GetValue();
public IBlueTableSchema schema => table.schema;
}
}
@@ -15,209 +15,16 @@ using mbts;
using BCG.Extensions;
using System.Text.Json;
using System.Text.Json.Nodes;
using Newtonsoft.Json;
using BCG;
using System.Runtime.CompilerServices;
using bts;
using Spark.Core;
using System.Numerics;
namespace bts {
// public class CompositeRow : IBlueRow {
// private IBlueRow _lrow, _rrow;
// private BlueRow _out_row;
// public CompositeRow(IBlueRow lrow, IBlueRow rrow) {
// _lrow = lrow;
// _rrow = rrow;
// IBlueTableSchema schema = _lrow.schema;
// List<object> vals = new List<object>();
// foreach (var o in _lrow) {
// vals.Add(o);
// }
// foreach (ColumnInfo ci in _rrow.schema.columnInfo) {
// if (ci.colName == "id") {
// continue;
// }
// vals.Add(_rrow[ci.colNo]);
// schema = schema.add_column(ci.type_code(), ci.colName);
// }
// _out_row = new BlueRow(schema, vals.ToArray());
// }
// public IBlueTableSchema schema {
// get { return _out_row.schema; }
// }
// public object? this[int index] {
// get { return _out_row[index]; }
// }
// public object? this[string colName] {
// get {
// return _out_row[colName];
// }
// }
// }
}
namespace BCG {
public static class BlueDataUtility {
public static IBlueRow create_composite_row(IBlueRow lr, IBlueRow rr, int id) {
IBlueTableSchema schema = lr.schema;
List<object> vals = new List<object>();
foreach (ColumnInfo ci in lr.schema.columnInfo) {
if (ci.colName == "id") {
vals.Add(id);
}
vals.Add(lr[ci.colName]);
}
foreach (ColumnInfo ci in rr.schema.columnInfo) {
if (ci.colName == "id") {
continue;
}
schema = schema.add_column(ci.type_code(), ci.colName);
vals.Add(rr[ci.colName]);
}
IBlueRow r = new BlueRow(schema, vals.ToArray());
return r;
}
#region Extensions
public static bool is_null(this IBlueRow r, string col_name) {
object col_val = r[col_name];
return col_val == null || DBNull.Value.Equals(col_val);
}
public static DateTime get_datetime(this IBlueRow r, string col_name, DateTime err_value = default(DateTime)) {
return BlueDataUtility.get_row_datetime_value(r, col_name, err_value);
}
public static DateTime get_datetime(this IBlueRow r, int col_no, DateTime err_value = default(DateTime)) {
return BlueDataUtility.get_row_datetime_value(r, col_no, err_value);
}
public static double? GetFloat64(this IBlueRow r, int colNo) =>
GetFloat64(r[colNo]);
public static double? GetFloat64(this IBlueRow r, string colName) =>
GetFloat64(r[colName]);
public static double? GetFloat64(object obj) {
if (obj is double d) {
return d;
}
if (obj is int i32) {
return i32;
}
if (obj is long i64) {
return i64;
}
if (obj is string s) {
return double.TryParse(s, out d) ? d : null;
}
if (obj is uint u32) {
return u32;
}
if (obj is ulong u64) {
return u64;
}
if (obj is short i16) {
return i16;
}
if (obj is ushort u16) {
return u16;
}
return null;
}
public static int? GetInt32(this IBlueRow r, int colNo) =>
GetInt32(r[colNo]);
public static int? GetInt32(this IBlueRow r, string colName) =>
GetInt32(r[colName]);
public static int? GetInt32(object obj) {
checked {
if (obj is double d) {
return (int)d;
}
if (obj is int i32) {
return i32;
}
if (obj is long i64) {
return (int)i64;
}
if (obj is string s) {
return double.TryParse(s, out d) ? (int)d : null;
}
if (obj is uint u32) {
return (int)u32;
}
if (obj is ulong u64) {
return (int)u64;
}
if (obj is short i16) {
return i16;
}
if (obj is ushort u16) {
return u16;
}
}
return null;
}
public static long? GetInt64(this IBlueRow r, int colNo) =>
GetInt64(r[colNo]);
public static long? GetInt64(this IBlueRow r, string colName) =>
GetInt64(r[colName]);
public static long? GetInt64(object obj) {
checked {
if (obj is double d) {
return (long)d;
}
if (obj is int i32) {
return i32;
}
if (obj is long i64) {
return i64;
}
if (obj is string s) {
return double.TryParse(s, out d) ? (long)d : null;
}
if (obj is uint u32) {
return u32;
}
if (obj is ulong u64) {
return (long)u64;
}
if (obj is short i16) {
return i16;
}
if (obj is ushort u16) {
return u16;
}
}
return null;
}
public static DateTime? GetUnixEpochDateTime(this IBlueRow row, string colName) =>
GetUnixEpochDateTime(row[colName]);
public static DateTime? GetUnixEpochDateTime(this IBlueRow row, int colNo) =>
GetUnixEpochDateTime(row[colNo]);
public static DateTime? GetUnixEpochDateTime(object obj) {
var tsNanos = GetInt64(obj);
return tsNanos.HasValue ? DateTime.UnixEpoch.Add(new TimeSpan(tsNanos.Value / 100)) : null;
}
public static DateTime? GetDateTime(object obj) {
var res = _get_datetime_value(obj, DateTime.MinValue);
if (res == DateTime.MinValue) {
return null;
}
return res;
}
public static T get_enum<T>(this IBlueRow r, string col_name, T err_value = default(T)) where T : struct {
return BlueDataUtility.get_row_enum_value<T>(r, col_name, err_value);
}
@@ -242,17 +49,6 @@ namespace BCG {
rv.Add(r.get<T>(col));
return rv;
}
public static IEnumerable<T> get_colvalues<T>(IEnumerable<IBlueRow> rows, string col, int start_index, int count) {
List<T> rv = new List<T>();
int i = 0;
int n_copied = 0;
foreach (IBlueRow r in rows)
if (i++ >= start_index && n_copied < count) {
rv.Add(r.get<T>(col));
n_copied++;
}
return rv;
}
public static IDictionary<T, IEnumerable<IBlueRow>> group_by<T>(IBlueRowCollection rows, string gp_col) {
Dictionary<T, List<IBlueRow>> rv = new Dictionary<T, List<IBlueRow>>();
@@ -316,17 +112,13 @@ namespace BCG {
}
}
public static List<IBlueRow> to_list(this IBlueRowCollection rows) {
public static IEnumerable<IBlueRow> to_ienum(this IBlueRowCollection rows) {
List<IBlueRow> rv = new List<IBlueRow>();
foreach (IBlueRow r in rows)
rv.Add(r);
return rv;
}
public static IEnumerable<IBlueRow> to_ienum(this IBlueRowCollection rows) {
return rows.to_list();
}
public static IDictionary<int, IBlueRow> to_map(this IBlueRowCollection rows) {
Dictionary<int, IBlueRow> rv = new Dictionary<int, IBlueRow>();
foreach (IBlueRow r in rows) {
@@ -336,10 +128,6 @@ namespace BCG {
return rv;
}
public static bool contains_column(this IBlueTableSchema input_schema, string col) {
return input_schema.columnNames.Contains(col);
}
public static IBlueTableSchema add_columns(this IBlueTableSchema input_schema, params Tuple<Type, string>[] cols) {
List<ColumnInfo> cis = new List<ColumnInfo>(input_schema.columnInfo);
foreach (Tuple<Type, string> c in cols)
@@ -347,11 +135,6 @@ namespace BCG {
return new BlueTableSchema(input_schema.tableName, cis.ToArray());
}
public static IBlueTableSchema add_column(this IBlueTableSchema input_schema, TypeCode type_arg, string col_name) {
Tuple<Type, string> tup = new Tuple<Type, string>(_typecode_to_type[type_arg], col_name);
return add_columns(input_schema, tup);
}
public static IBlueRowCollection to_collection(this IBlueRow r) {
if (r == null)
return null;
@@ -408,18 +191,6 @@ namespace BCG {
#region json
public static Dictionary<string, string> convert_json_to_dictionary(string json_string) {
Dictionary<string, string> dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(json_string);
return dictionary;
}
public static IBlueRow convert_json_to_row(string json_string, int id = 0) {
Dictionary<string, object> dictionary = JsonConvert.DeserializeObject<Dictionary<string, object>>(json_string);
if (!dictionary.ContainsKey("id")) {
dictionary.Add("id", id);
}
return new BlueRow(dictionary);
}
public static List<JsonNode> json_to_json_node_list(string jsonString) {
var jsonNodeList = new List<JsonNode>();
bool noe = String.IsNullOrEmpty(jsonString);
@@ -438,7 +209,7 @@ namespace BCG {
foreach (JsonNode jsonNode in jsonArray) {
jsonNodeList.Add(jsonNode);
}
} catch (System.Text.Json.JsonException ex) {
} catch (JsonException ex) {
Console.WriteLine($"Invalid JSON: {ex.Message}");
}
@@ -715,16 +486,7 @@ namespace BCG {
ColumnInfo[] cis = new ColumnInfo[table.Columns.Count];
foreach (DataColumn col in table.Columns)
cis[col.Ordinal] = new ColumnInfo(col.ColumnName, col.Ordinal, col.DataType);
IBlueTableSchema rv = new BlueTableSchema(cis, table.TableName);
rv = rv.add_id_col_if_missing();
return rv;
}
public static IBlueTableSchema add_id_col_if_missing(this IBlueTableSchema schema) {
IBlueTableSchema rv = schema;
if (!schema.columnNames.Contains("id")) {
rv = schema.add_columns(Tuple.Create(typeof(int), "id"));
}
return rv;
return new BlueTableSchema(cis, table.TableName);
}
/// <summary>
@@ -982,16 +744,10 @@ namespace BCG {
}
public static IBlueRowCollection toIBlueRowCollection(DataTable dt) {
IBlueTableSchema schema = getSchema(dt);
BlueTable rv = new BlueTable(schema);
foreach (DataRow dr in dt.Rows) {
MutableBlueRow nr = new MutableBlueRow(schema);
foreach (DataColumn col in dr.Table.Columns)
nr.setValue(col.ColumnName, dr[col.ColumnName]);
nr.setValue("id", rv.Count);
rv.addRow(nr);
}
return rv;
BlueTable retVal = new BlueTable(getSchema(dt));
foreach (DataRow dr in dt.Rows)
retVal.addRow(dr);
return retVal;
}
public static IBlueRowCollection toIBlueRowCollection(DataRow[] rows) {
@@ -1063,20 +819,20 @@ namespace BCG {
/// </summary>
/// <param name="r1"></param>
/// <param name="r2"></param>
/// <param name="col_names"></param>
/// <param name="colNames"></param>
/// <returns></returns>
public static int compare_rows(IBlueRow r1,
IBlueRow r2,
params string[] col_names) {
int comp_res = 0;
foreach (string cn in col_names) {
object val1 = r1[cn];
object val2 = r2[cn];
comp_res = _compare_row_cols(val1, val2);
if (comp_res != 0)
params string[] colNames) {
int retVal = 0;
foreach (string colName in colNames) {
object val1 = r1[colName];
object val2 = r2[colName];
retVal = _compare_row_cols(val1, val2);
if (retVal != 0)
break;
}
return comp_res;
return retVal;
}
private static int _compare_row_cols(object v1, object v2) {
@@ -1852,10 +1608,8 @@ namespace BCG {
public static int[] get_column_indices(IBlueTableSchema schema, string[] col_names) {
List<int> rv = new List<int>();
foreach (string c in col_names) {
Log.assert(schema.contains_column(c), $"Could not find col: {c} in table: {schema.tableName}");
foreach (string c in col_names)
rv.Add(schema[c].colNo);
}
return rv.ToArray();
}
@@ -2342,57 +2096,23 @@ namespace BCG {
try {
if (v == null || v == DBNull.Value)
return error_val;
if (v is DateTime) {
return (DateTime)v;
} else if (v is string) {
DateTime rv_dt;
// Try parsing the string as a DateTime
if (DateTime.TryParse((string)v,
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.RoundtripKind,
out rv_dt)) {
else {
if (v is DateTime)
return (DateTime)v;
else if (v is string) {
DateTime rv_dt = error_val;
DateTime.TryParse((string)v, out rv_dt);
return rv_dt;
} else {
return error_val; // Return the error value if parsing fails
double oa_date = (double)Convert.ChangeType(v, typeof(Double));
return DateTime.FromOADate(oa_date);
}
} else {
// Assume the input can be converted to a double and use FromOADate
double oa_date = (double)Convert.ChangeType(v, typeof(Double));
return DateTime.FromOADate(oa_date);
}
} catch {
return error_val;
}
}
public static TimeSpan? get_timespan(this IBlueRow r, int col_no) =>
get_timespan(r[col_no]);
public static TimeSpan? get_timespan(this IBlueRow r, string col_name) =>
get_timespan(r[col_name]);
public static TimeSpan? get_timespan(object obj) {
if (obj is TimeSpan ts) {
return ts;
}
var str = obj as string ?? obj?.ToString();
if (str is null) {
return null;
}
if (TimeSpan.TryParse(str, out ts)) {
return ts;
}
if (str.StartsWith("PT")) {
try {
// Parse ISO 8601 duration
return System.Xml.XmlConvert.ToTimeSpan(str);
} catch {
}
}
return null;
}
#endregion
#region CSV methods
@@ -1,56 +0,0 @@
#nullable enable
namespace Bts.DataStreamCore;
using BCG;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class BlueRowCollection : IBlueRowCollection {
readonly ICollection source;
readonly Func<int, IBlueRow> findRow;
readonly Func<int, bool> containsKey;
public BlueRowCollection(ICollection source, IBlueTableSchema schema, Func<int, IBlueRow>? findRow = null, Func<int, bool>? containsKey = null) {
this.source = source;
this.schema = schema;
if (findRow is null || containsKey is null) {
if (source is IBlueRowCollection brc) {
findRow ??= id => brc[id];
containsKey ??= brc.containsID;
} else if (source is IDictionary dict) {
findRow ??= id => dict[id] as IBlueRow ?? throw new KeyNotFoundException();
containsKey ??= id => dict.Contains(id);
} else if (source is IDictionary<int, IBlueRow> genDict) {
findRow ??= id => genDict[id];
containsKey ??= genDict.ContainsKey;
} else if (source is IReadOnlyDictionary<int, IBlueRow> roGenDict) {
findRow ??= id => roGenDict[id];
containsKey = roGenDict.ContainsKey;
} else {
var cachedRows = new Lazy<Dictionary<int, IBlueRow>>(() =>
source.Cast<IBlueRow>().ToDictionary(r => r.Id()));
findRow ??= id => cachedRows.Value[id];
// Don't remove this lambda expression. Intellisense may suggest it, but that would
// instantiate 'cachedRows' immediately and defeat the purpose of using Lazy<T>.
containsKey ??= id => cachedRows.Value.ContainsKey(id);
}
}
this.findRow = findRow;
this.containsKey = containsKey;
}
public IBlueRow this[int id] => findRow(id);
public IBlueTableSchema schema { get; }
public int Count => source.Count;
public bool containsID(int id) =>
containsKey(id);
public IEnumerator GetEnumerator() =>
source.GetEnumerator();
}
@@ -1,64 +0,0 @@
#nullable enable
namespace Bts.DataStreamCore;
using BCG;
using bts.collections;
using bts.utils;
using System;
using System.Collections.Generic;
public class BlueRowColumnMask : IBlueRow {
readonly IBlueRow row;
readonly int[] hiddenColumns;
public BlueRowColumnMask(IBlueRow row, params int[] hiddenColumns) {
this.row = row;
this.hiddenColumns = hiddenColumns;
Array.Sort(hiddenColumns);
}
/// <summary>
/// Provides a way to explicitly skip sorting hiddenColumns. This is done at the callers risk,
/// as the index (int) operator performs a binary search on hiddenColumns.
/// </summary>
/// <param name="row">The underlying row whose columns to hide</param>
/// <param name="sortHiddenColumns">Whether or not to sort <paramref name="hiddenColumns"/> in
/// the constructor. They are sorted by default to ensure correct behavior in the index (int)
/// operator, which performs a binary search on this array.</param>
/// <param name="hiddenColumns">The columns (indices) to hide</param>
public BlueRowColumnMask(IBlueRow row, bool sortHiddenColumns, params int[] hiddenColumns) {
this.row = row;
this.hiddenColumns = hiddenColumns;
if (sortHiddenColumns) {
Array.Sort(hiddenColumns);
}
}
public object? this[string colName] {
get {
for (int i = 0; i < hiddenColumns.Length; i++) {
if (row.schema.columnInfo[i].colName == colName) {
throw new KeyNotFoundException();
}
}
return row[colName];
}
}
public object? this[int index] {
get {
if (index > row.schema.columnInfo.Length - hiddenColumns.Length) {
throw new IndexOutOfRangeException();
}
int pos = hiddenColumns.BinarySearch(index);
if (pos < 0) {
pos = ~pos;
}
return row[index + pos];
}
}
public IBlueTableSchema schema => row.schema;
}
@@ -7,7 +7,7 @@ namespace BCG
/// Used for enumerating an IEnumerable (ex ICollection). Furthermore, this is the
/// default Enueramtor used when enumerating asn IBlueRow
/// </summary>
public class BlueRowEnumerator : IDictionaryEnumerator
public class BlueRowEnumerator : IEnumerator
{
protected int myPos = -1;
protected int myRowSize = -1;
@@ -18,11 +18,6 @@ namespace BCG
myRow = row;
myRowSize = row.schema.columnNames.Length;
}
public DictionaryEntry Entry =>
new(myRow.schema.columnInfo[myPos].colName, myRow[myPos]);
public object Key => myRow.schema.columnInfo[myPos].colName;
public object Value => myRow[myPos];
#region IEnumerator members
public void Reset() {myPos = 0;}
@@ -1,30 +0,0 @@
#nullable enable
namespace BCG;
using System;
using System.Collections;
public class BlueRowKeyCollection : ICollection {
readonly ColumnInfo[] columns;
public BlueRowKeyCollection(ColumnInfo[] columns) =>
this.columns = columns;
public int Count => columns.Length;
public bool IsSynchronized => false;
public object SyncRoot => this;
public void CopyTo(Array array, int index) {
for (int i = 0; i < columns.Length; i++) {
array.SetValue(columns[i].colName, i + index);
}
}
public IEnumerator GetEnumerator() {
for (int i = 0; i < columns.Length; i++) {
yield return columns[i].colName;
}
}
}
Loaded 100 of 537 files, more files were not shown because too many files have changed in this diff. Show more