Compare commits

...
Author SHA1 Message Date
John Colvin 2e78af1756 fix build: Upgrade IronPython to 3.4.2
All csprojs need to be on same version (Spark.csproj was on 3.4.1, while
DataStream.csproj was on 3.4.2)
2025-06-16 11:08:50 -04:00
Taha 70fae06a30 BlueOrb streams and MLP 2025-06-08 21:52:38 -04:00
John Colvin 07b59559a2 dev qol: Reduce md log level in config profile 2025-06-03 02:23:59 +00:00
John Colvin cd1709563b fix: Generate reject exe reports from ack at binance
This only applies to "new" order acks. In all other cases, exe reports
are generated from the order update stream. New order rejects are the
exception because they're not visible in the stream. Presumably, they're
never actually entered into binance's order system (they're "rejected"
before that happens).
2025-06-03 02:21:18 +00:00
arham 94f22ddf40 Update: changed url for okx ws exe in config 2025-05-30 12:59:26 +00:00
arham 7f6c08f956 Fix: positions now go through dispatch incoming 2025-05-29 16:26:05 +00:00
arham 1d737cdf82 Fix: change time to 5s for pos update okx 2025-05-23 16:12:12 +00:00
arham b645192355 Add: OKX position turned on 2025-05-23 15:33:11 +00:00
John Colvin 5ad7755b28 tool: Make open orders symbol param optional in binance.env 2025-05-20 20:08:34 +00:00
John Colvin df4ca124c3 cleanup: Remove redundant script get_binance_md.sh
I should have removed this when I added binance_rest_client.sh
2025-05-20 20:08:34 +00:00
John Colvin 2c8b9ee288 tool: Add envsource.fish to load .env files in fish 2025-05-20 20:08:34 +00:00
John Colvin f02f28e347 tool: Add a few vars to binance.env 2025-05-20 20:08:34 +00:00
John Colvin c8a89c1e8d cleanup: Rename get_binance_md.py -> binance_client.py
This is a more appropriate name (it's not just md anymore).
2025-05-20 20:08:34 +00:00
John Colvin 7ae9e07a30 tool: Use binance.env file in python client
Like the bash impl (binance_rest_client.sh), it gets urls, params
(templates), and api credentials from env vars.
2025-05-20 20:08:34 +00:00
Taha a130e47218 Arb Scoring stream 2025-05-20 00:24:17 -04:00
John Colvin a377f6de7f improvement (ui): Use sec qty display settings in rec report 2025-05-19 12:35:25 -04:00
John Colvin 855373c9e6 cleanup: Remove unnecessary code 2025-05-19 15:57:35 +00:00
John Colvin e1b535b633 feat: Sync exch positions in binance usds futs gw 2025-05-19 15:57:35 +00:00
John Colvin 3b9ac71460 refactor: Abstract out start/stop state machine for gen use
* From binance usds futures gateway
* Thread-safe
* Handles re-entrancy gracefully
2025-05-19 15:57:35 +00:00
John Colvin 9a5075daaf improvement: Use recursive_mutex in ws client to prevent deadlocks 2025-05-19 15:57:35 +00:00
John Colvin 4e7fe811a8 Add ConcurrentUnorderedMap (c++) 2025-05-19 15:57:35 +00:00
Taha 0a6733180d Added SpreadStatsStream 2025-05-18 01:10:33 -04:00
Taha f2169c6bd4 Adding more data to SpreadPerformanceStream 2025-05-16 01:42:32 -04:00
Taha 23ef478391 Spread analytics streams 2025-05-15 15:01:27 -04:00
John Colvin 236a5a9362 fix: Format binance order price up to 5 decimal places
Bugs (fixed):
  * Binance JELLYUSDT order prices get rounded to 4 decimal places, even
    though the price tick is 0.00001
2025-05-13 15:02:02 +00:00
John Colvin cb560bbe33 fix: Sum realized & unrealized pnl correctly in header rows 2025-05-08 14:13:02 -04:00
John Colvin 248f2644ca deploy: Automatically restart "sparkd-symbols" service
This is what we deploy to the alphaworx-zen-hk-live server
2025-05-07 14:49:53 +00:00
arham b87d86f4d6 FIx: okx exe user cancel should be cxl not rjct 2025-05-07 08:38:28 +00:00
arham 8515196dcb Add: okx exe fok orders working 2025-05-07 08:08:40 +00:00
Taha Afzal e5e042f016 Spreader in RH mode now fires FOK, and hedges only whne the FOK is completely filled (ie not as we we might get partial fills) 2025-05-07 06:12:48 +00:00
John Colvin da3593326d Enable FOK orders at binance 2025-05-06 22:20:46 +00:00
John Colvin 313d3a2377 Enable FOK in EMNativeOrder.cpp
This class was originally designed for Emumba execution at deribit
(hence the "EM" prefix), but now serves all crypto exchanges.
2025-05-06 22:19:11 +00:00
Taha Afzal 22f0e126d0 Adding FillOrKill (FOK) to TimeInForce 2025-05-06 19:39:40 +00:00
arham c76b061e20 fmt: okx exe 2025-05-02 09:00:00 +00:00
arham 0107b65281 add code for okx exe position updates 2025-05-02 08:59:46 +00:00
Taha Afzal 6b5496b799 OrderStore does not eleted all orders at sparkd boot-time now 2025-05-02 00:10:48 +00:00
arham 42f9daf9cb Add: okx cancel all after code, not turned on for now 2025-05-01 09:48:06 +00:00
arham bc5ddade7f Add: okx exe small changes to maybe make ping better 2025-05-01 09:42:54 +00:00
arham d8d198f7f4 Add: OKX only handle orders from this session 2025-05-01 09:41:20 +00:00
John Colvin af9eb670c1 build: Update build scripts to target dotnet 8 2025-04-30 12:06:28 -04:00
John Colvin d91837c377 improvement (pnl ui): Get qty display params from sec proto
Instead of config
2025-04-30 03:06:04 -04:00
John Colvin 7725ae33ef fix: Fix total realized/unrealized pnl calc 2025-04-30 01:35:22 -04:00
John Colvin 9f56abaa38 vscode: Replace net7 w/ net8 in launch.json 2025-04-30 01:15:34 -04:00
John Colvin 95444d4a4c fix: Exclude nans from pnl sum 2025-04-30 00:47:49 -04:00
John Colvin a7e1c18fe2 diag: Improve trace logs in binance usds futures gw 2025-04-29 19:49:33 +00:00
John Colvin d11fd23cb0 refactor: Drop "_" suffix in private vars (cpp)
It just looks ugly, and unnecessary with modern tooling. Plus it's ugly.
2025-04-29 19:35:15 +00:00
John Colvin 8499ac0dfb diag: Clean up structured logging in binance order store 2025-04-29 19:35:15 +00:00
John Colvin f4afe348e6 fix: Update timestamps in binance order store when orders change 2025-04-29 19:35:15 +00:00
John Colvin 096424b60b refactor: Use WebsocketClient fn run_in_background in binance gws 2025-04-29 19:35:15 +00:00
John Colvin b4f5e66466 fix: Set okx perp exp to year 2100
Because the year 3000 is too big for signed int64
nanosecond timestamp
2025-04-29 19:35:15 +00:00
John Colvin 69a0bcc9cd fix: Request binance fut md on ccapi dispatcher thread 2025-04-29 19:32:21 +00:00
John Colvin d72ebdf421 perf: Send Binance Usds Futs md rest reqs on background thread 2025-04-29 19:32:21 +00:00
John Colvin 8e93856767 fix: Send exchangeInfo req via our HttpClient instead of ccapi
For binance usds futs (we already did this for spots)

Bugs (fixed):
  * We get a boost beast exception about the read limit being exceeded
    when requesting securities from Binance prod url (testnet works).
2025-04-29 19:32:21 +00:00
John Colvin 19dae6cd34 fix build (cpp release): Don't return reference to local var 2025-04-29 19:32:21 +00:00
John Colvin 24f42550dd fix build (cpp release): Explicitly cast int64 -> uint64 2025-04-29 19:32:21 +00:00
John Colvin c2150ae450 refactor: Move BinanceUsdsFuturesFilterTuple fns to cpp file 2025-04-29 19:32:21 +00:00
John Colvin 40dbfaa068 improvement: Support both key types in binance spots gw
Namely, ED25519 and HMAC-SHA256. Only the former can be used
to login over websocket, which eliminates the need to sign requests
after that.
2025-04-29 19:32:21 +00:00
John Colvin 3756a8a8b7 Add api key type enum to binance exe gateway config
ED25519 keys offer performance benefits over the HMAC-SHA256
keys when using the websocket api, as you can log in on the websocket
connection to avoid signing each request.
2025-04-29 19:32:21 +00:00
John Colvin 46c8dcb18f fix: Add binance spot order newOrderResp type to json/query params 2025-04-29 19:32:21 +00:00
John Colvin 024480f32e improvement: Send binance usds fut orders via websocket api
Unlike the previous implementation, which sent REST requests, this won't
block the dispatch thread waiting for a response.
2025-04-29 19:32:21 +00:00
John Colvin ba525372bb cleanup: Move a few types from orderman_utils to their own headers
So they can be included without depending on OrderService.pb.h
2025-04-29 19:24:41 +00:00
John Colvin 8aa0f1b674 refactor: Move binance state machine out of "spots" dir
So it can be used in the implementation for all binance apis (usds futs,
cross margin, etc.)
2025-04-29 05:24:04 +00:00
John Colvin fc14215d9b fix: Don't assert-crash if ord key isn't found for outgoing req
The i/o is asynchronous, so it's possible for the gateway to receive
a terminal ack from the exchange, remove the order from its index,
then receive a cancel/modify req from an algo that submitted the
req before it knew the order reached a terminal state.
2025-04-29 05:24:04 +00:00
John Colvin 091ed5a327 fix: Don't fire exe report for internal rejections
Internal rejections don't mean the order isn't "working". Only
rejections from the exchange mean that.
2025-04-29 05:24:04 +00:00
John Colvin 30bb9d0837 fix: Make SpotsOrderStore threadsafe 2025-04-29 05:24:04 +00:00
John Colvin 9cb2c580d6 diag: Use structured logging in binance spots gw 2025-04-29 05:24:04 +00:00
John Colvin 2e2150ac1a refactor: Send binance spot orders through websocket api
This offers performance benefits over the REST api, since we don't have
to sign each request.

Note: I consolidated the UserDataSubscription code into SpotsGateway
because it was cleaner than trying to share a single websocket
connection between the two classes (UserDataSubscription and
SpotsGateway).
2025-04-29 05:24:04 +00:00
John Colvin 21d9435a67 Add run_in_background fn to WebsocketClient (cpp) 2025-04-29 05:24:04 +00:00
John Colvin e7e334fb5a Add continous ping function to WebsocketClient (cpp) 2025-04-28 17:12:59 +00:00
John Colvin 61f04c4605 fix: Implement state machine for binance cxl/replace 2025-04-28 17:12:59 +00:00
John Colvin 24fb2e1e39 refactor: Remove 'get_internal_key' delegate from exe report store
It made constructing the exe report store awkward, and smelled like poor
design.
2025-04-28 17:12:59 +00:00
John Colvin ece141c448 Add dedicated types for structured logging 2025-04-28 17:12:59 +00:00
John Colvin 617bac8e74 cleanup: Move CancelOrderMsg impl to .cpp 2025-04-28 17:12:59 +00:00
John Colvin ab217401eb cleanup: Move CreateOrderMsg impl to .cpp, get rid of unused code 2025-04-28 17:12:58 +00:00
John Colvin 77e5c1481b Add security_id/name fns to ExecutionReport for convenience
So callers don't need to check if security is a nullptr
2025-04-28 17:12:58 +00:00
John Colvin a0f77f92a3 cleanup: Move ExecutionReport impl to .cpp
Also add using aliases to get rid of repetitive namespace prefixes
2025-04-28 17:12:58 +00:00
John Colvin 0acdcb150d fix: Format price & qty w/ 6 decimals in binance modify order json 2025-04-28 17:12:58 +00:00
John Colvin ac2f3b9bc6 Add ConcurrentQueue (c++) 2025-04-28 17:12:58 +00:00
John Colvin 0e522f90e5 refactor: Add line num suffix to var name in LOCK_GUARD macro
Rename to "BTS_LOCK_GUARD" while we're at it to avoid potential naming conflicts
2025-04-28 17:12:58 +00:00
John Colvin 40ad1f1b48 Update binance websocket endpoints
The api just changed, and old urls will be retired in May 2025
2025-04-28 17:12:58 +00:00
John Colvin 1cb75d399f devcontainer: Update dotnet7 -> dotnet8 2025-04-28 17:12:58 +00:00
John Colvin cddecc0543 cleanup: Fix benign typo in websocket_client.h
The open_handler fn return type should be "OpenHandler", not
"CloseHandler" (obviously).
2025-04-28 17:12:58 +00:00
John Colvin 484e36b330 refactor: Make timestamp internal value to signed (int64)
I am sick of casting uint64 -> int64. The latter is a much more
common argument type than the former.
2025-04-28 17:12:58 +00:00
John Colvin 8a9c22fa2a vscode: Add Python Debugger entry to launch.json 2025-04-28 17:12:58 +00:00
John Colvin a6e8853cb9 fix build (warns): Account for nullable ref types 2025-04-28 17:12:58 +00:00
John Colvin dafa193283 fix build (windows): Update externals to fix catch include path
I couldn't get the build to work with the new catch2 on windows, though
it does work on linux. Rather than revert the catch -> catch2 include
path changes (again, which do build on linux), I decided to rename the
old windows catch include dir 'catch2'.
2025-04-28 17:12:58 +00:00
John Colvin 23651970c9 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.
2025-04-28 17:12:58 +00:00
John Colvin 043efab5a2 build: Upgrade c# to net8.0 2025-04-28 17:12:58 +00:00
John Colvin 5476466d55 Fetch secrets for config profiles with new aws sso config 2025-04-28 17:12:58 +00:00
John Colvin 54cb5a2ab2 tool: Add script to configure aws sso 2025-04-28 17:12:58 +00:00
John Colvin 29bf7d8d7e deploy (fix): Update okx urls
Their aws domain has been retired.
2025-04-28 17:12:58 +00:00
John Colvin 855d2fd790 build: Update vcpkg 2025-04-28 17:12:58 +00:00
John Colvin 8a6a652882 fix build: Get rid of databento's internal nlohmann-json
** Migrate nlohmann-json over to vcpkg in the process **

Make it so databento is built with the same nlohmann-json lib that our
code is built with. Recently, I started getting undefined symbol errors
in databento code from nlohmann headers - presumably a conflict between
their nlohmann dep and ours.
2025-04-28 17:12:58 +00:00
John Colvin 3f288704bf build (linux): Migrate openssl to vcpkg, update to 3.5.0
Databento, as of version 0.32.0, requires openssl >= 3.0

https://github.com/databento/databento-cpp/releases/tag/v0.32.0
2025-04-28 17:12:58 +00:00
John Colvin 98bc78463d build (linux): Migrate catch2 dep to vcpkg (from externals) 2025-04-28 17:12:58 +00:00
John Colvin 6d271ad7cd build (linux): Manage fmt dep with vcpkg 2025-04-28 17:12:58 +00:00
John Colvin 2a17d656a5 fix: Dump json to str in LOG statements
The nlohmann::json obj isn't formattable (i.e., doesn't have a
fmt::formatter<T> specialization)
2025-04-28 17:12:58 +00:00
John Colvin 10436f0f3b tool: Rename binance_orders_client.sh -> binance_rest_client.sh
It supports md and order/trade requests
2025-04-28 17:12:58 +00:00
arham 86b19f0ef0 Add: okx exe treats all cancelations except ioc as rejections 2025-04-26 05:35:46 +00:00
Taha Afzal 502024dd10 Removing an overzealous assert in the spreader, which was being false if the spread_book was not received once 2025-04-23 04:40:16 +00:00
John Colvin 623012b0b0 deploy: Add "sparkd_symbols" image to Dockerfile
Normally, we bake spark config into the image, which is simpler and less
error prone than managing separate configurations per host machine
and/or container. The sparkd_symbols deployment breaks the mold. Config
is mounted to a dir on the host machine so symbols can be added/removed
via config (i.,e., spark.conf) when we bounce sparkd.
2025-04-17 05:53:05 +00:00
John Colvin 5859f0f2d1 deploy (fix): chown bts for whole sparkdata dir in sparkd-symbols
Unlike normal deploys, the config dir isn't copied directly into the image
2025-04-16 13:48:24 +00:00
John Colvin eeffb735ae deploy (fix): Override existing values when loading env files 2025-04-16 13:48:24 +00:00
John Colvin b602997f3a deploy: Build sparkd if any service starts with "sparkd"
Previously, we only built sparkd for the "sparkd" service (i.e., exact match)
2025-04-16 13:48:24 +00:00
Taha Afzal 3530a77b38 Fixing the situation where an IOC cancels, cancels the spreader 2025-04-16 04:26:50 +00:00
arham afdf635b31 fix: changes spread_book_tick_sz from int to double to fix low tick being zero for reverse hedge orders 2025-04-11 07:31:03 +00:00
John Colvin 4d4aefc0a7 fix: Bind SpreaderType dropdown to all algo types in synth ladder
Bugs (fixed):
  * The SpreaderType dropdown only works for plain spreader orders. It
    doesn't work for icebergs, leans, etc.
2025-04-10 16:16:43 -04:00
arham 960a8af77a Fix: OKX futures working now 2025-04-10 05:06:17 +00:00
Taha Afzal 89828659a4 Reducing loggging on reverse hedge evaluation 2025-04-09 20:05:48 +00:00
John Colvin 76f83fd7f5 Revert "Set irrelevant spreader params to null in ladder"
This reverts commit 924386084b.
2025-04-09 15:52:00 -04:00
Taha Afzal d4e40948d2 Changing the logic to determine if a leg is a quoting leg or not 2025-04-09 19:29:50 +00:00
arham 912ab512d2 Add: ioc orders to okx exe 2025-04-09 19:00:24 +00:00
Taha Afzal 5d3eb92175 Spreader gets the spread ticks from the right source now (it was hard coded at 0.1 earlier) 2025-04-09 18:42:06 +00:00
John Colvin 924386084b Set irrelevant spreader params to null in ladder
Depending on the SpreaderType enum value (treat it like a oneof case)
2025-04-09 10:29:15 -04:00
Taha Afzal acab3ac392 Reversehedging fixed 2025-04-09 09:42:47 -04:00
arham d06a62f6ee Format: ran clang format on file 2025-04-09 09:42:47 -04:00
arham 14e3eee0bc Add: config changes to make server controller work and set up hk zen server 2025-04-09 09:42:47 -04:00
Taha Afzal 7277bf52f5 Fixing build: 2025-04-09 09:42:47 -04:00
Taha Afzal b81dc7f5cf Fixing a bug, where the spreader was isidentifying the quoting leg 2025-04-09 09:42:47 -04:00
John Colvin b1a4635345 ui: Enable IOC for Iceberg orders
Previously, it was only enabled for Limit orders.
2025-04-08 13:22:09 -04:00
John Colvin 7c7c689170 fix build: Don't cast to unsigned int when checking bytesRead < 0 2025-04-04 15:36:55 -04:00
John Colvin 116506c8da fix build: Lock databento version to v0.31.0
Previously, we were simply fetching HEAD. This was fine until they
released v0.32.0 (on 04/02/2025), which introduced a new dependency
requirement that broke our build: OpenSSL >= 3.0.
2025-04-04 15:36:55 -04:00
Adeel Khan 3feda49ef1 Fix: Taifex Time Conversion 2025-04-04 15:36:54 -04:00
Adeel Khan 10318be7bc FIX: Taifex Crash Fixed, Added Diag Logs 2025-04-04 15:36:54 -04:00
Adeel Khan f7d525a527 ADD: TBBO & Symbol wise Naming in Recorder 2025-04-04 15:36:54 -04:00
Adeel Khan d2fe9f167a ADD: TWSE Code Complete 2025-04-04 15:36:54 -04:00
Adeel Khan 696d91a5af ADD: TWSE to WebApp 2025-04-04 15:36:54 -04:00
Adeel Khan d575ba0ea8 ADD: TWSE throughout Sparkd 2025-04-04 15:36:54 -04:00
Taha 058b131760 Cleaning up some streams,new prompt etc 2025-04-04 15:36:52 -04:00
John Colvin 57f8f3ff58 ui: Add Sniper and Reverse Hedge controls 2025-04-04 00:19:38 -04:00
John Colvin 775df2850d Add Sniper and Reverse Hedge params to spreader proto 2025-04-04 00:19:38 -04:00
Taha Afzal cb2b15f10b Adding IOC to SimExecution 2025-04-03 23:24:30 +00:00
Taha Afzal 60362a4c95 Adding reverse-hedge to spreader 2025-04-03 23:24:30 +00:00
John Colvin c6d7a8f38c ui (pnl): Use dark theme fg in "Selected" and "Total" labels
Previously, it was black and hard to read since the background is dark.
2025-03-26 14:46:44 -04:00
John Colvin 7931c62b46 ui (pnl): Hide "Override Cpp" menu item
The overrides aren't respected in (new) pnl calcs.
2025-03-26 14:35:23 -04:00
John Colvin 58518451c8 ui (pnl): Show realized/unrealized pnl in row group totals 2025-03-26 14:31:04 -04:00
John Colvin e3bad78aef fix (pnl ui): Get cash per point from security
Previously, it was hardcoded to 1.
2025-03-24 16:54:37 -04:00
John Colvin 8e9ab8f2eb fix: Don't apply cme cpp overrides to non-cme securities
Bugs (fixed):
  * The cash per point for many securities is wrong. For example, it is
    5 for all BTC securities (which is wrong).

    Cause: cpp override config that should be specific to cme is applied
    to ALL securities.
2025-03-24 20:20:53 +00:00
John Colvin 8512f414d6 fix: Don't duplicate animations when migrating pnl window settings 2025-03-24 14:53:09 -04:00
John Colvin 513fc353cf ui (pnl): Increase default width for a few columns
I noticed some data was truncated when connected to Alphaworx prod
server.
2025-03-24 14:39:40 -04:00
John Colvin 4a04beafd2 cleanup: Consoildate order extension methods 2025-03-24 11:19:51 -04:00
John Colvin 79a3251f26 fix: Make security comparison deterministic again 2025-03-24 11:19:51 -04:00
John Colvin 8785e0fecd fix: Bootstrap all observers w/ snapshot on first update
Previously, the Subscribe impl only bootstrapped the first observer
(i.e., only in first call to Subscribe).

Bugs (fixed):
  * The ladder crashes if there are working orders when the
    ticks-per-row setting is changed.

    Cause: The ladder viewmodel resubscribes to order updates each time
    the ticks per row setting changes (as this determines the size of
    the price buckets into which orders are grouped). The IObservable
    "Bootstrap" extension fn doesn't properly clean up state leftover
    from the previous subcsription when this happens.
2025-03-24 11:17:04 -04:00
John Colvin 04251c96b6 ui (pnl): Compute pnl as sum of realized + unrealized
This addresses a subtle inconsistency in the pnl window.

The old "start_pnl" and "day_pnl" values (from IPNLUnit) are computed
with respect to the mid market for both long and short positions, while
the new "unrealized" pnl values are computed with respect to the side of
the market needed to close the position (i.e., bid market for long pos,
ask for short). Consequently, the combined pnl columns weren't equal to
the sum of realized and unrealized pnl.
2025-03-24 10:13:24 -04:00
John Colvin c2d400af1a fix (pnl ui): Don't overwrite menu display settings w/ defaults 2025-03-24 10:13:24 -04:00
John Colvin 133cc16628 ui: Add menu item to open mview from pnl
Populated with the same securities as the pnl window
2025-03-24 10:13:24 -04:00
John Colvin 16f7aede93 fix: Add case for Synthetic sec type in proto conversions 2025-03-24 10:13:24 -04:00
John Colvin 2b9488faff ui: Make pnl default settings pretty
* Make profit (green) and loss (red) easier to read against dark bg
* Hide 'SOD' and 'Day' columns (just show totals)
2025-03-24 10:13:24 -04:00
John Colvin 51b6d592d3 fix (pnl ui): Negate short avg cost when translating to avg price 2025-03-23 15:17:41 -04:00
John Colvin 1eb4ceba0a ui: Add columns for long/short avg pnl
When looking at avg cost, you often really want to know the difference
between it and the current market. These columns provide that information
so you don't need to do the arithmetic in your head.
2025-03-23 15:17:41 -04:00
John Colvin dbf5cadb44 ui: Add columns for realized/unrealized pnl 2025-03-23 15:17:41 -04:00
John Colvin 90f1bb0851 refactor: Move PNL data types to spark_api csproj 2025-03-23 13:08:46 -04:00
John Colvin 547d83e1b8 cleanup: Remove unused pnl enum WaterfallPriceFlags 2025-03-23 13:08:41 -04:00
John Colvin e888149c41 Add order msg throttle to sparkd config profiles 2025-03-20 17:29:43 +00:00
John Colvin b944c3980f Show 6 decimals in spreader order log
So we can better track those rascally iceberg orders w/ small fractional
quantities
2025-03-20 14:30:35 +00:00
Taha Afzal c2a8266106 merging 2025-03-20 01:23:05 +00:00
Mohammad Arham 4277ba61b9 Fix: Okx execution only sends 2025-03-19 13:26:57 -04:00
Mohammad Arham 35cfe9533b Add filter for okx er we that were caused by orders from outside the system 2025-03-19 13:26:39 -04:00
John Colvin d49efef93d Increase ram to 8gb in alphaworx_prod config
The previous value of 4gb wasn't enough, as the container would
occasionally crash with a SIGKILL interrupt.
2025-03-19 15:26:14 +00:00
John Colvin 502ed13456 fix: Round IcebergAlgo remaining quantity
Bugs (fixed, 2nd attempt):
  * Iceberg orders w/ fractional quantities can get into a state where
    they send an infinite stream of orders w/ 0 qty
2025-03-19 14:43:24 +00:00
John Colvin 716c4dd674 tool: Add script to dump sparkd logs to sqlite db 2025-03-19 14:41:23 +00:00
John Colvin 4a2b189a07 diag: Format Price and Quantity w/ up to 6 decimal places 2025-03-17 13:00:15 +00:00
John Colvin a42edaf9fa diag: Trivial fix for log msgs in SpreaderOrder
* Format qty with fractional part
* Remove redundant log
2025-03-17 13:00:15 +00:00
John Colvin cbc142ab15 fix: Account for rounding error in IcebergAlgo fills
Bugs (fixed):
  * Iceberg orders w/ fractional quantities can get into a state where
    they send an infinite stream of orders w/ 0 qty

    Note: I also changed the number of decimal places used when rounding
    order quantities from 6 to 7 (the level of precision guarenteed by
    IEEE 754).
2025-03-17 13:00:15 +00:00
John Colvin 3980f2d030 Add order msg throttle to alphaworx_prod config 2025-03-17 13:00:15 +00:00
John Colvin 00f6d269c9 fix: Set binance routing record "operator_id" to username (not account)
Must have been a typo
2025-03-17 00:51:54 +00:00
John Colvin 10b2d38de8 tool: Add cmd to tail sparkd log file using docker compose 2025-03-17 00:51:54 +00:00
John Colvin 6d4d8f6ac1 fix: Disable ccapi order book cross check for Binance md
When enabled, the checks fail regularly (usually more than once per
hour). Sometimes many of them happen in rapid succession before sparkd
crashes. I'm disabling them in the hopes that the crosses are benign,
and this will stop the crashes.
2025-03-17 00:51:54 +00:00
John Colvin 5db89e1e8d diag: Tone down noisy order management logs
* EMNativeOrder
* OrderRouter - only log routing record result if there are errors
* OrderServiceServer
* OrderStore - also avoid calling pb::to_string twice per change (it's
  expensive)
* ServiceBridge
2025-03-17 00:51:47 +00:00
John Colvin 379a46afa2 Add order msg throttle to sim_dev config 2025-03-15 20:07:14 +00:00
John Colvin d9eff37184 fix: Don't let rounding error accumulate in mview order summarizer
Bugs (fixed):
  * Sometimes mview shows that a security has working orders when it
    doesn't. It appears to be rounding-related as the price and qty of
    the phony working orders is NaN and 0, respectively.

  Cause: Rounding error accumulates in the order summarizer. If it gets
  bad enough, the working quantity (which is computed incrementally as
  orders transition to/from a working state) may still be non-zero after
  all orders become non-working.
2025-03-15 15:21:56 -04:00
John Colvin 3d055de139 cleanup: Rename _tick_factors -> _qty_tick in mview order summarizer
It is specifically for quantity (not price).
2025-03-15 15:21:56 -04:00
John Colvin 648be7dd97 improvement: Don't resort orderbook on every order update
This causes performace issues when the orderbook is sufficiently large
(noticeable when around 20k orders).
2025-03-15 15:21:56 -04:00
John Colvin 2cac9affe4 fix: Use consistent price comp in ladder order stream
Bugs (fixed):
  * The ladder occasionally crashes when orders are changing.

    Cause: Subtle differences between the ordinal and equality comparers
    made it possible for 2 prices to be considered equal by the former,
    and not equal by the latter. Since the ladder indexes orders by
    price, a "Key not found" exception could be thrown if the equality
    comparer detected a price change that the ordinal comparer did not.
2025-03-15 15:21:55 -04:00
John Colvin 30ff3ba707 Add some null checks in LadderGridHost 2025-03-15 15:21:55 -04:00
John Colvin 9d3afd68aa ui: Format Perp and Spot exps as "Perp" and "None" 2025-03-15 15:21:55 -04:00
John Colvin 8c3de1789b fix: Apply leg price mults when computing synth book
This is necessary to support synths with BTC-USDC-SWAP legs at Okx
(because 1 "contract" == 0.01 BTC).

Bugs (fixed):
  * Price multiplier has no effect in synthetic book
2025-03-14 19:32:04 +00:00
John Colvin b251e1d47e build: Generate semantic version header from git
Dump it to console and log file when sparkd runs
2025-03-14 16:00:06 +00:00
arham 6ccd48a8ba Fix, 1e-5 orders working okx 2025-03-13 17:49:14 +00:00
John Colvin 41d84f7f73 Change externals submodule url from ssh to https 2025-03-13 17:08:04 +00:00
John Colvin 795062864d fix: Fix typo in permission filter comparison (change == to !=)
Bugs (fixed):
  * The orderbook and ladder blink/flicker when orders change if logged
    in as non-bts user.

    Cause: The permission filter acted as if the predicate itself
    changed everytime an order changed. As a result, it would fire one
    update to cleared all values, then fire another to add items that
    pass the "new" predicate.
2025-03-13 10:39:33 -04:00
John Colvin 1ff72e9444 fix (ui): Show fractional order qty in activity log
Also fix formatting - change "price @ qty" to "qty @ price"
2025-03-13 10:39:33 -04:00
John Colvin e13b5066a3 fix: Preserve fractional qty when modifying existing order in ticket 2025-03-13 10:39:33 -04:00
Mohammad Arham 5ba7901258 Fix: undo special case for btc swap and add ccp for swaps 2025-03-12 20:47:44 +00:00
Mohammad Arham bc6eb59110 Fix: Change cttype from optional to string 2025-03-12 20:45:27 +00:00
John Colvin 5ae5a5dcbf fix: Add switch case for PositionSide::BOTH in binance futs gw
In this case, the position is signed (unlike LONG and SHORT).
2025-03-12 14:55:56 +00:00
John Colvin 7966bcce77 fix: Change trade id from uint32 to int64 2025-03-12 04:27:54 +00:00
Mohammad Arham ff86b10895 Fix: temp fix to move okx btc swap to config for min tick 2025-03-11 20:35:24 +00:00
John Colvin ea3c0717d8 fix: Remove erroneous assert from binance usds futs gateway 2025-03-11 19:48:11 +00:00
John Colvin d0abca3fd9 Fix symbols and account alphaworx_prod config 2025-03-11 19:47:34 +00:00
John Colvin 7895fe7357 Remove taifex and glbx from NotSimExecution in conf profiles 2025-03-11 15:24:08 +00:00
Mohammad Arham 6f5f4f5cc2 Fix: okx excution working now 2025-03-11 14:25:42 +00:00
John Colvin 066a0ba693 ui: Use dark theme foreground in mini orderbook, fills popups
It was black in a couple places before, making it hard to read.
2025-03-10 14:47:58 -04:00
John Colvin c2b67b4813 fix: Check for null in orderbook root algo type filter 2025-03-10 14:47:58 -04:00
John Colvin ecad456a2d fix: Apply exp filter to popup grids in pnl window 2025-03-10 14:47:58 -04:00
Taha Afzal 2cb3cfdcdd Spreader's orders were hardcoded to be DAY, now it gets it from the parent 2025-03-10 17:22:08 +00:00
Taha Afzal 0ebc8e5b4b Orders in DB are deleted on server bounce 2025-03-10 15:42:12 +00:00
John Colvin 2072105c0f cleanup: Add using aliases to make code more concise 2025-03-10 14:53:07 +00:00
John Colvin d663c86aa0 improvement: Only load synth metadata from disk once in md dumper
Instead of every time a synth is dumped (i.e., do it lazily, outside the
loop body)
2025-03-10 14:53:07 +00:00
John Colvin 4a2dfa46a1 improvement: Print delimiter line when dumping secs to console 2025-03-10 14:53:07 +00:00
John Colvin 6e35db6a24 improvement: Apply filter to shared mem secs in md dumper
Previously, filter only applied to db securities (i.e., when --db flag
was used)
2025-03-10 14:52:39 +00:00
John Colvin b45dc3bc2d fix: Preserve create time when order is updated
Bugs (fixed):
  * Order create time mirrors last update time (it should never change).
2025-03-10 05:24:49 +00:00
John Colvin a1912907b8 Add brief readmes for sparkd config profiles 2025-03-10 05:24:49 +00:00
John Colvin b1b3dcdeb8 Add sim_dev config profile for sparkd 2025-03-10 05:24:49 +00:00
John Colvin 03dc8ef767 Add boto3 to py venv, so we can retrieve secrets from aws 2025-03-10 05:24:49 +00:00
John Colvin 975bf56c2a fix: Don't spam binance w/ listen key requests
Sleep for a few seconds before trying again on failure.
2025-03-10 05:24:49 +00:00
John Colvin 3f58c2ce84 Add script to install aws cli
The aws cli can be used to configure credentials in the shell in order
to retrieve secrets (e.g., production api keys for alphaworx, etc.).
2025-03-10 05:24:49 +00:00
John Colvin 96f28acf91 Add dev config profile for sparkd 2025-03-10 05:24:49 +00:00
John Colvin c2c2658e21 Add alphaworx_prod config profile for sparkd 2025-03-10 05:24:49 +00:00
John Colvin d6b8e359cd Expand environment vars in binance gw config 2025-03-10 03:05:59 +00:00
John Colvin 84a0850d95 Tweak binance_dev config profile
* Factor out repeated symbol list into SymbolLists entry
* Change "binance_dev" account to "BINANCE_DEV" in exe gw json
* Adjust log level
* Remove unused config:
  - ExchangeSubAccounts
  - JetFIX_Connection.max_order_msgs_per_window
2025-03-10 03:05:59 +00:00
John Colvin 4effdc4160 diag: Log when http buffers are resized in binance exe gws 2025-03-10 03:05:59 +00:00
John Colvin b9fe39f6e3 refactor: Make MDRecorder join the run thread in destructor
This wasn't broken, but detached threads bother me.
2025-03-10 03:05:59 +00:00
John Colvin b555850015 build: Package & deploy sparkd with docker compose 2025-03-10 03:05:59 +00:00
John Colvin 23794fa30d devcontainer: Add docker in docker
Also remove default port bindings in devcontainer (so the "docker in
docker" sparkd can use them). It's easy enough to manually bind ports
in vs code.
2025-03-08 05:20:08 +00:00
John Colvin 90b5a309a3 cleanup: Make a couple fns const
Probably a typo, since these fns don't mutate anything.
2025-03-08 05:20:08 +00:00
John Colvin 07beda3fc6 fix: Support fractional show qty in iceberg orders 2025-03-07 20:42:24 +00:00
Taha Afzal e3c1ea70f2 Spreader orders can now be entered in fractional qty 2025-03-07 05:24:39 +00:00
Mohammad Arham 93b93969f5 Add: config to control databento md better 2025-03-06 02:44:40 +00:00
Mohammad Arham 0a10111846 Small changes to make cboe md work 2025-03-06 02:44:07 +00:00
John Colvin eee00cc407 diag: Integrate websocketpp with our logging system
* Unifies log message structure for improved readability
* Grants us runtime control over log levels via config
2025-03-05 20:48:14 +00:00
John Colvin 0eb58eaba8 fix (preemptive): Pass websocket io_context to PImpl ctr
The 'io_context' member var is accessed in the constructor (it must be
initialized before that happens).
2025-03-05 20:42:50 +00:00
John Colvin 12f6733d1e cleanup: Remove unnecessary account mapping in binance_dev conf 2025-03-05 18:04:04 +00:00
John Colvin 93a0984ed1 Filter out non usdc/usdt spots in binance_dev conf 2025-03-05 18:04:04 +00:00
John Colvin b7e9c393a0 fix: Don't sign binance listen key requests
The spots and usds futures apis ignore the unnecessary signature params,
but the cross margin api responds with an error.
2025-03-05 18:04:04 +00:00
John Colvin aa602b3fd6 tool: Add cross margin reqs to binance.env 2025-03-05 18:04:04 +00:00
John Colvin b4b8cabdae tool: Add listen key reqs to binance.env 2025-03-05 18:04:04 +00:00
John Colvin cfe06869b3 tool: Support empty query params in binance_orders_client.sh 2025-03-05 18:04:04 +00:00
John Colvin b177ed1cc0 fix: Include listenKey param in listen key refresh req (binance)
The cross margin api requires this. Spots and futures apis don't, but
including it for them is harmless. I also changed the response json impl
to treat the 'listenKey' field as optional (it's omitted in the cross
margin api).
2025-03-05 18:04:04 +00:00
John Colvin ff17a64933 cleanup: Remove unnecessary includes 2025-03-05 18:04:04 +00:00
John Colvin 81a1fe11f6 feat: Add binance gw for cross margin orders
Spots only
2025-03-05 18:04:04 +00:00
John Colvin ad5bf88fcf refactor: Rename user_data_streams dir, ns without plural 's'
There is one user data stream for Binance Spots, and another for Usds
Futures. We model both of these user data streams in separate folders,
so each "user_data_stream" dir represents a single stream.
2025-03-05 18:04:04 +00:00
John Colvin e15f155ac9 refactor: Abstract out common binance gw code
For all sub-venues to use
2025-03-05 18:04:04 +00:00
John Colvin 6d6822cd65 refactor: Rename binance exe gw filenames so they are unique
The debugger gets confused when a particular lib contains multiple
source files with the same name (in different dirs).
2025-03-05 18:04:04 +00:00
John Colvin ace0c70516 fix: Trim account name string when converting to Fill proto 2025-03-05 18:04:04 +00:00
John Colvin e9e5059bc2 fix: Disable CURLOPT_FAILONERROR to always get response body
Even when the http error code indicates failure. The payload may contain useful
information about the error.
2025-03-05 18:04:04 +00:00
John Colvin cde72f51a0 Improve logging/error reporting in binance execution gw
In the process, consolidate binance exe report stores into single class.
2025-03-05 18:04:04 +00:00
John Colvin e1fd49ae32 cleanup: Specify bts account directly in binance gw config
This eliminates the need for an ExchangeSubAccountResolver.
2025-03-05 16:00:43 +00:00
John Colvin 274f3f98e4 cleanup: Replace includes w/ fwd declares in header 2025-03-05 16:00:43 +00:00
John Colvin a4b7d84318 fix: Reject orders w/ invalid TimeInForce at binance
Do this internally (before sending them to the exchange)
2025-03-05 16:00:43 +00:00
John Colvin be17205094 fix: Report internal reject msgs to ExecutionReport
For Binance execution gateways (spots and usds futures)
2025-03-05 16:00:43 +00:00
John Colvin 6ef9bee8e4 Add reconnect behavior to WebsocketClient 2025-03-05 16:00:43 +00:00
John Colvin 2c8b3563f1 cleanup: Perform basic init in WebsocketClient ctr 2025-03-05 16:00:43 +00:00
John Colvin 71f7e64ccb Move config profiles dir to server/sparkd 2025-03-05 16:00:43 +00:00
John Colvin c31b44ecfb diag: Log when config server starts and show url 2025-03-03 19:32:16 +00:00
John Colvin 19efb77e07 tool: Add some usds futures requests to binance.env 2025-02-24 15:12:45 +00:00
John Colvin 76de640421 diag: Show Binance sub-venue in log message prefix
Otherwise it's hard to tell which Binance venue the log is about (e.g.,
spots, usds futures, etc.).
2025-02-24 06:16:22 +00:00
John Colvin fb030742d3 Clean up binance_orders_client.sh a bit, add docs 2025-02-24 06:06:15 +00:00
John Colvin 73608f1b45 perf: Run each ccapi md session on its own thread 2025-02-24 06:04:52 +00:00
John Colvin 58aebe7002 diag: Reduce log noise in CCApiMarketDepthAdaptor 2025-02-24 06:04:52 +00:00
John Colvin 299cb0b29e diag: Log when curl_global_init/cleanup is called
It should only happen once for the whole app (so it shouldn't be noisy).
2025-02-23 20:08:52 +00:00
John Colvin 06663f711e improvement: Only call curl_global_init/cleanup once
Avoids unnecessary overhead (plus their docs say it only needs to be
done once for the whole app). These fns have "global" in their name for
a reason.

https://curl.se/libcurl/c/curl_global_init.html
2025-02-23 20:08:52 +00:00
John Colvin 51479f4885 fix: Disable signal handling in curl
This avoids a strange stack corruption bug related to set/longjmp.

https://stackoverflow.com/questions/9191668/error-longjmp-causes-uninitialized-stack-frame
2025-02-23 20:08:50 +00:00
John Colvin 5b520ba241 cleanup: Get rid of custom fmt::formatter for security proto
Security proto objects are large, so we shouldn't pass them by value to
the log system. The custom formatter's presence makes this easy to do by
accident.
2025-02-23 19:05:42 +00:00
John Colvin f0651a5341 tool: Add flag to roll logs without running sparkd 2025-02-23 15:36:10 +00:00
John Colvin 897e0990a2 diag: Improve logging in SecurityCache 2025-02-23 15:36:10 +00:00
John Colvin 30e1ae5c3c Add Binance execution to config profile 2025-02-23 15:36:10 +00:00
John Colvin efe83f81ec fix: Index live securities (as well as db ones) in SecurityCache 2025-02-23 15:36:10 +00:00
John Colvin 5fb21ada97 diag: Add sec id to PositionMap log 2025-02-23 15:36:10 +00:00
John Colvin 58edd07f6b fix: Check for empty string in strn fns 2025-02-23 15:36:10 +00:00
John Colvin 9d81354c3a Add binance_orders_client.sh for quick/easy troubleshooting 2025-02-23 15:36:10 +00:00
John Colvin 0f37be89a4 Fix typos in binance.env 2025-02-23 15:36:10 +00:00
John Colvin f6586fe636 Activate ccapi exchanges according to md config at runtime
Previously, the list of exchanges ccapi would activate was determined at
build time.
2025-02-23 15:36:08 +00:00
John Colvin 7827ccc0e7 Update externals to get ccapi v6.12.0 2025-02-23 15:35:35 +00:00
John Colvin af6a2acc0a perf: Send Binance md rest reqs on background thread 2025-02-23 06:10:36 +00:00
John Colvin 84abf59a55 feat: Add binance spots execution 2025-02-23 06:10:36 +00:00
John Colvin 2fc1d30bf1 Add binance_usds_futures_testnet config profile
To activate this config profile, run:

tools/sparkd_profile.sh binance_usds_futures_testnet
2025-02-23 06:10:36 +00:00
John Colvin 4dcd5d63a1 tool: Add script to easily switch between spark.conf profiles 2025-02-23 06:10:36 +00:00
John Colvin 63e5697b20 Unify conf and conf_json dirs
Put all files (.conf and .json) in sparkdata/conf. This allows us to
implement config profiles via symlink.
2025-02-23 06:10:36 +00:00
John Colvin 8e5cb100a7 fix: Assign BTS account to ExecutionReport
Not external exch account
2025-02-23 06:10:36 +00:00
John Colvin 938bee1817 Validate ExecutionReport before invoking callback 2025-02-23 06:10:36 +00:00
John Colvin d48af15480 diag: Log warning if ExecutionReport acct not same as order def 2025-02-23 06:10:36 +00:00
John Colvin e3b2e98cd9 fix build: Add JsonReader.cpp to client & api server builds 2025-02-20 00:55:48 -05:00
John Colvin ee53fb854c ui: Make buy/sell button bg darker in order ticket
The buttons looked washed out; too bright, yet pale.
2025-02-20 00:49:59 -05:00
Taha d36e2d61f6 Fixing PNL for both crypto and non crypto 2025-02-19 19:06:12 -05:00
John Colvin bfff3ea5fe fix (preemptive): Check for null sec in ExecutionReport::to_string
I don't think it's ever a nullptr in practice, but if that changes, this
fn shouldn't seg fault.
2025-02-19 23:14:18 +00:00
John Colvin 059c03d289 cleanup: Removing docker submodules again
...they're back. It's like Night of the Living Dead submodules!
2025-02-19 22:50:29 +00:00
John Colvin 8c561f7886 improvement: Pass account/order updates by move (not value) 2025-02-19 22:50:29 +00:00
John Colvin 288567d1eb cleanup: Pass JetFIX cfg directly to binance usds futs exe gw 2025-02-19 22:50:29 +00:00
John Colvin ecfc5405fe refactor: Move macro defined json fns to cpp file
Some fns are big (shouldn't be inlined); plus its best to avoid exposing
macros in headers.
2025-02-19 22:50:29 +00:00
John Colvin 8db34a2a11 Add json & fmt formatters for order & sec protos 2025-02-19 22:50:29 +00:00
John Colvin 91094c4d84 refactor: Make parse_uint support generic char iterator 2025-02-19 22:50:29 +00:00
John Colvin dae8c85d73 fix: Check strlen when making order/fill keys
Although the string data is stored in a fixed size array, it isn't
necessarily the full length.
2025-02-19 22:50:29 +00:00
John Colvin abdd98082f Move BrokerProxy do_work fn to cpp
Doesn't make sense to inline; it's too big.
2025-02-19 22:50:29 +00:00
John Colvin 2f6aa785ab Use object_pool wrapper to count allocations and assert if too many 2025-02-19 22:50:29 +00:00
John Colvin 7acf1f7043 diag: Improve logging in PositionMap 2025-02-19 22:49:30 +00:00
John Colvin 1c3c7a078a diag: Improve logging in binance usds futures exe gateway
Also propagate error msgs through the execution report (so we can see
them in the front end).
2025-02-19 22:49:30 +00:00
John Colvin 93ace52bfa diag: Periodically log ActorThread work cycle speed
So we can better detect slowness, blockage, etc.
2025-02-19 22:49:30 +00:00
John Colvin b5d97c0b1b refactor: Consolidate ExecutionGatewayProvider/Factory code
It's easier to read and manage code when you're not constantly jumping
to and fro across a bunch of files.
2025-02-19 22:49:30 +00:00
John Colvin 284aa53ad4 Add script to run sparkd and roll over log w/ timestamp suffix
So each run gets its own log file
2025-02-19 22:49:30 +00:00
John Colvin 8a9952f52d diag: Improve logging in ServiceBridge 2025-02-19 22:49:30 +00:00
John Colvin 748aafaab3 cleanup: Remove unnecessary includes 2025-02-19 22:49:30 +00:00
John Colvin 3ba30c70de cleanup: Normalize indentation in orderman_cfg.conf
It was all over the place before; unreadable
2025-02-19 22:49:30 +00:00
John Colvin e72f465999 diag: Improve logging in OrderManager 2025-02-19 22:49:30 +00:00
John Colvin f3d93f7749 fix leak: Replace object pool raw ptrs w/ shared ptrs 2025-02-19 22:49:30 +00:00
Mohammad Arham 8d142b8a74 Fix: forgot to push a file 2025-02-19 03:36:14 +00:00
Mohammad Arham 8210b9f35f Fix: change onix exe so it uses dispatch fix msgs 2025-02-19 03:33:00 +00:00
Mohammad Arham 12b20b05ce Fix: OKX executions sends er only when dispatch called 2025-02-18 16:02:10 +00:00
Mohammad Arham 72efbccdbd Fix: USDC swaps md working for okx 2025-02-14 23:02:49 +00:00
Mohammad Arham 33643e9eab Fix: make log resize work again 2025-02-14 22:59:35 +00:00
Mohammad Arham 0f6dc6f40b Fix: Typo in Okx execution 2025-02-13 23:38:27 +00:00
Mohammad Arham 8c778f5e41 Fix: Added tdmode to config for okx execution 2025-02-13 23:32:53 +00:00
Mohammad Arham f308654200 Fix: okx execution fix large spreader orderd 2025-02-13 23:27:32 +00:00
Mohammad Arham bdf5b980fc Add: config for sim trading 2025-02-13 22:06:23 +00:00
Mohammad Arham 914ac597cd Vesrsion: Update to v2.2.5 deploying to jame prod 2025-02-13 14:40:27 +00:00
Mohammad Arham 4aa6a77680 Fix: OKX execution works as long as spreader not to big 2025-02-13 06:09:43 +00:00
Mohammad Arham 6b59dd84ee Fix: Ordermanager will not try to remake orders from er after restart 2025-02-13 06:09:01 +00:00
Mohammad Arham 4e2c5f2d17 Fix: Okx USDT perps fix re added 2025-02-13 06:08:27 +00:00
Mohammad Arham 9a1b94a1b0 Add: fill id to okx execution report 2025-02-13 01:13:50 +00:00
Mohammad Arham 13b3c55771 Change: lst msg only entered if error 2025-02-12 23:13:59 +00:00
Mohammad Arham d0a6fcdb9c Add: Stricter Assert if websocket goes down okx execution 2025-02-12 22:23:53 +00:00
John Colvin 1eb13028c1 ui: Get qty display settings from md instead of config 2025-02-12 15:59:51 -05:00
John Colvin 424e5ff16b Get Spark version at runtime via reflection
So it doesn't need to be hardcoded per release
2025-02-12 15:59:51 -05:00
John Colvin bed389885b Support qty tick size 10e-9
Some spots at OKX need this (e.g., BTC-AED)
2025-02-12 20:42:28 +00:00
John Colvin 85cf25a57a fix: Get min qty and min increment from correct fields in okx json
"lotSz" represents min qty, and "minSz" represents min qty increment. We
had them backwards before.
2025-02-12 20:36:40 +00:00
John Colvin 61471d4675 diag: Show qty info fields in FixedSecurity json 2025-02-12 20:34:48 +00:00
John Colvin d83435d49d Move FixedSecurity to_json fn to cpp
Doesn't make sense to inline; it's too big.
2025-02-12 20:34:47 +00:00
John Colvin 582fc10dce Add get_binance_md.sh for quick/easy troubleshooting 2025-02-12 20:34:47 +00:00
John Colvin 5969985d24 cleanup: Remove unnecessary includes 2025-02-12 20:34:47 +00:00
John Colvin fabe7d665c devcontainer: Install clang-format extension 2025-02-12 20:34:47 +00:00
John Colvin 7ce75bb8e7 devcontainer: Increase ram and shared mem
In order to support large symbol sets for Alphaworx
2025-02-12 20:34:47 +00:00
Mohammad Arham b8e1c3cd60 Add: Fix build Issue 2025-02-12 19:48:52 +00:00
Taha 4909944694 Fixing PNL for perps (its base don mid market now) 2025-02-12 11:20:55 -05:00
Mohammad Arham 7258af09b4 Add: Basic Okx execution working 2025-02-12 11:55:50 +00:00
Mohammad Arham 7f2ce6c1a9 Add: Okx execution cfg 2025-02-12 11:06:45 +00:00
Mohammad Arham 4835725e1c Add: diag logging to gttp client 2025-02-12 11:06:09 +00:00
Mohammad Arham 6a9e8de475 Deployment: Updating version numbers 2025-02-11 05:06:21 +00:00
Taha Afzal 4639951acc Fixing Sprader's reportin of its filled qty 2025-02-11 03:04:30 +00:00
Taha d8de211aac Front end does NOT filter nay CBOE or CME expirations 2025-02-10 17:49:14 -05:00
John Colvin 87394bc60b ui: Increase Currency col width so filter icon isn't clipped 2025-02-10 15:31:31 -05:00
John Colvin beba30f65c fix (ui): Remove temp hack that assumed synth qty always notional 2025-02-10 15:31:31 -05:00
John Colvin 2d58424d8f ui (mview): Hook up currency filter in vm
Make it a discrete values filter (listbox) while we're at it. This seems
more practical than regex.
2025-02-10 15:31:31 -05:00
John Colvin d1bbfa3791 Revert batch subscribe change in Binance 2025-02-10 19:59:42 +00:00
John Colvin aab17f460f cleanup: Remove docker submodules again
They just keep coming back.
2025-02-10 19:59:32 +00:00
John Colvin 461ef53322 devcontainer: Clean up and simplify
* Remove mounted dirs (the repo is automatically persisted in a volume)
* Remove user specific shell env initialization scripts (they're more
  trouble than they're worth, often break the devcontainer build)
* Remove redundant settings already defined in settings.json
2025-02-10 16:55:53 +00:00
Taha Afzal 2486bc90b2 Spreader is hooked to the priceCal dropdown while creating the spreader 2025-02-10 03:10:11 +00:00
John Colvin 1c5cbaf60b Change: Update version to 2.2.4-1 2025-02-08 13:19:41 -05:00
John Colvin b8de447cfb fix (pnl ui): Assume rows w/ exp DateTime.MinValue are Spots
Not the most elegant fix, but it'll do for now.

Bugs (fixed):
  * The Pnl window groups perpetual futures with spots
2025-02-08 13:18:27 -05:00
Mohammad Arham 8bfc2d40f9 Update: V2.2.4 pnl working now 2025-02-08 12:43:13 -05:00
Taha c09fd71c94 Fixing PNL for spots 2025-02-08 06:55:07 -05:00
Mohammad Arham f3b037553e Add: Batch subs in binance sub 2025-02-08 06:44:10 +00:00
Taha Afzal d386d93166 SpreaderChildOrder::on_order_udpate, changing an asserrt to an error lgo to monitor condition 2025-02-07 15:06:16 +00:00
Mohammad Arham 5217742c71 Add: SendingTime tag to cboe execution 2025-02-07 12:26:11 +00:00
Taha c59ec95460 Sheets and spreadbox theos can now optionally be set to market mid 2025-02-06 17:42:12 -05:00
Mohammad Arham 70f01583ec ADD: CBOE TIME and SALES working 2025-02-06 20:42:58 +00:00
Mohammad Arham 66d2f9eb63 Add: Quote algo updates, theos removed 2025-02-06 03:08:46 +00:00
John Colvin 4625bed8b8 Change: Update version to v2.2.3-1 2025-02-05 17:01:11 -05:00
John Colvin f18fb332b5 fix (orderbook): Make ColumnKeys enum 64bit
We rely on bit flags to indicate "dirty" columns in the vm. Need to do
this now that we have > 31 columns.
2025-02-05 17:01:11 -05:00
John Colvin 8746a6f5ca fix (orderbook): Refresh Notional Value view when it changes in vm 2025-02-05 16:30:13 -05:00
John Colvin 702d47abb5 fix (orderbook): Fix typos in default settings for Notional Value 2025-02-05 16:29:29 -05:00
John Colvin bf2a54717c ui (orderbook): Add Filled Notional Value column 2025-02-05 16:13:34 -05:00
John Colvin 9db779fb25 fix (hack): Assume synth quantities are always notional values 2025-02-05 16:07:07 -05:00
Mohammad Arham f55ddec708 Add: Vesrion logs to bothserver and client 2025-02-05 09:50:33 -05:00
Mohammad Arham 6e942dd2d4 Change: Updated version to v2.2.3 2025-02-05 08:38:31 -05:00
Mohammad Arham 142310a17a Add: SPXW to default for cboe 2025-02-05 12:16:47 +00:00
John Colvin 7f99a89a95 ui (fills): Add notional value column 2025-02-05 00:00:41 -05:00
John Colvin bfce663b4b fix (orderbook): Hook up notional val filter in vm, persist settings 2025-02-04 23:42:58 -05:00
John Colvin 33c743643d fix (orderbook): Include fractional qty in notional val 2025-02-04 23:34:47 -05:00
Taha Afzal 858e0a389b Fixed the issue where a notioanal quoter would send a 0 qty order 2025-02-05 04:16:53 +00:00
Taha Afzal 9c3bb85674 Notional qty handling in spreader 2025-02-05 04:16:53 +00:00
Taha Afzal f4930e8cd4 Added notional to PriceCalc type for the sprader, added code to compute notional books in SpreaderUtils 2025-02-05 04:16:53 +00:00
John Colvin f21e7f3602 ui (orderbook): Show synth notional value in terms of first leg 2025-02-04 16:54:37 -05:00
John Colvin b56c35aca4 ui (ladder): Show synth notional value in terms of first leg 2025-02-04 16:54:37 -05:00
John Colvin e6ac83196e fix (benign): Actually dispose _vm_sub in LadderGridHost 2025-02-04 16:54:37 -05:00
John Colvin 7b6f74fc4a cleanup: Get rid of 'mimic tt' ladder config
This config was leftover from custom DJ work. We no longer need it.
2025-02-04 16:54:37 -05:00
John Colvin f754953fac cleanup: Remove duplicate equality check 2025-02-04 16:54:37 -05:00
Taha 2dd1143d9f Fixed spx spreadbox theos 2025-02-04 16:31:17 -05:00
Mohammad Arham e1ee3275d8 Add: Filter secs upto n months databento 2025-01-31 21:46:11 +00:00
John Colvin 2549e406f3 fix: Compute notional value correctly when ticks per row > 1
It's the sum of price * qty for each level in the row. Previously, we
were multiplying the total qty by the same price (smallest in the row).
2025-01-29 16:28:28 -05:00
John Colvin d5024f1858 fix build: Don't check if unsigned int < 0 2025-01-28 20:20:06 +00:00
John Colvin 3623ac96db fix: Multiply array size by sizeof(T) 2025-01-28 20:19:51 +00:00
John Colvin 19834625f9 fix: Don't fall through switch case 2025-01-28 19:59:32 +00:00
John Colvin c8fc649b6b fix build: Pass config arg to cmake --build
For Ninja Multi-Config builds (i.e., api server and data streams)
2025-01-28 19:59:09 +00:00
John Colvin 6b1fc1c413 cleanup: Remove unused code 2025-01-28 19:59:09 +00:00
John Colvin 6f086532ac cleanup: Convert co2::TradeMessage in DomainSecurityUtils
Instead of domain::TradeRecord constructor. The domain types should have
minimal dependency on protos.
2025-01-28 19:59:09 +00:00
John Colvin dc66282225 cleanup: Rename UINT32 -> VALUE in qty macro names
Should have done this when we changed qty primitive from uint32 to float
2025-01-28 19:59:09 +00:00
John Colvin e2c74c0bb3 cleanup: Don't redefine CONTAINS macro 2025-01-28 19:59:09 +00:00
John Colvin e89d50eec1 cleanup: Move large fns from header to cpp 2025-01-28 19:59:08 +00:00
John Colvin 8bebbc278d cleanup: Get rid of 'using namespaces'
In headers, this is an objectively bad practice, since the type aliases
leak into dependent code and can cause unexpected naming conflicts. In
source files, it is debatable, but I prefer explicit aliases of the form
'using Foo = Bar'. The intentions are clear, and the resulting code is
naturally resistent to naming conflicts.
2025-01-28 19:59:08 +00:00
John Colvin 2e6d12c9c1 cleanup: Remove unnecessary includes 2025-01-28 19:59:08 +00:00
John Colvin 102a5e23ea vscode: Add Tests Sparkd entries to tasks.json 2025-01-28 19:59:08 +00:00
John Colvin 582dc791db vscode: Add Run Sparkd (Skip Build) entry to tasks.json 2025-01-28 19:59:08 +00:00
John Colvin afb35d8c25 Compute synth book qty in terms of first leg 2025-01-28 19:59:08 +00:00
John Colvin 3a32ed5fe6 Fix BookSide equality operators 2025-01-27 16:35:22 +00:00
John Colvin 4e01697327 Add equality and output operators to BookLevel 2025-01-27 16:25:32 +00:00
John Colvin 22032c1742 Add fmt::formatter for domain::Side
So we can pass it to LOG macros, etc.
2025-01-27 16:25:15 +00:00
John Colvin 0a9bce317c Add contract qty info to security proto (and FixedSecurity)
We should get this kind of security metadata from the exchange rather
than config.
2025-01-25 20:41:47 +00:00
Mohammad Arham 40e44db597 Fix: Added GCHandle in attempt to fix ui crash 2025-01-22 02:15:55 -05:00
Mohammad Arham 4a447e44e1 Add: Version to first log 2025-01-22 02:14:19 -05:00
John Colvin b1f4654b3c Fix benign typo in publish_spark.py 2025-01-21 17:28:50 -05:00
John Colvin 9d350334c0 fix build (installer): Fix install path typo in publish_spark.py 2025-01-21 17:28:05 -05:00
John Colvin ac597f505f fix build (installer): Set CMAKE_INSTALL_PATH for spark preset 2025-01-21 17:19:15 -05:00
John Colvin 147d9ceb1f ui: Enable net change price display for synths in ladder 2025-01-21 13:11:16 -05:00
John Colvin 377804dfb9 fix (ui): Don't crash on bad regex in grid filters
Wrap Regex construction in try/catch. This is from user input, so of
course we can't assume it will be valid.
2025-01-21 09:26:37 -05:00
John Colvin 0d26401961 fix: Preserve tick_factors in TickDisplaySettings "with" ext
Not sure this was a bug in practice, but it was definitely wrong.
2025-01-21 01:24:23 -05:00
John Colvin 889e226151 feat: Add setting to show notional values in ladder 2025-01-21 01:24:23 -05:00
John Colvin 986d53f4e0 ui: Make ladder size format text editable
This is the best of both worlds: the user can choose from one of the
canned presets in the dropdown, or specify a custom string format.
2025-01-21 01:24:23 -05:00
Taha d13ba2968a DateTimeExpanstionStream col name changes 2025-01-20 15:34:11 -05:00
John Colvin 1a192c8117 feat: Add setting to show ladder prices in basis pts from mid 2025-01-20 14:15:49 -05:00
John Colvin 5e36d4801c cleanup: Remove redundant if/else code 2025-01-20 13:31:41 -05:00
John Colvin 2cf6411ca7 fix: Send exchangeInfo req via our HttpClient instead of ccapi
Bugs (fixed):
  * We get a boost beast exception about the read limit being exceeded
    when requesting securities from Binance prod url (testnet works).
2025-01-19 14:21:11 +00:00
John Colvin e99df129d5 cleanup: Remove erroneous include 2025-01-18 22:54:06 +00:00
John Colvin d07c01bd17 ui: Support ladder ticks-per-row setting for synths
The ticks-per-row control was likely hidden by accident in the first
place. I'm guessing the original intent was to only hide the Price Terms
control for synthetics. At the time, there were no other controls in the
group box, so it made since to hide the whole thing. Some time later, we
added the ticks-per-row setting to the same group box, and forgot to
make the groupbox visible again.
2025-01-17 13:11:09 -05:00
Taha Afzal d69673c524 Previous change was not setting the create time for orders, fixing that + changign one log level to Dag 2025-01-17 07:00:57 +00:00
Taha Afzal 4ee595cdaf Fixing the issue were fractional fills on a working order could result in overfills being reported (it was only a reporting issue) 2025-01-17 06:38:38 +00:00
Mohammad Arham 6fcaf07df0 Fix: binance execution working on sim 2025-01-17 00:59:22 +00:00
Taha Afzal 492d48d886 Added qty_multiplier to spreader.proto 2025-01-16 20:18:26 +00:00
Taha Afzal b6a56e768b Adding config boolan config publish_boostrap_books_only to MarketDataReplayConfig which allows MDReplayer to only publish the bootstrap of all the books 2025-01-16 20:18:26 +00:00
Taha Afzal 3e2b5976a8 Minor changes and ocmments, to allow for fractional qtys 2025-01-16 20:18:26 +00:00
Mohammad Arham edd3f6cbd6 FIX: Orderbook quantity display fixed 2025-01-15 14:47:09 -05:00
John Colvin 2e9347341b fix: Don't throw ex just because leg qty is 0
ContractLegEnumerable shouldn't be responsible for security validation.
2025-01-14 12:58:58 -05:00
John Colvin 2061e38349 fix: Hook up mview venue filter in vm 2025-01-13 00:11:43 -05:00
Mohammad Arham 650dd57b6d FIX: increase max symbo count from 32 to 1024 2025-01-13 04:42:13 +00:00
Mohammad Arham 82747f7dc0 Fix: OKX perp swaps are same as futures now 2025-01-13 04:41:29 +00:00
John Colvin 04b26904a3 ui: Sort exchanges in grid filter dropdown 2025-01-12 15:10:20 -05:00
John Colvin f123e4c72c ui: Add Exchange col to mview 2025-01-12 15:10:20 -05:00
John Colvin b887cbebab fix: Actually capture emumba deribit cfg obj by value
The previous "fix" didn't actually work because, although the lambda
captured the obj by value, the thread captured the lambda by reference!
2025-01-09 16:53:22 +00:00
John Colvin 14e975bc7e vscode: Add Spark (Skip Build) entry to tasks.json 2025-01-09 11:23:30 -05:00
John Colvin 064f557057 ui: Sort accounts in ladder/ticket dropdown 2025-01-09 11:23:30 -05:00
John Colvin 4d106b5e6c ui: Fix alignment issues in order ticket 2025-01-09 11:23:30 -05:00
John Colvin 9fbeaf0d68 ui: Make TickUpDown style match default (dark) Button
* Set BorderThickness to 0
* Use same mouse-hover background as Button
2025-01-09 11:23:30 -05:00
John Colvin 4018ac8b78 ui: Add tooltips to order ticket 2025-01-09 11:23:30 -05:00
John Colvin 81c9503300 ui: Apply dark theme to order ticket buttons 2025-01-09 11:23:30 -05:00
John Colvin 477210926d ui: Fix text color in algo popup 2025-01-09 11:23:29 -05:00
John Colvin 0aa48a79a9 ui: Remove single quotes from tooltip
It looked busy
2025-01-09 01:38:26 -05:00
John Colvin 9e71c7af02 ui: Add tooltips to ladder 2025-01-09 01:38:26 -05:00
John Colvin 4647751409 vscode: Add Spark Test entry to launch.json, tasks.json 2025-01-09 01:03:33 -05:00
John Colvin a3087b874b cleanup: Remove unused code 2025-01-09 01:03:32 -05:00
John Colvin 5b2f5c5c8f Don't throw/catch type exception needlessly 2025-01-09 01:03:32 -05:00
John Colvin 479227090e ui: Remove overly rigid validation for "ticks per row" setting 2025-01-09 01:03:32 -05:00
John Colvin 2dfcf320f5 fix: Refresh ladder levels when "ticks per row" changes 2025-01-09 01:03:32 -05:00
John Colvin b4c7213cb2 fix: Refresh ladder prices in view when they change
Bugs (fixed):
  * Sometimes the prices in the left panel of the ladder get stale
2025-01-09 01:03:32 -05:00
John Colvin c7dfd69b90 Consolidate tick rounding functions
Too many functions were performing essentially the same service:
rounding ticks. It was confusing.
2025-01-09 01:03:32 -05:00
John Colvin 4fdc866485 build: Propagate py script exit codes back to the shell
I noticed the build cmds were broken on Windows because the debugger
would still start even when the preLaunchTask (build) failed!
2025-01-09 01:03:32 -05:00
John Colvin f5d5ca9a1c ui: Use appropriate colors in font picker control
We must have missed this when we switched to dark theme.
2025-01-09 01:03:32 -05:00
John Colvin cfafcf77b9 ui: Use appropriate text color in ladder settings dialog
We must have missed this black text when we switched to dark theme.
While we're at it, freeze the brushes it uses, since they are stored in
a StaticResource which could potentially be shared by multiple controls.
2025-01-09 01:03:32 -05:00
John Colvin 8ebe783139 fix: Clear low/high lines in ladder when scrolled out of view 2025-01-09 01:03:32 -05:00
John Colvin 1851a96a58 vscode: Add Spark (Skip Build) entry to launch.json 2025-01-09 01:03:32 -05:00
John Colvin 0b334ef870 fix: Remove erroneous early exit condition in Ladder render
Bugs (fixed):
  * The ladder doesn't always render ask prices
2025-01-09 01:03:32 -05:00
John Colvin ee811a729a ui: Make ladder price line colors match button text 2025-01-09 01:03:32 -05:00
John Colvin cb15be276d ui: Show bid, ask, mid lines in ladder by default 2025-01-09 01:03:32 -05:00
John Colvin 7d5af6729b ui: Show bid, ask, mid prices in ladder left panel 2025-01-09 01:03:31 -05:00
John Colvin e5679cf082 ui: Make ladder price links prettier
* Change them from hyperlinks to buttons
* Add mouse hover animation
* Align text to the right (so decimal places line up)
2025-01-09 01:03:31 -05:00
John Colvin 98f89b9ad4 fix: Capture emumba deribit cfg by value in thread body
Bugs (fixed):
  * Sparkd occasionally assert crashes on startup because it fails to
    read emumba deribit config.

    Cause: This is a simple race bug. The config obj isn't captured by
    value, so it can be destructed before the thread references it.
2025-01-08 19:03:01 +00:00
John Colvin ba4f8f67e3 fix: Disable binance usds futs symbol filter config
This was a premature optimization, and has become a burden now that we
need to subscribe to large symbol sets for Alphaworx.
2025-01-06 05:00:04 +00:00
John Colvin 9c78380490 fix build (gcc rel): Don't fallthrough switch cases 2025-01-06 03:52:25 +00:00
John Colvin f6166f0674 fix: Show iceberg show qty in algo params grid
Bugs (fixed):
  * In the ladder, you can't view/edit the iceberg show quantity.

  Cause: No view template was defined for nullable double params. Most
  likely, we changed the show qty in the vm from double to nullable
  double at some point, and forgot to reflect this change in the view.
  An easy mistake to make as it would not have broken the build.
2025-01-05 15:58:29 -05:00
John Colvin 6334a902e7 fix: Reclaim keyboard focus when mview popup is clicked 2025-01-05 15:29:11 -05:00
John Colvin 082ca62fff fix: Focus price textbox when mview order ticket popup opens 2025-01-05 15:18:46 -05:00
John Colvin 9dbd8dd7c6 fix: Set focus through FocusScope element if one exists 2025-01-05 15:18:46 -05:00
John Colvin 8f7a4d0df6 Fix typo in AutoFocusTargetProvider dependency prop 2025-01-05 15:18:46 -05:00
John Colvin f372dd56b3 fix: Return synthetic name in get_security_desc
If the security is a synthetic (of course).

Bugs (fixed):
  * Changing limits in the risk ui causes sparkd to assert crash
2025-01-05 20:15:10 +00:00
John Colvin 86eba20d61 build: Make compiler/build type case insensitive 2025-01-05 06:25:11 +00:00
John Colvin 35a985280d fix: Run heartbeat timer in MarketDataGateway
This is why we were getting those heartbeat asserts. Previously, only
ExchangeSimApplication would start this timer. Since MarketDataGateway
doesn't share its MDProducer with ExchangeSimApplication, it must start
one itself.
2025-01-03 16:59:07 +00:00
John Colvin f5e1b3319c cleanup: Don't write to cout in SparkDataDirectory
Don't need that noise.
2025-01-03 16:59:07 +00:00
John Colvin 65c3948e4f cleanup: Remove unused code 2025-01-03 16:59:07 +00:00
John Colvin 002bdff9a3 fix: Don't parse non-existent json files in SparkDataDirectory
Bugs (fixed):
  * Sparkd assert crashes if binance_usds_futures_execution.json file
    doesn't exist
2025-01-03 16:59:07 +00:00
John Colvin bb6e5dd548 diag: Fix sparkd log path in show_last_run.sh 2025-01-03 16:59:07 +00:00
John Colvin 7c1aed3339 fix build (api server): Remove old cpps from source file list 2025-01-03 16:59:07 +00:00
John Colvin 22ae51fb99 build: Clean up build py scripts 2025-01-03 16:59:07 +00:00
John Colvin a53d347f81 fix build (warns): Update cmake min version to 3.10
Versions < 3.10 will soon be deprecated (we just started getting
warnings about it).
2025-01-03 16:59:07 +00:00
John Colvin 838dbcd886 build: In py build scripts, exit with code 1 on failure
Previously, they would exit with 0 no matter what happened.
2025-01-03 16:59:07 +00:00
John Colvin 5ed2309d22 fix: Add switch case for VENUE_BTS in VenueIndex 2025-01-03 16:59:07 +00:00
John Colvin 4d41704dd2 build: Configure admin webapp build entirely in CMakeLists
Get rid of build_admin_web_app.py
2025-01-03 16:59:07 +00:00
John Colvin bd1000e518 build: Get rid of explicit "targets" in CMakePresets for sparkd
So we don't have to worry about keeping it synchronized with the actual
targets in the build (just one more thing that can break). You can build
specific targets via the cmake cli anyways.
2025-01-03 16:59:07 +00:00
John Colvin dd4aa3c2ed build: Update fable in dotnet-tools.json 2025-01-03 16:59:07 +00:00
John Colvin fee9d3f597 build: Update webpack-cli in admin webapp 2025-01-03 16:59:07 +00:00
John Colvin 416f9aef31 vscode: Add Sparkd Test to launch.json 2025-01-03 16:59:07 +00:00
John Colvin 48f5e4c201 vscode: Fix sparkd launch.json 2025-01-03 16:59:07 +00:00
John Colvin 4438b4ca8d feat: Support fractional quantities in synthetic book 2025-01-03 16:59:07 +00:00
John Colvin 73356e0d61 cli: Add cmd to print security info from the db to console
Usage: sparkd md dump --db
2025-01-03 16:59:07 +00:00
John Colvin 4a285fa581 cleanup: Make fn const 2025-01-03 16:59:07 +00:00
John Colvin cfa82c2177 cleanup: Remove erroneous fwd declared class 2025-01-03 16:59:07 +00:00
John Colvin 0410a0431a fix: Encode exp in valid date int when storing in sqlite
The strange bit shifting we were doing before doesn't support large
dates.

Bugs (fixed):
  * Synthetics with Binance perpetual future legs don't appear on the
    front end after sparkd restarts.

  * Cause: Exp dates for Binance perpetual futures aren't properly
    encoded in the database. As a result, when loaded from disk, they
    are mistakenly identified as expired, along with any synthetics that
    have them as legs.
2025-01-03 16:59:07 +00:00
John Colvin 02843f14ff cleanup: Get rid of trivial fn that's only used in one place
Move the logic into the function that used to call it.
2025-01-03 16:59:07 +00:00
John Colvin f1f1d4259c diag: Add logs around security discovery in MDConsumer
This is multi-threaded event driven code. Without descriptive logs in
the right places, diagnosing problems is difficult and tedious.
2025-01-03 16:59:07 +00:00
John Colvin 71fc43af68 cleanup: Flatten nested if blocks with continue statements
Easier to read
2025-01-03 16:59:07 +00:00
John Colvin 350144ffd5 fix: Use security desc to get unique id (along with venue, type)
I'm guessing this typo went unnoticed because it didn't break the build
(another arg of the same was being used instead).
2025-01-03 16:59:07 +00:00
John Colvin da227a5550 Support synths at Binance, Binance USDS Futures, Deribit, and Okx 2025-01-03 16:59:07 +00:00
John Colvin 0c92cf3a87 Add double ops to IntPrice 2025-01-03 16:59:07 +00:00
John Colvin 1188af391e Add trivial fns to TimeStamp for convenience
* += and -= operators
* 'date' fn
* 'to_date_int' fn
2025-01-03 16:59:07 +00:00
John Colvin 0bb85cf915 refactor: Change month and day params from uint32 to uint8
They only need to hold values 1-12 and 1-31, respectively. A single byte
is more than sufficient. Also add ymdhms TimeStamp constructor.
2025-01-03 16:59:07 +00:00
John Colvin d77f5996fe cleanup: Make a couple TimeStamp fns const 2025-01-03 16:59:07 +00:00
John Colvin 940c41a274 Add int32 arithmetic operators to domain::Price 2025-01-03 16:59:07 +00:00
John Colvin e671960dc3 Add double arithmetic operators to domain::Price 2025-01-03 16:59:07 +00:00
John Colvin 8fa34b6b39 fix: Multiply additive factors by exponent in domain::Price
We must not have been using these operators because the implementation
was very broken (yet it doesn't seemed to have caused any bugs).
2025-01-03 16:59:07 +00:00
John Colvin f9d5429b5b cleanup: Remove unused code 2025-01-03 16:53:05 +00:00
Mohammad Arham 2c342482eb Merge branch 'development.crypto' of bitbucket.org:bluetradesys/spark into development.crypto 2025-01-02 15:30:13 -05:00
Mohammad Arham 3aefac26c2 fix: Timer condition was incorrect 2025-01-02 20:15:38 +00:00
John Colvin 1554594cdd diag: Throttle noisy log in Ladder 2025-01-02 12:15:22 -05:00
John Colvin 727a0f38b5 fix: Prevent arithmetic overflow when converting long to int in Ladder 2025-01-02 12:13:58 -05:00
John Colvin 7a0e8cdb26 fix: Properly format spread/synth leg qty in generated desc 2025-01-01 13:12:17 -05:00
John Colvin a4e97b04d7 fix: Don't propagate security criteria changes to other windows
Bugs (fixed):
  * Security criteria changes in mview and time/sales propagate to other
    windows of the same type.
2024-12-31 11:06:24 -05:00
John Colvin 463980a6ef Fix typo in get_binance_md.py 2024-12-29 18:37:54 +00:00
John Colvin 9b25857042 fix: Ensure "earliest_expiration" fn actually returns min exp
Previously, it assumed the first leg would have the earliest exp. While
this may be true for most securities, it isn't guarenteed by our data
model.
2024-12-29 13:26:44 -05:00
John Colvin ef19e7d76b fix: Don't assume all securities have expirations in pnl vm
Bugs (fixed):
  * PNL window crashes if data has Spots (i.e., securities without exps)
2024-12-29 13:17:17 -05:00
Taha Afzal 471faec2cb Added more etsts for fractional qtys 2024-12-28 08:31:16 +00:00
Taha Afzal ce96d42db8 Merging 2024-12-26 07:01:30 +00:00
Mohammad Arham 187894ca84 FIX: makes gateway factory work 2024-12-24 17:56:49 +00:00
John Colvin 63492c4575 fix: Remove erroneous assert in LadderRender 2024-12-21 23:24:52 -05:00
John Colvin e150c611f6 fix: Round fractional order qty to 6 decimal places
It was previously rounding to 2 decimal places, which isn't enough for
many crypto currencies (e.g., BTCUSDT at Binance)
2024-12-21 23:17:52 -05:00
John Colvin bb837d6c26 fix build: Trivial changes in DatabentoDataHandler 2024-12-22 04:00:23 +00:00
John Colvin 965e541ac8 Fix json structures and endpoints for Binance USDS Futures md 2024-12-22 04:00:23 +00:00
John Colvin 1b232aa610 feat: Add Binance USDS Futures execution 2024-12-22 04:00:23 +00:00
John Colvin 25439b094a improvement: Perform sec lookup in const time 2024-12-21 20:08:19 +00:00
John Colvin f927ef2c5e Add conf_json dir to spark data file tree
So we don't have to add proto files to the build for trivial config.
2024-12-21 20:08:19 +00:00
John Colvin d42389b75a Don't needlessly download cme config xml
When we aren't subscribing to cme md (i.e., no glbx symbols in spark
conf).
2024-12-21 20:08:19 +00:00
John Colvin 671cbcf03a Fix bts::Quantity string fmt so it includes fractional qty 2024-12-21 20:01:55 +00:00
John Colvin e589e23f41 Add py script to get md at binance
For quick/easy troubleshooting (much easier than doing stuff in c++)
2024-12-21 20:01:55 +00:00
John Colvin 11fadc0a3e Expose "run" fn in WebsocketClient
So it doesn't have to be hidden in a background thread
2024-12-21 20:01:55 +00:00
John Colvin b8c2d93866 Add ping/pong facilities to WebsocketClient 2024-12-21 20:01:55 +00:00
John Colvin 67a23dd196 Add open/close callbacks to WebsocketClient 2024-12-21 20:01:55 +00:00
John Colvin ff22c4eb5f diag: Change WebsocketClient log category to "Http"
A better fit than "Gen"
2024-12-21 20:01:55 +00:00
John Colvin 5addff4c50 cleanup: Remove redundant fn HttpRequest::perform
This was doing the same thing as HttpClient::send. I likely refactored
this function during development, then forgot to remove it.
2024-12-21 20:01:55 +00:00
John Colvin 142e1bd2da Add HttpMethod "DELETE"
In Binance's REST api, orders are canceled via DELETE requests.
2024-12-21 20:01:55 +00:00
John Colvin d05d91bbe7 diag: Log Http requests 2024-12-21 20:01:55 +00:00
Mohammad Arham 3a90ca9cb5 Add: Johns changes to sec oracle 2024-12-17 14:47:37 +00:00
John Colvin 85a46727be Improve c++ http client facilities 2024-12-11 19:28:36 +00:00
Mohammad Arham 624fd2c976 FIX: BUILD Error 2024-12-09 01:34:29 +00:00
Mohammad Arham 16d599d2d6 Add: OKX execution gateway connected 2024-12-08 20:14:16 -05:00
John Colvin c00e4fcb6b feat: Add Binance Coin Futures market data 2024-12-06 00:39:41 +00:00
John Colvin 03e19afe1d Fix qty display conf for BTC/ETH futs at Binance
Need to show 3 decimal places (qty tick size is 0.001)
2024-12-05 21:05:53 +00:00
John Colvin 058e11eadc fix build: Fix install path for sparkd 2024-12-05 18:31:36 +00:00
John Colvin 6ff52e7107 fix build: Add onixs libs again
Taha accidentally reverted externals
2024-12-04 16:56:46 +00:00
John Colvin ee4c28ed41 Port ws client over from cme-websocket-connector
Need this to implement execution at crypto exchanges (beginning with
Binance and OKX)
2024-12-04 16:56:46 +00:00
Mohammad Arham 50d26f0060 Merge branch 'development' of bitbucket.org:bluetradesys/spark into development 2024-12-03 09:52:09 -05:00
Mohammad Arham 36378e6074 Add:: Recording md to sql 2024-12-03 14:51:32 +00:00
John Colvin 8cde8ee6e1 build: Add script to publish the api server
This will build the app as a self-contained executable here:
build/Release/bin/net7.0/linux-x64/publish
2024-11-28 16:35:21 +00:00
John Colvin 4f8fad444e fix build: Add missing csproj deps to Spark.Api.Server.sln 2024-11-28 16:35:20 +00:00
John Colvin 832c645a30 build: Map cmake install dir to associated preset
Cpp bins are now installed to "install/<cmake_preset>/bin". For example,
"install/sparkd-release-gcc/bin", "install/spark-api-server-linux/bin", etc.
2024-11-28 16:35:20 +00:00
John Colvin 691343d9b6 feat: Add datastreams to spark api server 2024-11-28 06:14:00 +00:00
Taha 461cbad338 Adding FakeBBO stream 2024-11-27 13:36:14 -05:00
Taha fecbcbb6b6 Merge branch 'development' of bitbucket.org:bluetradesys/spark into development 2024-11-26 22:33:31 -05:00
Taha aab8e83543 Some rewrite of streams that fetch bars, and making the other business streams thin wrapper over stream primitives 2024-11-26 22:33:26 -05:00
Mohammad Arham 420b46741e ADD: Config for sql writer in mdrecorder 2024-11-24 19:14:45 +00:00
Mohammad Arham e8f65f95bd Wrapped proto write in function in mdrecorder 2024-11-24 19:13:36 +00:00
Mohammad Arham 0e893b9b5d Fix: Multiple Exchange data sources work without timee 2024-11-20 23:48:50 +00:00
Mohammad Arham 0593ae0320 Fix: Logging path was incorrect 2024-11-20 23:48:24 +00:00
Mohammad Arham 960149b9c5 Fix: Stupid bug on sleep time 2024-11-20 22:49:22 +00:00
Mohammad Arham b5f5f2f3d5 Merge branch 'development' of bitbucket.org:bluetradesys/spark into development 2024-11-20 17:21:45 -05:00
John Colvin bd8c97244a 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-11-20 22:17:08 +00:00
John Colvin cb187e6997 Interpret db strng param as name or path in SqliteStore ctr 2024-11-20 22:17:08 +00:00
John Colvin 4004ed2267 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-11-20 22:17:08 +00:00
John Colvin a00347ac3f Add ostream operator for Venue 2024-11-20 22:17:08 +00:00
John Colvin c4d08840bd Add ostream operator for SecurityType 2024-11-20 22:17:08 +00:00
John Colvin 84c0684b63 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-11-20 22:17:08 +00:00
Mohammad Arham bca8df6d99 Fix: Release Crash fixed still has timer 2024-11-20 22:14:48 +00:00
Mohammad Arham 98f8e58f3f Add optional tags to config 2024-11-20 22:12:06 +00:00
Mohammad Arham 76f18f3443 Fix: typo in fixed securities 2024-11-20 20:17:29 +00:00
Mohammad Arham b67d748ba1 removed: moved onix glbx to main controler thread 2024-11-20 06:58:14 +00:00
Mohammad Arham 0113721355 Add: Config for marex reconnect attemps 2024-11-20 06:29:41 +00:00
Mohammad Arham 715f7f7c70 Fix: Race condition causes crash not sure if fixed 2024-11-20 06:17:28 +00:00
Mohammad Arham 89955597c1 Add: Onix/Marex fix adapter, listener, and state handler 2024-11-20 06:16:58 +00:00
Mohammad Arham 96d9aae048 Add: IFIXGenericAdapter 2024-11-20 04:45:36 +00:00
Mohammad Arham f28d32946f Add: General Execution Gateway (between system and IFIXAdapter ) 2024-11-20 04:39:43 +00:00
Mohammad Arham 924efb2c3f Add: Added proto for marex fix config 2024-11-20 04:26:39 +00:00
Mohammad Arham 50abb1d784 Fix: Refactored to Switch Statement instead of if and aadded cboe 2024-11-20 04:24:51 +00:00
Mohammad Arham b5ef39ee4b Fix: Change default tick_config for taifed 2024-11-20 04:18:58 +00:00
Mohammad Arham 5b61b4fe69 Add: Accounts for CBOE Execution, subaccounts dont work 2024-11-20 03:22:18 +00:00
Mohammad Arham 2d8523ae67 FIX: Order cancel now working in emnative order 2024-11-20 03:18:31 +00:00
Mohammad Arham f0eef447d3 Add: Exchange parameter added to EMNAtive Order 2024-11-20 03:18:04 +00:00
Mohammad Arham 8604d5672c ADD: Comments for CME execution for later 2024-11-20 03:11:54 +00:00
Mohammad Arham 30822fb1f1 Fix: move start glbx onix to seperate thread 2024-11-20 03:09:07 +00:00
Mohammad Arham 826bbf76a9 Add: load_reference_data config for databento 2024-11-20 02:53:19 +00:00
John Colvin eb8c97a1b7 fix: Detect integer ticks of all sizes (not just 1)
Also don't divide by zero!

Bugs (fixed):
  * Spark crashes when opening a ladder with integer tick size of 5.
    This was first observed with TAIFEX futures.

    Cause: The ladder throws a DivideByZero exception when calculating
    the number of ticks per dollar. It isn't caught until it bubbles up
    to the scope in which 'Dispatcher.Run' was called. The catch handler
    then deliberately assert crashes.
2024-11-12 16:15:47 -05:00
John Colvin 5517c58724 fix (ui): Display trade time w/ microsecond precision
Was only showing milliseconds before
2024-11-12 11:42:23 -05:00
John Colvin e9bcdd0c65 fix build: Update Newtonsoft.Json to 13.0.3 in Spark.csproj 2024-11-12 10:35:51 -05:00
Taha 83b37c6661 Merge branch 'development' of bitbucket.org:bluetradesys/spark into development 2024-10-30 13:36:33 -04:00
Taha 6163887cd3 Bunch of CME queries are now working 2024-10-30 13:36:23 -04:00
Mohammad Arham 214641aa1e Add: cpp tp sec_common 2024-10-25 07:02:46 +00:00
Mohammad Arham 06bc7af232 FIx: Taifex md working 2024-10-25 06:59:52 +00:00
Mohammad Arham 36b6168dec Taifex State working 2024-10-18 21:13:56 +00:00
Taha f9aa9dd982 Merge branch 'development' of bitbucket.org:bluetradesys/spark into development 2024-10-15 23:48:34 -04:00
Taha 22f1ab44f9 Basic set of streams that can talks ot the LLM and get DSL back from few-shot prompt 2024-10-15 23:38:49 -04:00
John Colvin e4c87c267d Fix DateTimeConstant token regex for DataStreams
The previous regex was overly ambitious (and needlessly complex as a
result). The new regex is simpler, and doesn't impose bounds on month
and day ints, aside from requiring 1-2 digits.

Bugs (fixed):
  * The DataStreamExpressionInterpretter fails to parse certain date
    constants, such as "8/30/2024"
2024-10-15 11:46:58 -04:00
Mohammad Arham 86899a6ff0 FIX: TAifex state working 2024-10-14 17:19:03 +00:00
Adeel Khan 2324fd3ad2 CHANGE: Taifex State Mgmt 2024-10-14 20:59:34 +05:00
Taha 288b7712db Added and modified more streams to address teh CME NL queries 2024-10-09 13:59:01 -04:00
Mohammad Arham 8850bf4903 Remove: Assert in taifex code 2024-10-09 14:53:20 +00:00
Mohammad Arham 11112b41d1 Add: Missing config entry databento 2024-10-09 02:36:35 +00:00
Adeel Khan 2a98889b67 UPDATE: TaifexDataGateway 2024-10-09 02:18:28 +00:00
Adeel Khan 8060518a28 FIX: Removed Taifex Bugs 2024-10-08 21:29:44 +00:00
Mohammad Arham 68440d3df3 ADD: Config for one year security filter 2024-10-08 13:50:38 +00:00
Mohammad Arham 7d775afc4c Add: Taifex after hours ip change config 2024-10-08 13:49:36 +00:00
Mohammad Arham 50c7764ef7 Add: Databento security filter 2024-10-07 20:33:38 +00:00
Mohammad Arham fb8b2d28f3 Fix: DATABENTO live working 2024-10-07 20:05:38 +00:00
Mohammad Arham bcc2c4a514 CHANGE: Taifex Refactored 2024-10-07 16:26:12 +00:00
Mohammad Arham 9352298be0 Add: Taifex statehandler 2024-10-07 08:51:55 +00:00
Mohammad Arham 180bd11740 FIX: Taifex replay types of files handled 2024-10-06 21:31:34 +00:00
Mohammad Arham 57ea841381 ADD: i084 taifex 2024-10-06 20:31:07 +00:00
Mohammad Arham 7d9d176fa2 Change: Rename taifex files 2024-10-06 18:38:36 +00:00
Mohammad Arham a8f4ec07c8 Change: moved file paths to config for taifex file replay 2024-10-06 08:29:27 +00:00
Mohammad Arham 58c5be268f Add: Refactored taifex code to break it down 2024-10-06 08:01:22 +00:00
Mohammad Arham bf4859a2a9 Change: Refactored read binary file taifex 2024-10-06 07:28:12 +00:00
Adeel Khan db1cf93994 Add: Incremental Books 2024-10-04 23:23:54 +05:00
Adeel Khan ecb1c4fea0 Add: Taifex Trades 2024-10-04 23:23:41 +05:00
Mohammad Arham a513933044 Add: Exceptions handling for databento 2024-10-04 13:06:56 +00:00
Mohammad Arham 764d65b595 Remove: code to remove secuties 2024-10-03 12:06:55 +00:00
Mohammad Arham bc0d606252 Add: code to connect to Live databento 2024-10-03 12:03:48 +00:00
Mohammad Arham ceb8a68902 Add: databento repllay filename to cofig 2024-09-27 03:20:20 +00:00
Mohammad Arham 0b3183fd30 Add: added onix fix to lib to build dir 2024-09-26 16:23:19 +00:00
Mohammad Arham b6dbe37818 Add: entry for onix fix 2024-09-24 13:41:45 +00:00
Mohammad Arham c78b8bc8e1 Add databento to external 2024-09-24 13:37:57 +00:00
Taha Afzal 314f3e3715 Adding comments 2024-09-23 18:40:06 +00:00
Taha Afzal 26a1d5fc03 Creating scaffolding for incremental book updates in GeneralMarketDataListener 2024-09-23 18:39:12 +00:00
John Colvin 37e5003cf9 Merge remote-tracking branch 'origin/development.ps_linux' into development 2024-09-19 05:40:59 +00:00
John Colvin 07f3868ffc Add CBOE to spark admin webapp 2024-09-18 19:03:43 +00:00
John Colvin 46f0b17138 Add TAIFEX to spark admin webapp 2024-09-18 19:03:43 +00:00
Taha 33a8e06a3a Fixing implied vols for SPX (market data was getting divide dby the fwd) 2024-09-17 22:17:31 -04:00
John Colvin 74afdde8de fix build: Add ".list" to SymbolLists config
For new exchanges, TAIFEX and CBOE
2024-09-17 13:01:05 +00:00
John Colvin 0a92ad2eb1 fix (build): Add break statement to new venue switch cases
Namely, TAIFEX and CBOE
2024-09-17 13:00:14 +00:00
John Colvin 56d207c3f1 fix: Preserve vs exp sec type (Option) when computing implied vol
Because the exp keys in the data map have sec type Option.
2024-09-16 13:46:53 -04:00
John Colvin 9172e752e3 ui: Highlight launcher buttons when selected
Namely, the expandable menu buttons in Analytics shell module
2024-09-16 13:46:53 -04:00
John Colvin adc9f2acfc Replace trivial refs to ThreadedBlackboard w/ IBus 2024-09-15 23:45:15 -04:00
John Colvin 41d17e67d2 fix: Move accounts subscription to dispatcher thread
We update a collection that is bound to the view in the callback (mutation
ops throw if performed on a different thread).
2024-09-15 23:45:15 -04:00
John Colvin 5cacff073b fix: Check 'HasTimestamp' before accessing prop in man fill row
Pending adds (i.e., unpersisted new rows) don't have timestamps.
In such cases, the 'Timestamp' getter throws an exception.
2024-09-15 23:45:15 -04:00
John Colvin c8da92c250 Cache/index options for faster lookups in SystemContractData 2024-09-15 23:45:15 -04:00
John Colvin c4e76076e3 fix: Include venue w/ symbol when publishing interp greeks 2024-09-15 23:45:14 -04:00
John Colvin 6a715b9a68 Fix typo in comment 2024-09-15 23:45:11 -04:00
John Colvin 1f28940c95 fix: SelectorList.RemoveAt doesn't need 'convert_back' delegate
So don't throw an exception if it is null.
2024-09-15 23:45:11 -04:00
John Colvin ebff40b88f fix: Don't assume venue is in spread def string
Pass it as an argument to the parse fn. This should be fine for now, but
obviously a singular venue param won't work for cross exchange spreads.
2024-09-15 23:45:11 -04:00
John Colvin a6d14a3ac3 improvement: Move system contracts sub off of dispatcher thread
Also add 200ms throttle. Contracts shouldn't change that often, so we don't need
lightening speed here. Furthermore, such changes may trigger expensive cpu ops.

Note: this change also replaces refs to ThreadedBlackboard w/ IBus (the
former is somewhat tethered to the dispatcher thread, particularly by
its timer_callback).
2024-09-15 23:45:11 -04:00
John Colvin af96bcb9e3 fix: Pass symbol/venue from vs usage cfg to AnalyticsService proto 2024-09-15 23:28:59 -04:00
John Colvin 619702cb04 cleanup: Remove unused code 2024-09-15 23:28:59 -04:00
John Colvin 5baec19aff refactor: Index vol and theos data by symbol/venue tuple
Rather than just symbol, to avoid conflicts when the same symbol exists
at multiple exchanges
2024-09-13 10:50:23 -04:00
John Colvin 39ef30c1e3 cleanup: Remove redundant type VolSurfaceSymbolStructure
There is an identical type (in terms of prop types and corresponding proto indices)
called VolSurfaceSymbolRelationship that is used in more places.
2024-09-13 10:50:23 -04:00
John Colvin c2f2d28914 Move nested vm classes into own files
VolSurfaceSettingsEditor has too much code (still). It is hard to
navigate.
2024-09-13 10:50:23 -04:00
John Colvin e06bc3bdf5 Simplify driver symbol structure in vs settings vm
The code was confusing and difficult to follow.
2024-09-13 10:50:23 -04:00
John Colvin e19c19c013 fix: Raise prop changed event when is_selected changes 2024-09-13 10:50:23 -04:00
John Colvin 8f324bc507 Add venue to vs calc fns 2024-09-13 10:50:23 -04:00
John Colvin 12107c42ce fix: Provide venue param w/ symbol when computing fut slide 2024-09-13 10:50:23 -04:00
John Colvin 91c6fb4e52 diag: Log added/removed exps when syncing vs input w/ system exps
This shouldn't happen often, but if it does, we should know about it.

PS: We recently fixed a bug caused by inequalities between
VolSurfaceExpirations in vs input, and in SystemContractData. User
inputs to the vs grid would be immediately reverted, as the exps
associated with the inputs were not found in the SystemContractData.
This bug would have been easier to track down with this logging in
place.
2024-09-13 10:50:23 -04:00
John Colvin 7044355547 Add venue to VolSurface(DisplayGrid)Expiration
So we can handle symbol/exp date conflicts for securities that differ
only by venue (exchange)
2024-09-13 10:50:23 -04:00
John Colvin 583ae65fb2 Clean up VolSurfaceExpiration
* Enable nullable lang feat
* Use file-scoped namespace
* Sort members
* Include sec type in Compare impl
2024-09-13 10:50:22 -04:00
John Colvin 552fec0edc Add null check in SelectorList ctr 2024-09-13 10:50:22 -04:00
John Colvin fcf6927fbf cleanup: Remove unused code 2024-09-13 10:50:22 -04:00
John Colvin 23f6d827d5 refactor: Replace ThreadedBlackboard w/ IBus
In SingleVolSurfaceCommittedOutputRetriever
2024-09-13 10:50:22 -04:00
John Colvin f083d0abab Clean up VolSurfaceTimeParameters
* Enable nullable lang feat
* Use file-scoped namespace
* Implement ICloneable
2024-09-13 10:50:22 -04:00
John Colvin a895e36922 cleanup: Remove unnecessary ternary op 2024-09-13 10:50:22 -04:00
John Colvin 59d7a72288 fix: Actually use (sec) type arg in to_security_expiration 2024-09-13 10:50:22 -04:00
John Colvin 7731f2f4d1 fix: Check security_type in vs exp Equals impl 2024-09-13 10:50:22 -04:00
John Colvin 41ae5897c0 fix: Maintain sec type when converting SecurityExpiration to vs exp
Avoids data loss
2024-09-13 10:50:22 -04:00
John Colvin c7949ccfba refactor: Get rid of sec type 'Option' default (magic const)
Better to be explict
2024-09-13 10:50:22 -04:00
John Colvin 567af79c7f Fix selection binding issues in vs settings editor
This specifically addresses issues in the driver symbol grids.
Unfortunately, we can't bind directly to ComboCheckBox.SelectedItems
because the view is contained in TabControl. When the selected tab
changes, the previously selected tab clears its ItemsSource (and
consequently the SelectedItems) as a side effect of being unloaded.
2024-09-13 10:50:22 -04:00
John Colvin 6bb4a7b25c refactor: Enable nullable (ref types) in ImmutableListExtensions 2024-09-13 10:50:22 -04:00
John Colvin bc7cef4c34 Fix typo in namespace bts.collection -> bts.collections 2024-09-13 10:50:22 -04:00
John Colvin ab9dc361d6 fix: Use ComboCheckBoxItem.IsSelectedProperty
Instead of Selector.IsSelectedProperty. Unlike ComboBoxItem, ComboCheckItem's
IsSelectedProperty isn't linked to Selector.IsSelectedProperty.
2024-09-13 10:50:21 -04:00
John Colvin 39da0a4dde Add currency column to mview 2024-09-13 10:50:21 -04:00
John Colvin 44e864d697 fix: Use SetCurrentValue instead of SetValue
So we propagate values to/from the binding data source,
rather than overwrite the data source itself.
2024-09-13 10:50:21 -04:00
John Colvin 0a02da3aba Add venue, sec type dropdown filters to exp params ui 2024-09-13 10:50:21 -04:00
John Colvin 836771a7f0 fix: Add null check in ComboCheckBox.SelectedItemsCollectionChanged 2024-09-13 10:50:21 -04:00
John Colvin f386badcfb fix: Disconnect old INotifyCollectionChanged source when dp changes 2024-09-13 10:50:21 -04:00
John Colvin 1d43a484db fix: Index opt/fut exps by venue in vs analytics 2024-09-13 10:50:21 -04:00
John Colvin 91042cb41e fix: Support multiple exchanges in exp params view/vm 2024-09-13 10:50:21 -04:00
John Colvin 10c0e4247d cleanup: Remove unused 'option_symbol' param from compute_atm_data 2024-09-13 10:50:21 -04:00
John Colvin 8e34264e6d fix: Filter by exch when getting atm data for sheets
This is necessary now that we support exchanges with overlapping securities
2024-09-13 10:50:21 -04:00
John Colvin 0a840d256b fix: Remove sec id prop from SecurityExpiration
This class isn't designed to represent a particular contract; it's
basically a key to get option theos.
2024-09-13 10:50:21 -04:00
John Colvin 8a69c51cac refactor: Add 'onDispatcher' param to 'ThreadedBlackboard.subscribe'
This will allow us to gradually move subscriptions off of the dispatcher
(render) thread. When the render thread is pegged, the ui is laggy and
unresponsive. The new param defaults to true, so it won't change
anything until we explicitly set it to false in 'subscribe' calls.
2024-09-13 10:50:21 -04:00
John Colvin 0262fd40bc fix: Remove redundant SparkTimer threads
This addresses some slowness on the front end. Prior to this commit,
each ThreadedBlackboard would start its own timer thread. Since multiple
ThreadedBlackboard run concurrently, this multiplied the frequency of
the SparkTimer callbacks by the number of active ThreadedBlackboards.

The fix is to start this thread in an IShellDaemon rather than the
ThreadedBlackboard. This avoids duplicate threads because the former is
guarenteed to be instantiated only once, via dependency injection.
2024-09-13 10:50:21 -04:00
John Colvin 859dfe3544 refactor: Simplify FakeMDDaemon code that delays post
Use Task.Delay/ContinueWith instead of subscribing to the SparkTimer tag.
2024-09-13 10:50:21 -04:00
John Colvin 9c624a2f79 refactor: Use IBus instead of ThreadedBlackboard
This should address some slowness/mouse lag in the front end (recently
reported by Brandon at Immutable Cap)
2024-09-13 10:50:20 -04:00
John Colvin dec1061b40 fix: Detect and log ccapi depth msg parse errors
This fixes a crash that would happen if a depth item's price or quantity
were an empty string (now we log an error and keep going).
2024-09-13 10:50:20 -04:00
John Colvin be4895faa6 fix: Actually store currency in shared mem
This field has always been in the Security proto, though it until now it
had been omitted from the shared memory representation (FixedSecurity).
2024-09-13 10:50:20 -04:00
Mohammad Arham 3c9755f0dd ADD: Added delay to databento file reader 2024-09-12 15:10:34 +00:00
Mohammad Arham 61ed847d7d Add: Replay speed added to mdreplayer 2024-09-11 06:50:37 +00:00
Mohammad Arham fc9094fea8 Added: CBOE working on databento 2024-09-11 06:17:26 +00:00
Mohammad Arham e36c0efc4b Added: GLBX working on databento 2024-09-11 06:16:42 +00:00
Mohammad Arham 4158a14cff Added: option to send timestamp in onbook IMDListener 2024-09-11 06:15:40 +00:00
Mohammad Arham 201a45cba0 taifex deo 2024-09-05 00:59:00 +00:00
Mohammad Arham ab31b9b253 Add: Multiple files working taifex 2024-09-03 15:15:55 +00:00
Adeel Khan 780ddc79a7 Add: Taifex I083 Message 2024-09-03 20:06:48 +05:00
Mohammad Arham d5a2adaed6 fix: removed errernous code 2024-09-03 13:09:54 +00:00
Mohammad Arham 008ab3f068 Merge branch 'development.new_exchanges' of bitbucket.org:bluetradesys/spark into development.new_exchanges 2024-09-02 16:31:14 -04:00
Mohammad Arham 7d926f588d FIX: typo, changed date to day 2024-09-02 16:31:10 -04:00
Mohammad Arham 707cd07876 Add: CBOE L1 books and contracts working 2024-08-28 16:22:51 +00:00
Mohammad Arham f7ecb9090c add: code to start working on cboe 2024-08-27 12:33:23 +00:00
Mohammad Arham a19e8a7315 change: changes to make taifex work 2024-08-27 07:45:59 -04:00
John Colvin cf189ecf81 refactor: Start cboe and taifex md 'start_databento'
Similar to how we start all ccapi implemented exchanges in "_start_cc"
(in MarketDataGateway)
2024-08-26 19:13:59 +00:00
John Colvin 4405b7adcb refactor: Rename cc_md_listeners -> venue_listeners
They are general purpose, not specific to ccapi.
2024-08-26 19:09:57 +00:00
John Colvin e51ee7b7b9 refactor: Wrap IDGenerator and IMarketDataListeners in shared_ptrs
Our various market data providers (ccapi, emumba, replay, onixs)
dereference pointers to common instances of these types concurrently on
different threads. Although we've correctly managed memory ownership
thus far, we really should be using smart pointers (this is why they
were made).
2024-08-26 19:03:29 +00:00
John Colvin dfaa74f426 build: Add databento dep via FetchContent
Now we actually build libdatabento in the devcontainer along with our
code (as we do with the vcpkg deps, though this is not part of vcpkg)
2024-08-26 17:13:51 +00:00
Mohammad Arham 1d2ce59009 add: added taifex entries 2024-08-22 23:13:05 +00:00
Adeel Khan 3602cc05bb added: TaifexDataHandler, temp 2024-08-23 02:06:47 +05:00
Adeel Khan ac88a81ac6 Security Extensions 2024-08-23 01:42:24 +05:00
Adeel Khan 01fa8e0c63 added: files for Taifex, Cboe 2024-08-23 00:57:40 +05:00
Taha 322c06bfbe Fixing build relted to BCG vs bts namespace 2024-08-21 16:24:22 -04:00
Taha b68fceb362 Cleaning up FileStreams 2024-08-21 16:11:57 -04:00
John Colvin 59547e0f37 fix build: Lock fmt version to 10.2.1 in vcpkg
This fixes the front-end (Windows) libspark build
2024-08-21 13:45:43 -04:00
John Colvin 3ce100a9cf build: Add databento to sparkd
* Install databento deps in docker
  - libzstd-dev
* Add databento cmake module to externals
2024-08-21 13:49:53 +00:00
John Colvin 6513fb0cd5 cleanup: Remove unused include 'date.h' from MDSource
This was an external header, and may interfere with a dependency in the
databento lib (which we are about to add).
2024-08-21 13:49:24 +00:00
Taha Afzal fd0fb1f760 Adding incremental book updates to IMarketDataListener 2024-08-12 22:49:27 -04:00
Taha Afzal 5db586c4d3 spaces, newlines? 2024-08-12 21:27:43 -04:00
Taha 31df1a3827 Added benzinga streamd to MDPub's test config 2024-07-17 14:32:57 -04:00
Taha 7e219aec7c Merging 2024-07-17 02:06:17 -04:00
Taha 37f8b98df9 Icomplete SharedStreamsConfig was breaking build, fixing 2024-07-17 02:03:43 -04:00
Taha f06beff22f Added new benzinga streams 2024-07-17 02:02:01 -04:00
Taha Afzal 6aa39a716a PubSubSingleTagState is not needed any more 2024-07-16 01:15:51 +00:00
Taha Afzal 5088b5ebe0 Fixing problems where PSS's client socket's IP was different than what the client was sending in PubSubClientSubscription 2024-07-08 23:09:53 +00:00
Taha Afzal 010dd3a26f Fixing PubsubEchoTestStream 2024-07-07 06:13:22 +00:00
Taha Afzal 1a18755176 Added pss_echo() 2024-07-06 06:53:35 +00:00
Taha Afzal 233e2576af Merging 2024-07-05 21:21:27 +00:00
Taha Afzal 543c655bca src/DataStreamSuite/PubSub/ManagedTCP/AsyncTCPConnection_AsyncWrapper.cs 2024-07-05 21:13:36 +00:00
Taha 050e21e22b Adding TableMetaDataStream 2024-07-04 23:39:04 -04:00
Taha Afzal 672ad6d237 Cleaning Config 1.0 (not completely done) 2024-06-30 23:17:20 -04:00
Taha 0a8f6e866f Added pubsub routes to the Title of DSQA 2024-06-27 14:04:07 -04:00
Taha b177ffef04 Fixing the bug where messages were being sent by the pubsubserver out of order 2024-06-27 00:17:22 -04:00
Taha 393f304be4 some buf gixes + cleanup 2024-06-26 00:23:19 -04:00
Taha 151816bf5e PubSuMessageReactor empties the message queue (instead oif one elem ata a time) in the main loop 2024-06-24 02:29:28 -04:00
Taha 5cf7eacd82 Fixing the extra .0 in the default pubsub server routeplusfixing acorner cae issue of gettign a fast streaming data cakback after an unsubscribe 2024-06-24 00:28:07 -04:00
Taha 87b6a2044c PubSubServer's linux issues fixed 2024-06-23 21:13:37 -04:00
John Colvin 087d8ab8c9 Set text=auto in gitattributes
Otherwise git can cause files to show as "permanently modified" when you
apply changes from the index (e.g., by running 'git rebase', or 'git
stash pop')
2024-06-11 17:39:12 +00:00
John Colvin b69b7b3350 vscode: Use '\' dir separator in show_last_run.cmd
This script only runs on Windows
2024-06-08 15:08:25 -05:00
John Colvin 5620f33524 vscode: Add task to view logs for last PubSubServer run 2024-06-08 14:42:13 +00:00
John Colvin f3e33fa390 vscode: Add task to run PubSubServer without building 2024-06-07 16:41:42 +00:00
John Colvin 3b631e0d5f Fix a couple more typos in logs 2024-06-07 16:35:06 +00:00
John Colvin f93d28ee76 vscode: Add task to view logs for last DSQA run 2024-06-07 11:34:36 -05:00
John Colvin 23d7d3775d cleanup: Delete unused files 2024-06-07 10:40:34 -05:00
John Colvin 4940771166 fix: Don't login to sparkd from DSQA 2024-06-07 10:02:42 -05:00
John Colvin c1967a8f6a vscode: Add tasks to edit Spark, DataStream config 2024-06-06 11:12:56 -05:00
John Colvin 8c797ee76b Fix typo in log msg 2024-06-06 09:21:01 -05:00
John Colvin ce80957d07 DSQA shouldn't connect to sparkd by default 2024-06-06 09:21:01 -05:00
John Colvin c60018b59e DataStreamPublisher shouldn't connect to sparkd by default
It only needs to connect to sparkd if it's publishing market data
2024-06-06 09:21:01 -05:00
John Colvin 3a27af87d1 PubSubServer shouldn't download config from sparkd by default
As far as I know, it only needs spark/protobuf config to initialize the
c++ logging system. Eventually, we should get rid of that dependency and
use builtin Microsoft Logging facilities for c# instead. In the
meantime, PubSubServer will load config from local files by default
(i.e., spark.conf).
2024-06-06 09:21:01 -05:00
John Colvin 068c1c6973 cleanup: Remove erroneous comment 2024-06-06 09:21:01 -05:00
John Colvin 645a58c97d vscode: Add launch.json 2024-06-06 09:21:01 -05:00
John Colvin b7f455b29a vscode: Remove launch/tasks.json from gitignore 2024-06-06 09:21:00 -05:00
John Colvin 4a2735839e Change line endings to crlf in a few cs files 2024-06-06 09:21:00 -05:00
John Colvin d2e9fe8237 Change line endings to crlf in a few cs files 2024-06-06 09:21:00 -05:00
John Colvin cfc60766d8 Change line endings to crlf in a few cs files 2024-06-06 09:21:00 -05:00
John Colvin b03fec7f79 Change line endings to crlf in a few cs files 2024-06-06 09:20:59 -05:00
John Colvin fb8e7c5b81 Ensure crlf line endings for cs files 2024-06-06 09:20:05 -05:00
John Colvin e44601d1b1 fix merge: Bring back few fns that SchemaGuesserStream needs
* BlueDataUtility.get_typed_schema
* BlueDataUtility.get_typed_table
2024-06-06 09:20:05 -05:00
Taha 07bade53c0 Fixing AsyncTCPCOnnection_APM's double partial messages for messages > 100 MB 2024-06-06 09:20:05 -05:00
Taha fac0a9c25b RemoteQueryStream 2024-06-06 09:20:05 -05:00
John Colvin 1d1de3dd18 Ensure proper line endings for sh, cmd scripts
Via new gitattributes file
2024-06-06 09:20:05 -05:00
John Colvin cfcbf004ba vscode: Use consistent naming conventions in tasks.json 2024-06-06 09:20:05 -05:00
John Colvin 78c7dadbbe vscode: Add parameterless task variants
This allows us to build as a 'preLaunchTask' when debugging (without
requiring users to redundantly specify 'Debug' as the build type).
2024-06-06 09:20:01 -05:00
John Colvin 7b5a6031af build: Use consistent naming conventions in CMake presets
We'll use similar naming conventions for our (vscode) tasks
2024-06-06 09:15:17 -05:00
John Colvin c13a7782c8 build: Name sparkd binary dirs after cmake preset
All other builds follow this pattern. Given the fact that we have so
many different builds now (spark, sparkd, data-streams, api-server,
etc.), it behooves us to adopt consistent naming conventions.
2024-06-06 09:15:17 -05:00
John Colvin 45f02391d1 cleanup: Remove sparkd login creds from PubSubServerConfig
It only needs a Sparkd url to download logging config. TBH, we can probably
get rid of that too, and simply read the local spark.conf.
2024-06-06 09:15:17 -05:00
John Colvin a3ca06addc Reduce 'internal_publish' log level to Diag
It was a bit noisy for the Info level
2024-06-06 09:15:17 -05:00
John Colvin 32869e54ec fix: Fix typos in c# Logs
Prefix a few msgs with '$' so vars in curly braces are expanded via
interpolation
2024-06-06 09:15:17 -05:00
John Colvin ca73220a2e Add new PubSub cfg to DSQA
At least the server address (port) needs to be exposed
2024-06-06 09:15:17 -05:00
John Colvin 9fc3c2618e cleanup: Remove unnecessary reference to SharedStreams
From DataStreamPublisher
2024-06-06 09:15:17 -05:00
John Colvin e72e0c0a30 fix: Make PubSubServer actually use sparkd url in config 2024-06-06 09:15:17 -05:00
John Colvin a5bfc75278 cleanup: Fix a few nullability warnings in DSQA 2024-06-06 09:15:17 -05:00
John Colvin 261a184d25 refactor: Replace legacy Crono type w/ dotnet Stopwatch 2024-06-06 09:15:16 -05:00
John Colvin 54e96a06cb build: Build DSQA on Windows in build_data_stream.py
It was only building DataStreamSuite.sln before, which is crossplatform
now so it no longer includes DSQA.
2024-06-06 09:15:16 -05:00
John Colvin 17e60df32b cleanup: Remove unused file PubSub3Config.cs 2024-06-06 09:15:16 -05:00
John Colvin c99d5fe24c Add support for core PubSub config via json 2024-06-06 09:15:16 -05:00
John Colvin 6049826e90 build: Make build_data_stream.py cross platform
Previously it only worked on Windows
2024-06-06 09:15:16 -05:00
John Colvin 672149dd89 Add more descriptive logs (via stdout) during initialization
The C++ configure/initialize routines were particularly opaque
2024-06-06 09:15:16 -05:00
John Colvin 8c99147f04 build: Build cmake presets in distinct binary dirs
It may use more disk space, but we really don't have a choice. CMake
projects with different parameters, preprocessors, source files, etc.
are not designed to share binary dirs. For example, the libspark.so file
that the Spark front-end is supposed to use is not necessarily the same
as the libspark.so file the Api Server is supposed use.
2024-06-06 09:15:16 -05:00
John Colvin 4d4b0b7ae3 build: Give api server distinct shm prefix 2024-06-06 09:15:16 -05:00
John Colvin 1a7955c1b1 build: Remove unnecessary cache var/macro for api server
* BUILD_API_SERVER (cmake cache var)
* SPARK_ENABLE_API_SERVER (preprocessor defined conditionally w/ BUILD_API_SERVER)

They were originally added to control whether or not MD Consumer extern
fns were built. They have been made redundant by the more appropriately
named EXPORT_MD_CONSUMER cache var/macro (both have same name now).
2024-06-06 09:15:16 -05:00
John Colvin f8fc2a1d96 cleanup: Remove static service Locator class
It relied on a static singleton 'ServiceContext'. Replace references
with a properly scoped (i.e., non-static) ServiceContext
2024-06-06 09:15:16 -05:00
John Colvin 9a7b3cb77c refactor: Reduce code (simplify) in BTS.init
Remove the 'args' parameter, since the cmd line can be obtained from
Environment.GetCommandLine anyways
2024-06-06 09:15:16 -05:00
John Colvin 8a3e4edb4d Dispose connections in SimpleTCPServer.Dispose 2024-06-06 09:15:15 -05:00
John Colvin e59183bb1e improvement: Allow app data dir to be overriden w/ env var
Historically, this has been hardcoded to ~/sparkdata on Linux, and
%APPDATA%/bts on Windows.
2024-06-06 09:15:15 -05:00
John Colvin dd4d4e8dc6 fix: Expand path vars in cmake presets at runtime
The binaries should be portable to other machines (paths shouldn't
be fixed to the user's home dir at compile time).
2024-06-06 09:15:15 -05:00
John Colvin f1744450ca build: Add script to build api server 2024-06-06 09:15:15 -05:00
John Colvin 3a7827a75b build: Automatically load vs dev prompt for win builds 2024-06-06 09:15:15 -05:00
John Colvin 8d22e91c0d fix build: Remove references to HighPerformanceTimer
An old custom timer class from Edge that we no longer need. We're
replacing it w/ a dotnet builtin timer class called 'Stopwatch'.
2024-06-06 09:15:15 -05:00
John Colvin c425145fc9 Remove mongo stream from MarketDataPublisher.json
It doesn't work unless you have mongodb running (a bit of a burden when you
just want to publish market data)
2024-06-06 09:15:15 -05:00
John Colvin 4855935ae0 improvement: Get PubSubRoutes from config (json)
Previously, we were using hardcoded default routes.
2024-06-06 09:15:15 -05:00
John Colvin 65f412ec9f fix: Fix myLoadAllTypes impl
* Fix lowercase typo in hardcoded assemblies (case matters now that we
  run on Linux)
* Fix resolution to full path (previous impl used deprecated functions,
  and incorrectly appended relative paths)
2024-06-06 09:15:15 -05:00
John Colvin 40681c6093 Add MaybeNullWhen(false) attribute to TryGetFirst result
So callers can assume non-null when it returns true (for IEnumerables of
non-null ref types)
2024-06-06 09:15:15 -05:00
John Colvin ab2d36e523 vscode: Add tasks.json
This provides a good base of operations to build/launch our now numerous
projects
2024-06-06 09:15:09 -05:00
John Colvin b1ab3a66d2 build: Fix old build_sparkd.py script
Things have become a lot simpler since it was originally written.
2024-06-05 15:44:36 +00:00
John Colvin 5e7e7e8ef4 test: Add FilterStreamTests 2024-06-05 15:44:35 +00:00
John Colvin 9291d30ae9 build: Add cmake opt to export MDConsumerInterop fns
Now that we have all these different builds (sparkd, spark, api server,
data streams) - many of which are cross platform - we need a proper
toggle for this (relying on 'IF WIN32' preprocessors doesn't cut it)
2024-06-05 15:44:35 +00:00
John Colvin 549708fcc2 fix: Use ".dll" file ext when loading assemblies by path 2024-06-05 15:44:35 +00:00
John Colvin 1d5551f301 build: Add cmake preset to build data streams on linux 2024-06-05 15:44:35 +00:00
John Colvin 283db0f9ea build: Define shm prefix and app data dir in CMakePresets
It's more organized this way, with the input variables for each
configuration defined in one place.
2024-06-05 15:44:35 +00:00
John Colvin 9fb04b2db9 cleanup: Remove unused cmake preset 'spark-api-server-base'
This was a hidden preset designed for common Linux/Windows config.
Neither Linux nor Windows configs were inheriting it.
2024-06-05 15:44:35 +00:00
John Colvin ceca96e10a Add build_data_stream.sh script for Linux 2024-06-05 15:44:35 +00:00
John Colvin fc48cc64af fix build (webapp): Add --include=dev arg to npm install
The apt repo finally updated npm from 8.X.X to 10.8.0. This broke the
Spark.Admin.WebApp build because the new version doesn't install dev
dependencies by default.
2024-06-05 15:44:35 +00:00
John Colvin 015d846941 feat: Add Pandas(Script)Stream 2024-06-05 15:44:35 +00:00
John Colvin e39108bbda fix build (sparkd): Fix typo
'git' was appended to a type name. I suspect a keyboard focus conflict
between vs code editor/terminal panes.
2024-06-03 13:46:51 +00:00
John Colvin 6240d89a08 Map PubSubServerConfig json to historic PubSub3Config 2024-06-03 13:46:51 +00:00
John Colvin c76700e5e5 cleanup: Remove unused PubSubRoute array from DSQA 2024-06-03 13:46:51 +00:00
John Colvin a8a0e8dea0 cleanup: Remove unused PubSubConfigureForm 2024-06-03 13:46:51 +00:00
John Colvin d65a2d6ed6 test: Add DataPacketBuilderTests
This tests somes facilities used in the new MongoCollectionStream
2024-06-03 13:46:51 +00:00
John Colvin 1824d5f9a4 feat: Add [incremental] MongoCollectionStream 2024-06-03 13:46:51 +00:00
John Colvin d3eb29087b refactor: Impl IDictionary<int, IBlueRow> in BlueTable 2024-06-03 13:46:51 +00:00
John Colvin d6fae238f9 Add IObservable ViewStream wrapper 2024-06-03 13:46:51 +00:00
John Colvin 44b46033e3 cleanup: Remove HighPerformanceTimer 2024-06-03 13:46:51 +00:00
John Colvin 5741ec9ab2 cleanup: Remove unnecessary usings (namespaces) 2024-06-03 13:46:51 +00:00
John Colvin 596975b309 style: Apply modern formatting to Crono 2024-06-03 13:46:51 +00:00
John Colvin 9050318ceb refactor: Replace HighPerformanceTimer w/ Stopwatch
This is needed to build DataStreamSuite on Linux.

'Stopwatch' is a platform independent timer class included with the
System.Runtime library in modern dotnet. 'HighPerformanceTimer' is a BTS
class that predates Stopwatch, and is NOT platform independent as it
relies on Windows kernel32.dll QueryPerformanceCounter/Frequency fns.
2024-06-03 13:46:51 +00:00
John Colvin 7ee6933789 refactor: Add formal config classes for prepublish streams
They can be passed to command line via --config <json_file>
2024-06-03 13:46:51 +00:00
John Colvin 306c572b53 improvement: Polish clis in DataStreamSuite
Specifically PubSubServer, DataStreamPublisher and DSQA

* Use CommandLineParser (nuget pkg)
* Clean up csproj files a bit while we're at it
2024-06-03 13:46:51 +00:00
John Colvin 63306173b1 refactor: Reorganize NumericComparer, support all types
Get rid of redundant UniversalNumericComparer while we're at it
2024-05-25 15:37:33 +00:00
John Colvin df1b45ca3e cleanup: Remove leftover legacy files 2024-05-25 15:37:33 +00:00
John Colvin c31a1f1bf3 cleanup: Switch assert statements to 'constraint model'
This gets rid of a few more build warnings in DataStreamSuite
2024-05-25 15:37:33 +00:00
John Colvin e95997ea17 cleanup: Chip away a few nullability warnings in DataStreamSuite
This is a start, but there're still > 700 of them!
2024-05-25 15:37:33 +00:00
John Colvin 12a070fd8d build: Remove DSQA from DataStreamSuite.sln to its own sln
So we can build DataStreamSuite.sln on Linux (DSQA depends on WinForms)
2024-05-25 15:37:33 +00:00
John Colvin e0459c54fd build: Fix 'pubsub' -> 'PubSub' typo in csproj ProjectReferences
Now all DataStream projects build on Linux (except DSQA, which is a winforms app)
2024-05-25 15:37:33 +00:00
John Colvin 15262a5a95 build: Move winform deps from BlueRegistry.csproj to DSQA
So we can build all DataStream projects (except DSQA) on Linux
2024-05-25 15:37:33 +00:00
Taha Afzal 90ec64d25c deleting old serializers 2024-05-25 15:37:33 +00:00
Taha Afzal 061481419e Streams can be published and subscribed now 2024-05-25 15:37:33 +00:00
Taha Afzal 8035255868 Cleaned up the cashe held by PublisherCore 2024-05-25 15:37:33 +00:00
Taha Afzal 7feaf869dc Stream serialization revamp, all tests pass (TestsStream.s) 2024-05-25 15:37:33 +00:00
Taha Afzal 7104e90fc9 Adding tests for stream serialization 2024-05-25 15:37:33 +00:00
Taha Afzal 52c1e500e6 Re-fixing PubSubserver exception caused by null server in internal tags 2024-05-25 15:37:33 +00:00
Taha Afzal 07274f897a Pubsub stats 2024-05-25 15:37:33 +00:00
Taha Afzal f626e53415 CPublisherCore, SubscriberCore, PubsubMessageReactor claned 2024-05-25 15:37:33 +00:00
Taha Afzal 5a7b2965be PubUBState cleaned up and modernized 2024-05-25 15:37:33 +00:00
Taha Afzal 0aab1628bc removing old handlers from PubsubMessageReactor 2024-05-25 15:37:33 +00:00
Taha Afzal b9649e1d8e Clearing up PubSubMessageReactor 2024-05-25 15:37:33 +00:00
Taha Afzal 3bc9bf2207 Starting the server cleanup work 2024-05-25 15:37:33 +00:00
Taha Afzal 888c06262b PublisherCore cleaned up 2024-05-25 15:37:33 +00:00
Taha Afzal 03e80dabcb CHanging member names from old style 2024-05-25 15:37:33 +00:00
Taha Afzal 54184d0875 Cleaning up ISubscriberCore to use ne PubSubClientMssage class 2024-05-25 15:37:33 +00:00
Taha Afzal 90bcf5a455 Adding testss for PubSubMessages 2024-05-25 15:37:33 +00:00
Taha Afzal d32d5ef40c Cleaning up PubSubMessages, as types messages instead of PubSubMetaData untypes dictionary 2024-05-25 15:37:33 +00:00
Taha Afzal 2e0e0658c6 Fixing merging 2024-05-23 10:34:40 -04:00
Taha Afzal bbdb50a41e FIX bridge for Trafix 2024-05-23 10:34:40 -04:00
John Colvin 90705cac83 Integrate theos into Algo Testing Framework
(For Laguna)
2024-05-13 14:28:16 +00:00
John Colvin b91cdd6d91 Expose get/set test secs fn for Algo Testing Framework
Laguna needs this. Historically, the test securities were extracted from
coconut md replay files. Eventually, we'll extract them from the new
replay file format, but until then, this gives Laguna a way to manually
set securities for algo tests (I hardcoded 1 ES sec for convenience by
default).
2024-05-13 14:23:31 +00:00
Mohammad Arham 64f2bd7a88 removed quoting algo so can be loaded dynamically 2024-04-04 20:38:15 -04:00
Mohammad Arham 3e32f684e3 removed redundant code 2024-04-03 16:56:31 -04:00
Mohammad Arham ff73756a55 removed assert if delete order that is completed 2024-04-03 16:55:29 -04:00
Mohammad Arham 1e64811d93 changed error code 2024-04-03 16:54:51 -04:00
John Colvin 2488597cf2 fix build (linux api server): Remove srcs that moved to sparkd 2024-04-02 16:25:13 +00:00
John Colvin 2d8047ba80 build: Tidy up build/publish_spark scripts
In preparation for the first deployment of the "development" branch.
2024-04-02 01:47:47 -05:00
John Colvin 3cb602b77e dev: Remove irrelevant comment from devcontainer.json
It was added by accident
2024-04-02 06:10:25 +00:00
John Colvin 51e1005e79 dev: Fix compile-commands-dir in devcontainer.json
It should be '${workspaceFolder}/build/clang/debug'
2024-04-02 06:01:14 +00:00
John Colvin ef7ea64973 dev: Add -y to 'apt install libpcap' in Dockerfile
Fixes the docker build
2024-04-02 05:57:03 +00:00
Mohammad Arham 0267c16e5a Merge branch 'development' of bitbucket.org:bluetradesys/spark into development 2024-04-01 19:02:32 -04:00
Mohammad Arham ca40e278ff quoting crash fix and comments 2024-04-01 19:01:27 -04:00
John Colvin 1c5da7ad48 cleanup: Tidy up hdrs included in cpp algo sdk 2024-04-01 10:09:35 -04:00
John Colvin 9bb3d5c569 refactor: Move ChildOrder defs to cpp file
So deps can be omitted in header
2024-04-01 10:09:35 -04:00
John Colvin 92ba43bfad refactor: Move ccapi logger into its own file 2024-04-01 10:09:35 -04:00
John Colvin ddeb5e59f0 fix: Add missing exchs to risk webapp 2024-04-01 10:09:35 -04:00
John Colvin 6b0b3e31cc cleanup: Move nested Trade class into its own file
Cut down on dep clutter
2024-04-01 10:09:35 -04:00
John Colvin 3f6c904ccc cleanup: Get rid of redundant SecurityKey def
Make bts::Security an alias for bts::md::Security instead
2024-04-01 10:09:35 -04:00
John Colvin d433919f1b refactor: Move OrderBuilder defs to cpp file
So impl deps don't leak into the sdk through headers
2024-04-01 10:09:35 -04:00
John Colvin 75da9af39d improvement: Add fmt impl for SecurityKey 2024-04-01 10:09:34 -04:00
John Colvin 22eff44926 cleanup: Tidy up Book.h 2024-04-01 10:09:34 -04:00
John Colvin cd6a052d0c cleanup: Tidy up IAlgoOrder, add fmt impl for ChildState
Part of a larger effort to polish the sdk for laguna
2024-04-01 10:09:34 -04:00
John Colvin 3b6cf0b187 cleanup: Remove unnecessary includes 2024-04-01 10:09:34 -04:00
John Colvin c170dd7a9e refactor: Include ostream in EnumMacros.h
So it doesn't need to be explicitly included to support ENUM_CLASS_DEF
2024-04-01 10:09:34 -04:00
John Colvin 154775bc70 refactor: Move misplaced code from libspark to sparkd
This will reduce the dependency load on libspark and the c++ algo sdk.
This has been on the backburner for a while; we're doing it now so we
can deliver a clean sdk to Laguna.

Migrating the following code:
  * general server-side md utils (MarketDataGateway, etc.)
  * emumba dependent code, including md impl for:
    - deribit
  * ccapi dependent code, including md impl for
    - binance
    - binance_us
    - binance_usds_futures
    - ftx
    - coinbase
    - okx
    - deribit
  * md recording

Note: I first began this migration to eliminate the c++ algo sdk's
wependency on emumba. There seemed to be a conflict related to ssl
versions (the build in the sdk docker would fail with unresolved
external symbols for OPENSSL macros)
2024-04-01 10:09:34 -04:00
John Colvin 7f936f3ba9 fix: Inline defs in hdr file 2024-04-01 10:09:24 -04:00
John Colvin 9b30a947a8 fix build: Add a few includes, suppress some werrors
Not sure how this slipped through the cracks, but I'm guessing the build
broke when we upgraded the cpp compilers (to clang 17 and gcc 13).

* Include <cstdint> in a few places
* Suppress -Wstringop-overflow in sparkd-gcc-release build
* Change const char * param to explicit std::string for proper type
  deduction in call to 'std::make_tuple'. For some reason, the gcc build
  was failing with an array-bounds werror (changing the arg fixed it).
2024-04-01 10:09:24 -04:00
John Colvin 2ee58d8f99 dev: Add devcontainer.json (for linux) 2024-04-01 10:09:24 -04:00
John Colvin 0537b3e9c7 cleanup: Remove mongodb.js file that was added by accident 2024-04-01 10:09:24 -04:00
John Colvin 8ae940bcbc fix: Change "init" call to "initAsync" in spark_api_server main
WebsocketDataSync.init was refactored to initAsync
2024-04-01 10:09:23 -04:00
Mohammad Arham 966ccb5f2c fixed order entry 2024-04-01 07:48:36 -04:00
Mohammad Arham fae9c3e59e quantity connected, fills reported, limit set as default 2024-04-01 07:46:36 -04:00
Mohammad Arham cb1dfb257d updated defaults to have max_order_msgs_per_window 2024-03-29 16:00:36 -04:00
Mohammad Arham 76c3fe86c2 quote algo quantity hooked 2024-03-29 14:42:15 -04:00
Mohammad Arham 7e3b1de70f bug fix 2024-03-29 00:38:33 -04:00
Mohammad Arham 2a07e3cf3c custom orders working on api 2024-03-29 00:37:04 -04:00
Mohammad Arham 6d0249825d quotingalgo working 2024-03-29 00:35:49 -04:00
Mohammad Arham 63810e3966 build fix 2024-03-26 18:07:48 -04:00
Mohammad Arham 4c013a8886 reorganise code 2024-03-26 18:07:01 -04:00
Mohammad Arham 9509818978 set theos 2024-03-26 18:06:07 -04:00
Mohammad Arham 4fdf3b8b60 just cleaner code 2024-03-26 02:10:06 -04:00
Mohammad Arham ee9a58486d cleaner code same logic 2024-03-25 02:52:51 -04:00
Mohammad Arham 75d6939c8b added new rules for onix decode ticks 2024-03-25 01:48:22 -04:00
Mohammad Arham fb1697b571 spelling fix 2024-03-24 23:17:02 -04:00
Mohammad Arham 4080d606d8 fixed get trades 2024-03-24 23:16:38 -04:00
Mohammad Arham 7655fd47dd fixed spelling 2024-03-24 23:14:11 -04:00
Taha Afzal d029b0fce7 SimExecution works with GLBX now 2024-03-18 23:54:19 -04:00
John Colvin 60df5b2a68 refactor: Move OrderDataHelper to spark_api.csproj
So it can be called from the websocket api server to parse
CustomOrderDefinitions
2024-03-13 12:45:17 -05:00
Taha Afzal bada5dc961 Fixing SimExecution for CME 2024-03-06 14:11:02 -05:00
Taha Afzal 4510e120ab enabling some streams like max, that were dependent on AddCOlumns (thta John fixed in the last commit) 2024-02-12 13:21:28 -05:00
Taha Afzal da2af06ee6 Merging 2024-02-08 15:48:51 -05:00
John Colvin 9212c6d097 Line ending changes in yacc/lex generated code
I recently upgrade the YaccLexTools nuget to 1.2.2, perhaps these new
line endings are related to that.
2024-02-08 14:28:36 -06:00
John Colvin 8660dea85a build: Downgrade new DataStream code from net8 -> net7
The AddColumnsStream, SortStream, and requisite yacc/lex grammar were
originally added to a new branch, off of development, which is on net8.
I forgot to change it to net7 when I cherry-picked the commits for the
regular development branch.

It's wasn't quite as simple as flipping net8 -> net7 in csproj files,
because I was eager to use new language features only available in net8!
Namely, primary constructors and collection expressions.
2024-02-08 14:24:31 -06:00
Taha Afzal 8c1342230b RowDiff added 2024-02-08 14:11:10 -05:00
John Colvin d0ddc1d57b Resurrect SortStream
Add ColumnSortExpressions grammar (lex/yacc)
2024-02-08 10:04:53 -06:00
John Colvin fe1e953030 Resurrect AddColumnStream
Add ColumnExpressions grammar (lex/yacc)
2024-02-08 10:04:53 -06:00
John Colvin dab17af5a9 build: Upgrade YaccLexTools to 1.2.2 2024-02-08 00:51:16 -06:00
Taha Afzal 8dd2775092 Added volatility to trade bars 2024-02-04 23:22:52 -05:00
John Colvin 7fb7b1e4af Fix PriceStatsStream
* Store subscription IDisposable in class (we need to control the life of the subscription)
* Flip typo '_dirty = false' -> '_dirty = true'
2024-02-04 22:14:00 -06:00
Taha Afzal 8966b73ac9 Merge branch 'development' of bitbucket.org:bluetradesys/spark into development 2024-02-04 18:04:06 -05:00
Taha Afzal ddb2a91763 Adding TradBar stream 2024-02-04 18:03:51 -05:00
John Colvin bc5bcbf11e fix: Bootstrap MarketDataClient.price_ticker/stats w/ init state
Bugs (fixed):
  * MarketDataClient.price_ticker, and price_stats streams don't fire update
    with initial state (they only tick as subsequent changes are observed)
2024-02-04 15:33:20 -06:00
Taha Afzal 287ee291cc Adding a stream that send a TCP packet to the echo server and monitors the n_sends and n_recvs 2024-01-25 13:37:41 -05:00
Taha Afzal 2bceda01ae Added code in BlueDataUtility to create schema from data 2024-01-22 16:28:23 -05:00
John Colvin c39a270115 fix: Support all exchs in QueryServer::get_names 2024-01-17 11:15:01 -05:00
Taha Afzal 6e3f9f99c0 Merge branch 'development' of bitbucket.org:bluetradesys/spark into development 2024-01-17 10:08:17 -05:00
John Colvin b53d9d7d4c refactor: Remove 'Platform' (md source) config
Good riddance. Improper 'PlatformMap' config was often the reason market
data mysteriously wouldn't show up in the client. Especially with new
exchanges. We should keep all md source/connection configuration in one
place (one proto message), to avoid any confusion.
2024-01-17 01:42:57 -05:00
Taha Afzal cc3e289345 KeyValueToRelationalStream added 2024-01-16 19:08:40 -05:00
John Colvin 60a8b4f8c7 Gitignore all .tmp dirs (at any level) 2024-01-15 13:34:35 -05:00
John Colvin c5e0a93869 Gitignore all .venv* dirs (at any level) 2024-01-15 13:33:05 -05:00
John Colvin 3a3216421b Remove unnecessary file temp.cpp 2024-01-15 13:33:05 -05:00
Taha Afzal 8cbbbc6da3 Merging 2024-01-13 23:45:51 -05:00
1668 changed files with 94171 additions and 55912 deletions

No files matched your search

+2 -2
View File
@@ -9,7 +9,7 @@
]
},
"fable": {
"version": "4.0.6",
"version": "4.24.0",
"commands": [
"fable"
]
@@ -27,4 +27,4 @@
]
}
}
}
}
+131
View File
@@ -0,0 +1,131 @@
FROM ubuntu:22.04
ARG DEBIAN_FRONTEND=noninteractive
# Note installations that take a while (more than 10s)
RUN apt-get update
RUN apt-get install -y ca-certificates
RUN apt-get install -y ccache
RUN apt-get install -y curl
RUN apt-get install -y fish
RUN apt-get install -y gdb
# git-all: ~250s
RUN apt-get install -y git-all
RUN apt-get install -y gnupg
# liblttng-ust-dev: ~30s
RUN apt-get install -y liblttng-ust-dev
RUN apt-get install -y libssh2-1-dev
RUN apt-get install -y locales
RUN apt-get install -y ninja-build
# openssh-server: ~40s
RUN apt-get install -y openssh-server
RUN apt-get install -y pkg-config
RUN apt-get install -y software-properties-common
RUN apt-get install -y sudo
RUN apt-get install -y tzdata
RUN apt-get install -y vim
RUN apt-get install -y zip
# Python: ~30s
RUN apt-get install -y \
python3-pip \
python3-venv \
&& python3 -m pip install --upgrade pip
# GCC
ARG gcc_major=13
RUN \
add-apt-repository ppa:ubuntu-toolchain-r/test \
&& apt-get update \
&& apt-get install -y g++-$gcc_major
# Clang
ARG clang_major=17
RUN \
curl -fsSL https://apt.llvm.org/llvm-snapshot.gpg.key 2> /dev/null \
| gpg --dearmor - \
| tee /usr/share/keyrings/llvm-snapshot.gpg > /dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-$clang_major main" \
| tee -a "/etc/apt/sources.list.d/llvm.list" \
&& apt-get update \
&& apt-get install -y \
clang-$clang_major \
clang-format-$clang_major \
clangd-$clang_major
# CMake
RUN \
curl -fsSL https://apt.kitware.com/keys/kitware-archive-latest.asc 2> /dev/null \
| gpg --dearmor - \
| tee /usr/share/keyrings/kitware-archive-keyring.gpg > /dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" \
| tee /etc/apt/sources.list.d/kitware.list > /dev/null \
&& apt-get update \
&& apt-get install -y cmake
# Dotnet
RUN apt-get update && apt-get install -y dotnet8
# Node
ARG node_major=18
RUN mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
| gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$node_major.x nodistro main" \
| tee /etc/apt/sources.list.d/nodesource.list \
&& apt-get update \
&& apt-get install -y nodejs
# Emumba (deps)
RUN apt-get update && apt-get -y install rapidjson-dev
# Emumba
COPY emumba /emumba
RUN dpkg -i /emumba/emumba-deribit-connector-3.3.1-Linux.LICENSE_DISABLED.deb \
&& rm -r /emumba
# Pcap
RUN apt-get update && apt-get install -y libpcap0.8-dev
# Databento (deps)
RUN apt-get update && apt-get -y install libzstd-dev
# Docker in Docker
RUN apt-get update && apt-get install -y \
docker.io \
docker-compose \
docker-compose-v2
# Set up default executables (update-alternatives)
RUN \
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-$clang_major 100; \
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-$clang_major 100; \
update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-$clang_major 100; \
update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-$clang_major 100; \
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-$gcc_major 100; \
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-$gcc_major 100
# Add compiler symlinks for ccache
RUN \
ln -s /usr/bin/ccache /usr/local/bin/clang; \
ln -s /usr/bin/ccache /usr/local/bin/clang++; \
ln -s /usr/bin/ccache /usr/local/bin/clang-$clang_major; \
ln -s /usr/bin/ccache /usr/local/bin/clang++-$clang_major; \
ln -s /usr/bin/ccache /usr/local/bin/gcc; \
ln -s /usr/bin/ccache /usr/local/bin/g++
RUN locale-gen en_US.UTF-8
ARG docker_user="bts"
ARG docker_uid="1000"
ARG docker_pass="bts"
RUN \
groupadd -g "$docker_uid" "$docker_user" \
&& useradd \
-m \
-u "$docker_uid" \
-g "$docker_uid" \
-G sudo \
--password "$(openssl passwd -1 "$docker_pass")" \
"$docker_user"
+31
View File
@@ -0,0 +1,31 @@
{
"dockerFile": "Dockerfile",
"hostRequirements": {
"memory": "8gb",
"storage": "10gb"
},
"containerUser": "bts",
"updateRemoteUserUID": true,
"shutdownAction": "none",
// Note: If running multiple containers on the same host, each must use a
// unique set of ports. Usually we just add 1000 to each port as needed. For
// example, if 8000-8003 is taken, go with 9000-9003, then 10000-10003, etc.
"runArgs": [
"--shm-size",
"8gb"
],
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
"customizations": {
"vscode": {
"extensions": [
"eamodio.gitlens",
"llvm-vs-code-extensions.vscode-clangd",
"ms-vscode.cmake-tools",
"ms-vscode.cpptools",
"xaver.clang-format"
]
}
}
}
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
this_dir="$(realpath "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")"
sudo dpkg -i "$this_dir/emumba-deribit-connector-3.3.1-Linux.LICENSE_DISABLED.deb"
+48
View File
@@ -0,0 +1,48 @@
# 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
# - TODO: pubsub
# - TODO: md-publisher
# - TODO: webapp (DSQA on the web)
# - TODO: 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/server/sparkd/Dockerfile
SPARKD__IMAGE=sparkd
# The config dir for this service to use
SPARKD__CONFIG_DIR=src/server/sparkd/configurations/dev
# Mount a specific volume or dir to "~/sparkdata/data" inside the docker.
# Defaults to a volume named "sparkd_<config_port>" (e.g., sparkd_8000).
# SPARKD__DATA_DIR=/home/bts/sparkdata/data
SPARKD__SOURCE_DIR=install/sparkd-release-gcc
SPARKD__RUNTIME_CONF_DIR=/home/ubuntu/8000/sparkdata/conf/
SPARKD__CONFIG_PORT=8000
SPARKD__QUICKBUS_PORT=8001
SPARKD__SIM_FIX_PORT=8002
SPARKD__SHM_SIZE=4gb
# TODO: add config for other services (pubsub, md-publisher, webapp, api-server, etc.)
+3
View File
@@ -0,0 +1,3 @@
*.cmd text=auto eol=crlf
*.cs text=auto eol=crlf
*.sh text=auto eol=lf
+8 -4
View File
@@ -8,7 +8,9 @@ cmake-build-debug/
.idea/
.dir-locals.el
*.pyc
**.vscode
**.vscode/*
!.vscode/launch.json
!.vscode/tasks.json
.vs
obj/
*.csproj.user
@@ -47,13 +49,15 @@ trace_data/
/src/.clang-format
/src/server/sparkd/cmds/spartan/analysis/.ipynb_checkpoints
/src/server/sparkd/cmds/spartan/analysis/data
*.tmp/*
/.venv*/*
.tmp/
.venv*/
.cache/
/src/Spark.Admin.WebApp/tsconfig.*.g.json
/src/Spark.Admin.WebApp/src/bin/
**/CMakeDeps.cmake
**/CMakeDeps_win.cmake
**/.devcontainer
.devcontainer/
*.Generated.cs
*.lst
.env.local
.secrets
+1 -1
View File
@@ -1,6 +1,6 @@
[submodule "externals"]
path = externals
url = git@bitbucket.org:bluetradesys/externals.git
url = https://bitbucket.org/bluetradesys/externals.git
[submodule "vcpkg"]
path = vcpkg
url = https://github.com/microsoft/vcpkg.git
+337
View File
@@ -0,0 +1,337 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Python Debugger: Current File with Arguments",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"args": "${command:pickArgs}"
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
},
{
"name": "DataStreamPublisher",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build DataStream (Debug)",
"program": "",
"linux": {
"program": "DataStreamPublisher",
},
"windows": {
"program": "DataStreamPublisher.exe",
},
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json"
],
"cwd": "build/Debug/bin/net8.0",
"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": "spreader tests2",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/sparkd-debug-clang/server/sparkd",
"args": [
"test",
"[spreader2]"
],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/sparkd-debug-clang/server",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
},
{
"name": "spreader tests",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/sparkd-debug-clang/server/sparkd",
"args": [
"test",
"[spreader]"
],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/sparkd-debug-clang/server",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
},
{
"name": "DataStreamQueryAnalyzer",
"type": "coreclr",
"request": "launch",
//"preLaunchTask": "Build DataStreamQueryAnalyzer (Debug)",
"program": "",
"windows": {
"program": "DataStreamQueryAnalyzer.exe",
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json"
],
"cwd": "build/Debug/bin/net8.0-windows",
"env": {
"PYTHON_EXE": "${workspaceFolder}/.venv/Scripts/python.exe"
},
},
"stopAtEntry": false,
"console": "integratedTerminal",
},
{
"name": "PubSubServer",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build DataStream (Debug)",
"program": "",
"linux": {
"program": "PubSubServer",
},
"windows": {
"program": "PubSubServer.exe",
},
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json"
],
"cwd": "build/Debug/bin/net8.0",
"stopAtEntry": false,
"console": "integratedTerminal"
},
{
"name": "Spark",
"type": "coreclr",
"request": "launch",
"program": "",
"windows": {
"preLaunchTask": "Build Spark (Debug)",
"program": "Spark.exe",
"cwd": "build/Debug/bin/net8.0-windows",
},
"stopAtEntry": false,
"console": "integratedTerminal"
},
{
"name": "Spark (Skip Build)",
"type": "coreclr",
"request": "launch",
"program": "",
"windows": {
"program": "Spark.exe",
"cwd": "build/Debug/bin/net8.0-windows",
},
"stopAtEntry": false,
"console": "integratedTerminal"
},
{
"name": "Spark (Parameterized)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build Spark (Debug)",
"program": "",
"windows": {
"program": "Spark.exe",
"args": [
"--sparkd",
"${input:sparkConfigServer}"
],
"cwd": "build/Debug/bin/net8.0-windows",
},
"stopAtEntry": false,
"console": "integratedTerminal"
},
{
"name": "Spark Test",
"type": "coreclr",
"request": "launch",
"program": "",
"windows": {
"preLaunchTask": "Build Spark (Debug)",
"program": "Spark.Console.exe",
"cwd": "build/Debug/bin/net8.0",
"args": [
"test",
"${input:sparkTest}"
]
},
"stopAtEntry": false,
"console": "integratedTerminal"
},
{
"name": "Spark Test (Skip Build)",
"type": "coreclr",
"request": "launch",
"program": "",
"windows": {
"program": "Spark.Console.exe",
"cwd": "build/Debug/bin/net8.0",
"args": [
"test",
"${input:sparkTest}"
]
},
"stopAtEntry": false,
"console": "integratedTerminal"
},
{
"name": "Sparkd",
"type": "cppdbg",
"request": "launch",
"program": "",
"linux": {
"preLaunchTask": "Build Sparkd (Debug)",
"program": "${workspaceFolder}/build/sparkd-debug-clang/server/sparkd",
"args": [
"run"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/build/sparkd-debug-clang/server",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
},
{
"name": "Sparkd (Skip Build)",
"type": "cppdbg",
"request": "launch",
"program": "",
"linux": {
"program": "${workspaceFolder}/build/sparkd-debug-clang/server/sparkd",
"args": [
"run"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/build/sparkd-debug-clang/server",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
},
{
"name": "Sparkd Test",
"type": "cppdbg",
"request": "launch",
"program": "",
"linux": {
"preLaunchTask": "Build Sparkd (Debug)",
"program": "${workspaceFolder}/build/sparkd-debug-clang/server/sparkd",
"args": [
"test",
"${input:sparkdTest}",
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/build/sparkd-debug-clang/server",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
},
{
"name": "Sparkd Test (Skip Build)",
"type": "cppdbg",
"request": "launch",
"program": "",
"linux": {
"program": "${workspaceFolder}/build/sparkd-debug-clang/server/sparkd",
"args": [
"test",
"${input:sparkdTest}",
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/build/sparkd-debug-clang/server",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
},
],
"inputs": [
{
"id": "dataStreamPublisherConfig",
"type": "pickString",
"description": "Publisher Configuration",
"options": [
"MarketDataPublisher",
"SimpleEchoClient",
"SimpleTestDataPublisher",
"TestDataPublisher",
],
"default": "MarketDataPublisher",
},
{
"id": "pubSubServerConfig",
"type": "pickString",
"description": "PubSub Configuration",
"options": [
"PubSubServer",
"SimpleEchoClient",
],
"default": "PubSubServer",
},
{
"id": "sparkConfigServer",
"type": "promptString",
"description": "Config Server URL",
"default": "http://localhost:8000/config",
},
{
"id": "sparkTest",
"type": "promptString",
"description": "Test to run",
},
{
"id": "sparkdTest",
"type": "promptString",
"description": "Test to run",
},
]
}
+930
View File
@@ -0,0 +1,930 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build Api Server",
"group": "build",
"type": "process",
"command": "",
"linux": {
"command": "tools/build_api_server.sh",
},
"windows": {
"command": "tools/build_api_server.cmd",
},
"args": [
"--configuration",
"${input:buildConfiguration}",
],
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Api Server (Debug)",
"group": "build",
"type": "process",
"command": "",
"linux": {
"command": "tools/build_api_server.sh",
},
"windows": {
"command": "tools/build_api_server.cmd",
},
"args": [
"--configuration",
"Debug",
],
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Api Server (Release)",
"group": "build",
"type": "process",
"command": "",
"windows": {
"command": "tools/build_api_server.cmd",
},
"linux": {
"command": "tools/build_api_server.sh",
},
"args": [
"--configuration",
"Release",
],
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build DataStream",
"group": "build",
"type": "process",
"command": "",
"linux": {
"command": "tools/build_data_stream.sh",
},
"windows": {
"command": "tools/build_data_stream.cmd",
},
"args": [
"--configuration",
"${input:buildConfiguration}",
],
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build DataStream (Debug)",
"group": "build",
"type": "process",
"command": "",
"linux": {
"command": "tools/build_data_stream.sh",
},
"windows": {
"command": "tools/build_data_stream.cmd",
},
"args": [
"--configuration",
"Debug",
],
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build DataStream (Release)",
"group": "build",
"type": "process",
"command": "",
"linux": {
"command": "tools/build_data_stream.sh",
},
"windows": {
"command": "tools/build_data_stream.cmd",
},
"args": [
"--configuration",
"Release",
],
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Spark",
"group": "build",
"type": "process",
"command": "",
"windows": {
"command": "tools/build_spark.cmd",
},
"args": [
"--configuration",
"${input:buildConfiguration}",
],
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Spark (Debug)",
"group": "build",
"type": "process",
"command": "",
"windows": {
"command": "tools/build_spark.cmd",
},
"args": [
"--configuration",
"Debug",
],
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Spark (Release)",
"group": "build",
"type": "process",
"command": "",
"windows": {
"command": "tools/build_spark.cmd",
},
"args": [
"--configuration",
"Release",
],
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Sparkd",
"group": "build",
"type": "shell",
"command": "",
"linux": {
"command": "tools/build_sparkd.sh",
"args": [
"--preset",
"${input:sparkdCmakePreset}",
],
},
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Sparkd (Debug)",
"group": "build",
"type": "shell",
"command": "",
"linux": {
"command": "tools/build_sparkd.sh",
"args": [
"--build-type",
"Debug",
"--compiler",
"${input:sparkdCompiler}"
],
},
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Sparkd (Debug | Gcc)",
"group": "build",
"type": "shell",
"command": "",
"linux": {
"command": "tools/build_sparkd.sh",
"args": [
"--build-type",
"Debug",
"--compiler",
"gcc"
],
},
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Sparkd (Debug | Clang)",
"group": "build",
"type": "shell",
"command": "",
"linux": {
"command": "tools/build_sparkd.sh",
"args": [
"--build-type",
"Debug",
"--compiler",
"clang"
],
},
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Sparkd (Release)",
"group": "build",
"type": "shell",
"command": "",
"linux": {
"command": "tools/build_sparkd.sh",
"args": [
"--build-type",
"Release",
"--compiler",
"${input:sparkdCompiler}"
],
},
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Sparkd (Release | Gcc)",
"group": "build",
"type": "shell",
"command": "",
"linux": {
"command": "tools/build_sparkd.sh",
"args": [
"--build-type",
"Release",
"--compiler",
"gcc"
],
},
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Build Sparkd (Release | Clang)",
"group": "build",
"type": "shell",
"command": "",
"linux": {
"command": "tools/build_sparkd.sh",
"args": [
"--build-type",
"Release",
"--compiler",
"clang"
],
},
"icon": {
"id": "terminal",
"color": "terminal.ansiCyan"
},
},
{
"label": "Edit DataStream Config",
"type": "process",
"command": "",
"linux": {
"command": "editor",
"args": [
"${env:HOME}/.local/share/DataStream/conf/spark.conf"
],
},
"windows": {
"command": "vim",
"args": [
"${env:APPDATA}/bts/DataStream/conf/spark.conf"
],
},
"presentation": {
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false,
"close": true,
},
"icon": {
"id": "wrench"
},
},
{
"label": "Edit Spark Config",
"type": "process",
"command": "",
"windows": {
"command": "vim",
"args": [
"${env:APPDATA}/bts/conf/spark.conf"
],
},
"presentation": {
"reveal": "always",
"focus": true,
"panel": "dedicated",
"showReuseMessage": false,
"close": true,
},
"icon": {
"id": "wrench"
},
},
{
"label": "Run DataStreamQueryAnalyzer",
"dependsOn": "Build DataStream",
"type": "process",
"command": "",
"windows": {
"command": "DataStreamQueryAnalyzer.exe",
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json",
],
"options": {
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0-windows"
},
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run DataStreamQueryAnalyzer (Debug)",
"dependsOn": "Build DataStream (Debug)",
"type": "process",
"command": "",
"windows": {
"command": "DataStreamQueryAnalyzer.exe",
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json",
],
"options": {
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0-windows"
},
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run DataStreamQueryAnalyzer (Release)",
"dependsOn": "Build DataStream (Release)",
"type": "process",
"command": "",
"windows": {
"command": "DataStreamQueryAnalyzer.exe",
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json",
],
"options": {
"cwd": "${workspaceFolder}/build/Release/bin/net7.0-windows"
},
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run DataStreamPublisher",
"dependsOn": "Build DataStream",
"type": "process",
"command": "",
"linux": {
"command": "DataStreamPublisher",
},
"windows": {
"command": "DataStreamPublisher.exe",
},
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
],
"options": {
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run DataStreamPublisher (Debug)",
"dependsOn": "Build DataStream (Debug)",
"type": "process",
"command": "",
"linux": {
"command": "DataStreamPublisher",
},
"windows": {
"command": "DataStreamPublisher.exe",
},
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
],
"options": {
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run DataStreamPublisher (Release)",
"dependsOn": "Build DataStream (Release)",
"type": "process",
"command": "",
"linux": {
"command": "DataStreamPublisher",
},
"windows": {
"command": "DataStreamPublisher.exe",
},
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
],
"options": {
"cwd": "${workspaceFolder}/build/Release/bin/net7.0"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run PubSubServer",
"dependsOn": "Build DataStream",
"type": "process",
"command": "",
"linux": {
"command": "PubSubServer",
},
"windows": {
"command": "PubSubServer.exe",
},
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
],
"options": {
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run PubSubServer (Debug)",
"dependsOn": "Build DataStream (Debug)",
"type": "process",
"command": "",
"linux": {
"command": "PubSubServer",
},
"windows": {
"command": "PubSubServer.exe",
},
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
],
"options": {
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run PubSubServer (Debug | Skip Build)",
"type": "process",
"command": "",
"linux": {
"command": "PubSubServer",
},
"windows": {
"command": "PubSubServer.exe",
},
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
],
"options": {
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run PubSubServer (Release)",
"dependsOn": "Build DataStream (Release)",
"type": "process",
"command": "",
"linux": {
"command": "PubSubServer",
},
"windows": {
"command": "PubSubServer.exe",
},
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
],
"options": {
"cwd": "${workspaceFolder}/build/Release/bin/net7.0"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run PubSubServer (Release | Skip Build)",
"type": "process",
"command": "",
"linux": {
"command": "PubSubServer",
},
"windows": {
"command": "PubSubServer.exe",
},
"args": [
"--config",
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
],
"options": {
"cwd": "${workspaceFolder}/build/Release/bin/net7.0"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run Spark",
"dependsOn": "Build Spark",
"type": "process",
"command": "",
"windows": {
"command": "Spark.exe",
"options": {
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0-windows"
},
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
}
},
{
"label": "Run Spark (Debug)",
"dependsOn": "Build Spark (Debug)",
"type": "process",
"command": "",
"windows": {
"command": "Spark.exe",
"options": {
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0-windows"
},
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
}
},
{
"label": "Run Spark (Release)",
"dependsOn": "Build Spark (Release)",
"type": "process",
"command": "",
"windows": {
"command": "Spark.exe",
"options": {
"cwd": "${workspaceFolder}/build/Release/bin/net7.0-windows"
},
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
}
},
{
"label": "Run Spark (Skip Build)",
"type": "process",
"command": "",
"windows": {
"command": "Spark.exe",
"options": {
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0-windows"
},
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
}
},
{
"label": "Run Spark Config Query",
"dependsOn": "Build Spark",
"type": "process",
"command": "",
"linux": {
"command": "Spark.Console",
},
"windows": {
"command": "Spark.Console.exe",
},
"args": [
"config",
"--query",
"${input:sparkConfigQuery}",
],
"options": {
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run Sparkd",
"dependsOn": "Build Sparkd",
"type": "process",
"command": "",
"linux": {
"command": "sparkd",
},
"args": [
"run"
],
"options": {
"cwd": "${workspaceFolder}/build/${input:sparkdCmakePreset}/server"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run Sparkd (Skip Build)",
"type": "process",
"command": "",
"linux": {
"command": "sparkd",
},
"args": [
"run"
],
"options": {
"cwd": "${workspaceFolder}/build/${input:sparkdCmakePreset}/server"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Run Sparkd Config Query",
"dependsOn": "Build Sparkd",
"type": "process",
"command": "",
"linux": {
"command": "sparkd",
},
"args": [
"config",
"--query",
"${input:sparkdConfigQuery}",
],
"options": {
"cwd": "${workspaceFolder}/build/${input:sparkdCompiler}/${input:sparkdBuildType}/server"
},
"icon": {
"id": "run",
"color": "terminal.ansiGreen",
},
},
{
"label": "Test Spark (Debug)",
"dependsOn": "Build Spark (Debug)",
"type": "process",
"icon": {
"id": "coverage",
"color": "terminal.ansiYellow",
},
"command": "",
"windows": {
"command": "Spark.Console.exe",
"args": [
"test",
"${input:sparkTest}"
],
"options": {
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0",
}
},
},
{
"label": "Test Sparkd",
"dependsOn": "Build Sparkd",
"type": "process",
"command": "",
"linux": {
"command": "sparkd",
},
"args": [
"test",
"${input:sparkdTest}",
],
"options": {
"cwd": "${workspaceFolder}/build/${input:sparkdCmakePreset}/server"
},
"icon": {
"id": "coverage",
"color": "terminal.ansiYellow",
},
},
{
"label": "Test Sparkd (Skip Build)",
"type": "process",
"command": "",
"linux": {
"command": "sparkd",
},
"args": [
"test",
"${input:sparkdTest}",
],
"options": {
"cwd": "${workspaceFolder}/build/${input:sparkdCmakePreset}/server"
},
"icon": {
"id": "coverage",
"color": "terminal.ansiYellow",
},
},
{
"label": "View DataStreamQueryAnalyzer Logs (Last Run)",
"type": "process",
"command": "",
"windows": {
"command": "tools/logging/show_last_run.cmd",
"args": [
"DataStream",
"DataStreamQueryAnalyzer.exe",
"'Starting DataStreamQueryAnalyzer'"
]
},
"presentation": {
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false,
"close": true,
},
"icon": {
"id": "wrench"
},
},
{
"label": "View PubSubServer Logs (Last Run)",
"type": "process",
"command": "",
"linux": {
"command": "tools/logging/show_last_run.sh",
"args": [
"${env:HOME}/.local/share/DataStream/data/logging.PubSubServer",
"Starting PubSubServer"
]
},
"windows": {
"command": "tools/logging/show_last_run.cmd",
"args": [
"DataStream",
"PubSubServer.exe",
"Starting PubSubServer"
]
},
"presentation": {
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false,
"close": true,
},
"icon": {
"id": "wrench"
},
},
],
"inputs": [
{
"id": "buildConfiguration",
"type": "pickString",
"description": "Configuration",
"options": [
"Debug",
"Release",
],
"default": "Debug",
},
{
"id": "sparkdCmakePreset",
"type": "pickString",
"description": "Configuration",
"options": [
"sparkd-debug-clang",
"sparkd-debug-gcc",
"sparkd-release-clang",
"sparkd-release-gcc",
],
"default": "sparkd-debug-clang",
},
{
"id": "sparkdCompiler",
"type": "pickString",
"description": "Configuration",
"options": [
"clang",
"gcc",
],
"default": "sparkd-debug-clang",
},
{
"id": "dataStreamPublisherConfig",
"type": "pickString",
"description": "Publisher Configuration",
"options": [
"MarketDataPublisher",
"SimpleEchoClient",
"SimpleTestDataPublisher",
"TestDataPublisher",
],
"default": "MarketDataPublisher",
},
{
"id": "pubSubServerConfig",
"type": "pickString",
"description": "PubSub Configuration",
"options": [
"PubSubServer",
"SimpleEchoClient",
],
"default": "PubSubServer",
},
{
"id": "sparkConfigQuery",
"type": "promptString",
"description": "Config Type(s)"
},
{
"id": "sparkdConfigQuery",
"type": "promptString",
"description": "Config Type(s)"
},
{
"id": "sparkTest",
"type": "promptString",
"description": "Test to run",
},
{
"id": "sparkdTest",
"type": "promptString",
"description": "Test to run",
},
]
}
+32 -20
View File
@@ -1,7 +1,10 @@
cmake_minimum_required(VERSION 3.12)
project(spark)
include(GNUInstallDirs)
include(${CMAKE_SOURCE_DIR}/cmake/GitVersion.cmake)
set(CMAKE_CXX_STANDARD 20)
get_version_from_git()
if(WIN32)
set(platform "windows")
else()
@@ -14,12 +17,17 @@ set(
CACHE
STRING
"External dependencies root folder (should contain folders: lib, bin, include")
# SHARED_MEMORY_PREFIX serves as a kind of namespace so multiple applications
# can run simultaneously without fighting over the same shm files (e.g., sparkd,
# api server, etc.).
set(SHARED_MEMORY_PREFIX "bts" CACHE STRING "Prefix to use when creating shared memory files")
set(SPARK_BIN "${EXTERNALS_ROOT}/bin")
set(SPARK_INCLUDE "${EXTERNALS_ROOT}/include")
set(SPARK_LIB "${EXTERNALS_ROOT}/lib/$<CONFIG>")
set(BUILD_API_SERVER OFF CACHE BOOL "Build the api server")
set(BUILD_DOCS OFF CACHE BOOL "Build documentation")
set(BUILD_SDK OFF CACHE BOOL "Build the sdk")
set(EXPORT_MD_CONSUMER OFF CACHE BOOL "Export (extern) C functions for MD consumer interop")
if (WIN32)
set(BUILD_SPARKD OFF CACHE BOOL "Build sparkd")
set(BUILD_ADMIN_WEB_APP OFF CACHE BOOL "Build the Admin WebApp")
@@ -31,29 +39,21 @@ endif()
include_directories(BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
link_directories(${SPARK_LIB})
if(BUILD_API_SERVER)
add_compile_definitions(SPARK_ENABLE_API_SERVER)
add_compile_definitions(SHARED_MEMORY_PREFIX="${SHARED_MEMORY_PREFIX}")
add_compile_definitions(APP_DATA_DIR="${APP_DATA_DIR}")
if(DEFINED APP_DATA_DIR_OVERRIDE)
add_compile_definitions(APP_DATA_DIR_OVERRIDE="${APP_DATA_DIR_OVERRIDE}")
endif()
add_compile_definitions(EXPORT_MD_CONSUMER="${EXPORT_MD_CONSUMER}")
if(WIN32)
add_compile_definitions(SHARED_MEMORY_PREFIX="spark")
add_compile_definitions(APP_DATA_DIR="\$\{APPDATA\}/bts/")
# subdirs
add_subdirectory(src/lib)
else()
# make sparkd look for libspark.so in its directory
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH ".")
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install")
set(SPARK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/$<CONFIG>")
if(BUILD_API_SERVER)
add_compile_definitions(APP_DATA_DIR="\$\{HOME\}/spark_api/")
add_compile_definitions(SHARED_MEMORY_PREFIX="spark_api")
elseif(BUILD_SPARKD)
add_compile_definitions(SHARED_MEMORY_PREFIX="sparkd")
add_compile_definitions(APP_DATA_DIR="\$\{HOME\}/sparkdata/")
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)
@@ -90,9 +90,15 @@ else()
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")
add_compile_definitions(CCAPI_BINANCE_USDS_FUTURES_URL_REST_BASE="https://fapi.binance.com")
add_compile_definitions(BINANCE_USDS_FUTURES_INSTRUMENTS_PATH="/fapi/v1/exchangeInfo")
add_compile_definitions(BINANCE_USDS_FUTURES_PRICE_STATS_PATH="/fapi/v1/ticker/24hr")
add_compile_definitions(BINANCE_USDS_FUTURES_USER_DATA_PATH="/api/v3/userDataStream")
# ** Binance Coin Futures **
add_compile_definitions(CCAPI_BINANCE_COIN_FUTURES_URL_REST_BASE="https://dapi.binance.com")
add_compile_definitions(BINANCE_COIN_FUTURES_INSTRUMENTS_PATH="/dapi/v1/exchangeInfo")
add_compile_definitions(BINANCE_COIN_FUTURES_PRICE_STATS_PATH="/dapi/v1/ticker/24hr")
# ** Deribit **
add_compile_definitions(DERIBIT_INSTRUMENT_PATH="/api/v2/public/get_instrument")
@@ -112,6 +118,7 @@ else()
# subdirs
if (BUILD_SPARKD)
add_subdirectory(src/lib_binance_execution)
add_subdirectory(src/server/sparkd)
add_subdirectory(src/data_files)
endif()
@@ -133,6 +140,8 @@ else()
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/server/sparkd/sparkd ${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/data_files ${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/lib/libspark.so ${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${EXTERNALS_ROOT}/lib/${CMAKE_BUILD_TYPE}/libonixs-fix-engine.so.4 ${CMAKE_BINARY_DIR}/server
COMMAND
ln ARGS -sf
${EXTERNALS_ROOT}/lib/Release/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0
@@ -146,11 +155,14 @@ else()
install(
DIRECTORY "${CMAKE_BINARY_DIR}/server/plugins"
DESTINATION "${SPARK_INSTALL_PREFIX}/bin")
DESTINATION "${CMAKE_INSTALL_BINDIR}")
install(
FILES
"${SPARK_LIB}/libACE-5.7.5.so"
"${SPARK_LIB}/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0"
DESTINATION "${SPARK_INSTALL_PREFIX}/bin")
"${SPARK_LIB}/libonixs-fix-engine.so.4.10.1"
"${SPARK_LIB}/libonixs-fix-engine.so.4"
"${SPARK_LIB}/libonixs-fix-engine.so"
DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif()
endif()
+122 -74
View File
@@ -15,22 +15,30 @@
"rhs": "Windows"
},
"generator": "Visual Studio 17 2022",
"binaryDir": "${sourceDir}/build",
"binaryDir": "${sourceDir}/build/${presetName}",
"environment": {
"SPARK_CMAKE_CXX_FLAGS": "/MP /WX /wd4250 /wd4251 /wd4244 /wd4267 /wd4355 /wd4275 /wd4345 /bigobj /EHsc /DCURL_STATICLIB /D_WINSOCK_DEPRECATED_NO_WARNINGS /D__TBB_NO_IMPLICIT_LINKAGE /DBOOST_ALL_NO_LIB /std:c++20 /D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600"
},
"cacheVariables": {
"APP_DATA_DIR": "${dollar}{APPDATA}/bts",
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARK_DATA_DIR}",
"CMAKE_CXX_FLAGS": "$env{SPARK_CMAKE_CXX_FLAGS}",
"CMAKE_CXX_FLAGS_DEBUG": "$env{SPARK_CMAKE_CXX_FLAGS} /MTd",
"CMAKE_CXX_FLAGS_RELEASE": "$env{SPARK_CMAKE_CXX_FLAGS} /MT",
"CMAKE_CXX_STANDARD": "20",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}",
"CMAKE_SHARED_LINKER_FLAGS_DEBUG": "/DEBUG",
"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": "config/profiles/default/*.conf",
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0",
"DOTNET_WINDOWS_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0-windows"
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net8.0",
"DOTNET_WINDOWS_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net8.0-windows",
"EXPORT_MD_CONSUMER": {
"type": "BOOL",
"value": "ON"
},
"SHARED_MEMORY_PREFIX": "spark"
}
},
@@ -46,14 +54,21 @@
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"platform": "",
"APP_DATA_DIR": "${dollar}{HOME}/sparkdata",
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARKD_DATA_DIR}",
"CMAKE_BUILD_WITH_INSTALL_RPATH": {
"type": "BOOL",
"value": "ON"
},
"CMAKE_CXX_STANDARD": "20",
"CMAKE_INSTALL_RPATH": ".",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}/sparkd",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}",
"CMAKE_EXE_LINKER_FLAGS": "-Wno-undef",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
"DATABENTO_USE_EXTERNAL_JSON": {
"type": "BOOL",
"value": "ON"
},
"EXTERNALS_ROOT": "${sourceDir}/externals/linux",
"BUILD_SDK": {
"type": "BOOL",
@@ -62,7 +77,8 @@
"BUILD_ADMIN_WEB_APP": {
"type": "BOOL",
"value": "ON"
}
},
"SHARED_MEMORY_PREFIX": "sparkd"
}
},
@@ -95,98 +111,72 @@
{
"name": "sparkd-debug-clang",
"inherits": "sparkd-debug",
"displayName": "Debug (clang)",
"displayName": "Sparkd (Debug | Clang)",
"description": "Debug build compiled w/ clang",
"binaryDir": "${sourceDir}/build/clang/debug",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"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_INSTALL_PREFIX": "${sourceDir}/install/clang/debug/sparkd"
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -DDEBUG"
}
},
{
"name": "sparkd-debug-gcc",
"inherits": "sparkd-debug",
"displayName": "Debug (gcc)",
"displayName": "Sparkd (Debug | Gcc)",
"description": "Debug build compiled w/ gcc",
"binaryDir": "${sourceDir}/build/gcc/debug",
"cacheVariables": {
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -Wno-stringop-overread -DDEBUG",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/gcc/debug/sparkd"
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -Wno-stringop-overread -DDEBUG"
}
},
{
"name": "sparkd-release-clang",
"inherits": "sparkd-release",
"displayName": "Release (clang)",
"displayName": "Sparkd (Release | Clang)",
"description": "Release build compiled w/ clang",
"binaryDir": "${sourceDir}/build/clang/release",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++",
"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",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/clang/release/sparkd"
"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"
}
},
{
"name": "sparkd-release-gcc",
"inherits": "sparkd-release",
"displayName": "Release (gcc)",
"displayName": "Sparkd (Release | Gcc)",
"description": "Release build compiled w/ gcc",
"binaryDir": "${sourceDir}/build/gcc/release",
"cacheVariables": {
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -Wno-stringop-overread -Wno-maybe-uninitialized -fno-omit-frame-pointer -DNDEBUG -O3",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/gcc/release/sparkd"
}
},
{
"name": "spark-api-server-base",
"hidden": true,
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"BUILD_API_SERVER": {
"type": "bool",
"value": "ON"
},
"CONFIG_DEFAULTS_PATH": "config/profiles/md_dev/*.conf;config/profiles/default/*.conf"
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers -Wno-stringop-overflow --std=c++20 -fdiagnostics-color -Wno-stringop-overread -Wno-maybe-uninitialized -fno-omit-frame-pointer -DNDEBUG -O3"
}
},
{
"name": "spark-api-server-windows",
"inherits": "spark",
"displayName": "Spark Api Server",
"displayName": "Spark Api Server (Windows)",
"cacheVariables": {
"BUILD_API_SERVER": {
"type": "bool",
"value": "ON"
}
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARK_API_SERVER_DATA_DIR}",
"SHARED_MEMORY_PREFIX": "spark_api_server"
}
},
{
"name": "spark-api-server-linux",
"inherits": "sparkd",
"displayName": "Spark Api Server",
"displayName": "Spark Api Server (Linux)",
"generator": "Ninja Multi-Config",
"cacheVariables": {
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARK_API_SERVER_DATA_DIR}",
"BUILD_ADMIN_WEB_APP": {
"type": "BOOL",
"value": "OFF"
},
"BUILD_API_SERVER": {
"type": "bool",
"value": "ON"
},
"BUILD_SPARKD": {
"type": "BOOL",
"value": "OFF"
@@ -197,7 +187,11 @@
"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",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}",
"CONFIG_DEFAULTS_PATH": "config/profiles/default/*.conf",
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0"
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net8.0",
"EXPORT_MD_CONSUMER": {
"type": "BOOL",
"value": "ON"
}
}
},
@@ -220,13 +214,62 @@
},
{
"name": "data-stream-suite",
"name": "data-stream-suite-windows",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"inherits": "spark",
"displayName": "Data Stream Suite",
"displayName": "Data Stream Suite (Windows)",
"description": "Data Stream utils ported over from Edge",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CONFIG_DEFAULTS_PATH": "config/profiles/default/*.conf;config/profiles/data_stream/*.conf"
"APP_DATA_DIR": "${dollar}{APPDATA}/bts/DataStream",
"APP_DATA_DIR_OVERRIDE": "${dollar}{DATA_STREAM_DATA_DIR}",
"CONFIG_DEFAULTS_PATH": "config/profiles/default/*.conf;config/profiles/data_stream/*.conf",
"SHARED_MEMORY_PREFIX": "data_stream"
}
},
{
"name": "data-stream-suite-linux",
"displayName": "Data Stream Suite (Linux)",
"description": "Data Stream utils ported over from Edge",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"inherits": "sparkd",
"generator": "Ninja Multi-Config",
"cacheVariables": {
"APP_DATA_DIR": "${dollar}{HOME}/.local/share/DataStream",
"APP_DATA_DIR_OVERRIDE": "${dollar}{DATA_STREAM_DATA_DIR}",
"BUILD_ADMIN_WEB_APP": {
"type": "BOOL",
"value": "OFF"
},
"BUILD_SDK": {
"type": "BOOL",
"value": "OFF"
},
"BUILD_SPARKD": {
"type": "BOOL",
"value": "OFF"
},
"CMAKE_C_COMPILER": "clang",
"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",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}",
"CONFIG_DEFAULTS_PATH": "config/profiles/default/*.conf;config/profiles/data_stream/*.conf",
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0",
"EXPORT_MD_CONSUMER": {
"type": "BOOL",
"value": "ON"
},
"SHARED_MEMORY_PREFIX": "data_stream"
}
}
],
@@ -244,7 +287,7 @@
{
"name": "spark-debug",
"displayName": "Debug",
"displayName": "Spark (Debug)",
"inherits": "spark",
"configurePreset": "spark",
"configuration": "Debug"
@@ -252,7 +295,7 @@
{
"name": "spark-release",
"displayName": "Release",
"displayName": "Spark (Release)",
"inherits": "spark",
"configurePreset": "spark",
"configuration": "Release"
@@ -265,43 +308,34 @@
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"hidden": true,
"targets": [
"data_files_dir",
"admin_web_app_bundle",
"install",
"libspark",
"rapidjson_project",
"server_layout",
"sparkd"
]
"hidden": true
},
{
"name": "sparkd-debug-clang",
"configurePreset": "sparkd-debug-clang",
"displayName": "Debug (clang)",
"displayName": "Sparkd (Debug | Clang)",
"inherits": "sparkd"
},
{
"name": "sparkd-debug-gcc",
"configurePreset": "sparkd-debug-gcc",
"displayName": "Debug (gcc)",
"displayName": "Sparkd (Debug | Gcc)",
"inherits": "sparkd"
},
{
"name": "sparkd-release-clang",
"configurePreset": "sparkd-release-clang",
"displayName": "Release (clang)",
"displayName": "Sparkd (Release | Clang)",
"inherits": "sparkd"
},
{
"name": "sparkd-release-gcc",
"configurePreset": "sparkd-release-gcc",
"displayName": "Release (gcc)",
"displayName": "Sparkd (Release | Gcc)",
"inherits": "sparkd"
},
@@ -318,14 +352,14 @@
{
"name": "spark-api-server-windows-debug",
"displayName": "Spark Api Server (Debug)",
"displayName": "Spark Api Server (Windows | Debug)",
"inherits": "spark-api-server-windows",
"configuration": "Debug"
},
{
"name": "spark-api-server-windows-release",
"displayName": "Spark Api Server (Debug)",
"displayName": "Spark Api Server (Windows | Release)",
"inherits": "spark-api-server-windows",
"configuration": "Release"
},
@@ -344,14 +378,14 @@
{
"name": "spark-api-server-linux-debug",
"inherits": "spark-api-server-linux",
"displayName": "Spark Api Server (Debug)",
"displayName": "Spark Api Server (Linux | Debug)",
"configuration": "Debug"
},
{
"name": "spark-api-server-linux-release",
"inherits": "spark-api-server-linux",
"displayName": "Spark Api Server (Release)",
"displayName": "Spark Api Server (Linux | Release)",
"configuration": "Release"
},
@@ -371,16 +405,30 @@
},
{
"name": "data-stream-suite-debug",
"displayName": "DataStreamSuite (Debug)",
"configurePreset": "data-stream-suite",
"name": "data-stream-suite-windows-debug",
"displayName": "Data Stream Suite (Windows | Debug)",
"configurePreset": "data-stream-suite-windows",
"configuration": "Debug"
},
{
"name": "data-stream-suite-release",
"displayName": "DataStreamSuite (Release)",
"configurePreset": "data-stream-suite",
"name": "data-stream-suite-windows-release",
"displayName": "Data Stream Suite (Windows | Release)",
"configurePreset": "data-stream-suite-windows",
"configuration": "Release"
},
{
"name": "data-stream-suite-linux-debug",
"displayName": "Data Stream Suite (Linux | Debug)",
"configurePreset": "data-stream-suite-linux",
"configuration": "Debug"
},
{
"name": "data-stream-suite-linux-release",
"displayName": "Data Stream Suite (Linux | Release)",
"configurePreset": "data-stream-suite-linux",
"configuration": "Release"
}
]
+139
View File
@@ -14,6 +14,34 @@ 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
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -70,6 +98,102 @@ 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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -80,4 +204,19 @@ 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
+48
View File
@@ -0,0 +1,48 @@
include_guard(GLOBAL)
function(get_version_from_git)
find_package(Git QUIET)
if(NOT Git_FOUND)
message(WARNING "Git not found")
return()
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --tags --always
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_TAG
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE GIT_RESULT
)
if(NOT GIT_RESULT EQUAL 0)
message(WARNING "Failed to get git tag")
return()
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --short=7 HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_SHORT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(PROJECT_VERSION_BUILD_METADATA ${GIT_COMMIT_SHORT_HASH})
set(PROJECT_VERSION_BUILD_METADATA ${GIT_COMMIT_SHORT_HASH} PARENT_SCOPE)
string(REGEX REPLACE "^v" "" CLEAN_TAG "${GIT_TAG}")
if(CLEAN_TAG MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-.*)?$")
set(PROJECT_VERSION_MAJOR ${CMAKE_MATCH_1})
set(PROJECT_VERSION_MAJOR ${CMAKE_MATCH_1} PARENT_SCOPE)
set(PROJECT_VERSION_MINOR ${CMAKE_MATCH_2})
set(PROJECT_VERSION_MINOR ${CMAKE_MATCH_2} PARENT_SCOPE)
set(PROJECT_VERSION_PATCH ${CMAKE_MATCH_3})
set(PROJECT_VERSION_PATCH ${CMAKE_MATCH_3} PARENT_SCOPE)
set(PROJECT_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
set(PROJECT_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}" PARENT_SCOPE)
set(PROJECT_VERSION_FULL "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}+${GIT_COMMIT_SHORT_HASH}")
set(PROJECT_VERSION_FULL "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}+${GIT_COMMIT_SHORT_HASH}" PARENT_SCOPE)
else()
message(WARNING "Tag '${CLEAN_TAG}' does not match semver format")
endif()
endfunction()
+49
View File
@@ -0,0 +1,49 @@
include_guard(DIRECTORY)
function(protobuf_generate_fs)
set(_options)
set(_one_value_args TARGET_NAME OUT_DIR PROTOC)
set(_multi_value_args PROTO_INCLUDE_DIRS PROTO_SOURCES)
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
if (NOT DEFINED _ARGS_TARGET_NAME)
set(_ARGS_TARGET_NAME "${PROJECT_NAME}_generate_fs_protos")
endif()
if (NOT DEFINED _ARGS_PROTOC)
set(_ARGS_PROTOC "${SPARK_BIN}/protoc")
endif()
set(_proto_include_cli_args)
foreach(_dir ${_ARGS_PROTO_INCLUDE_DIRS})
list(APPEND _proto_include_cli_args -I ${_dir})
endforeach()
set(_outputs)
foreach(_proto_source ${_ARGS_PROTO_SOURCES})
# get_filename_component(_abs_proto_source ${_proto_source} ABSOLUTE)
get_filename_component(_proto_source_we ${_proto_source} NAME_WE)
# get_filename_component(_proto_source_dir ${_proto_source} DIRECTORY)
list(APPEND _outputs ${_ARGS_OUT_DIR}/${_proto_source_we}.fable.fs)
endforeach()
set(_venv_exec ${CMAKE_SOURCE_DIR}/tools/venv_exec.sh)
set(_plugin_py ${CMAKE_SOURCE_DIR}/src/lib/api/service_compiler/plugin.py)
set(_template_fs ${CMAKE_SOURCE_DIR}/src/lib/api/service_compiler/templates/fs/fable.fs)
add_custom_command(
OUTPUT ${_outputs}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${_venv_exec}
${_ARGS_PROTOC}
--plugin=protoc-gen-service=${_plugin_py}
--service_out=lang=fs,strip_out_path=1:${_ARGS_OUT_DIR}
${_proto_include_cli_args}
${_ARGS_PROTO_SOURCES}
DEPENDS
${_venv_exec}
${_plugin_py}
${_template_fs}
${CMAKE_CURRENT_SOURCE_DIR}/package-lock.json
${_ARGS_PROTO_SOURCES}
)
add_custom_target(${_ARGS_TARGET_NAME} ALL DEPENDS "${_outputs}")
endfunction()
+33
View File
@@ -0,0 +1,33 @@
include_guard(DIRECTORY)
function(protobuf_generate_js)
set(_options)
set(_one_value_args TARGET_NAME OUTPUT)
set(_multi_value_args PROTO_INCLUDE_DIRS PROTO_SOURCES)
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
if (NOT DEFINED _ARGS_TARGET_NAME)
set(_ARGS_TARGET_NAME "${PROJECT_NAME}_generate_js_protos")
endif()
set(_proto_include_cli_args)
foreach(_dir ${_ARGS_PROTO_INCLUDE_DIRS})
list(APPEND _proto_include_cli_args -p ${_dir})
endforeach()
add_custom_command(
OUTPUT ${_ARGS_OUTPUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND npx
--no-install pbjs
-t json-module
-w commonjs
-o ${_ARGS_OUTPUT}
${_proto_include_cli_args}
${_ARGS_PROTO_SOURCES}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/package-lock.json
${_ARGS_PROTO_SOURCES}
)
add_custom_target(${_ARGS_TARGET_NAME} ALL DEPENDS ${_ARGS_OUTPUT})
endfunction()
+49
View File
@@ -0,0 +1,49 @@
include_guard(DIRECTORY)
include(${CMAKE_SOURCE_DIR}/cmake/TernaryOperator.cmake)
function(sym_link_dir)
set(_options)
set(_one_value_args TARGET_NAME SOURCE DEST COMMENT)
set(_multi_value_args)
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
add_custom_command(
OUTPUT ${_ARGS_DEST}
COMMAND ln ARGS -sf ${_ARGS_SOURCE} ${_ARGS_DEST}
)
set_ternary(_comment _ARGS_COMMENT "${_ARGS_COMMENT}" "linking dir ${_ARGS_SOURCE} -> ${_ARGS_DEST}")
add_custom_target(
${_ARGS_TARGET_NAME} ALL
DEPENDS ${_ARGS_DEST}
COMMENT "${_comment}"
)
endfunction()
function(sym_link_file)
set(_options)
set(_one_value_args 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
)
if (DEFINED _ARGS_INSTALL_DEST)
install(
FILES
${_ARGS_SOURCE}
DESTINATION ${_ARGS_INSTALL_DEST}
)
endif()
endfunction()
function(sym_link_local_lib LIB_NAME)
set(_lib_file_name "${CMAKE_SHARED_LIBRARY_PREFIX}${LIB_NAME}.so")
file(
CREATE_LINK
"${CMAKE_BINARY_DIR}/src/lib_${LIB_NAME}/${_lib_file_name}"
"${CMAKE_CURRENT_BINARY_DIR}/${_lib_file_name}"
SYMBOLIC
)
endfunction()
+9
View File
@@ -0,0 +1,9 @@
include_guard(GLOBAL)
macro(set_ternary RESULT CONDITION TRUE_VALUE FALSE_VALUE)
if(${CONDITION})
set(${RESULT} ${TRUE_VALUE})
else()
set(${RESULT} ${FALSE_VALUE})
endif()
endmacro()
+11
View File
@@ -0,0 +1,11 @@
#ifndef BTS_SPARK_VERSION_H
#define BTS_SPARK_VERSION_H
#define BTS_SPARK_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define BTS_SPARK_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define BTS_SPARK_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define BTS_SPARK_VERSION_BUILD_METADATA @PROJECT_VERSION_BUILD_METADATA@
#define BTS_SPARK_VERSION "@PROJECT_VERSION@"
#define BTS_SPARK_VERSION_FULL "@PROJECT_VERSION_FULL@"
#endif
+104
View File
@@ -0,0 +1,104 @@
services:
sparkd:
volumes:
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/sparkdata/data
build:
dockerfile: src/server/sparkd/Dockerfile
args:
- IMAGE=${SPARKD__IMAGE}
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
- CONFIG_DIR=${SPARKD__CONFIG_DIR}
shm_size: "${SPARKD__SHM_SIZE:-512mb}"
command: >
sh -c "
echo bts | sudo -S chown -R bts:bts /home/bts/sparkdata/data
if [ -e "/home/bts/sparkdata/data/logging.sparkd/log" ]; then
mv "/home/bts/sparkdata/data/logging.sparkd/log" "/home/bts/sparkdata/data/logging.sparkd/log_$(date '+%Y%m%d-%H%M')"
fi
if [ -e "/home/bts/sparkdata/conf/.env.local" ]; then
echo 'Sourcing /home/bts/sparkdata/conf/.env.local'
set -a
. /home/bts/sparkdata/conf/.env.local
set +a
fi
./sparkd run"
env_file:
- .env
- ${SPARKD__CONFIG_DIR}/.env
ports:
- "${SPARKD__CONFIG_PORT}:${SPARKD__CONFIG_PORT}"
- "${SPARKD__QUICKBUS_PORT}:${SPARKD__QUICKBUS_PORT}"
- "${SPARKD__SIM_FIX_PORT}:${SPARKD__SIM_FIX_PORT}"
deploy:
resources:
limits:
memory: "${SPARKD__MEMORY:-4gb}"
sparkd-symbols:
volumes:
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/sparkdata/data
- ${SPARKD__RUNTIME_CONF_DIR:-sparkd_conf}:/home/bts/sparkdata/conf
build:
dockerfile: src/server/sparkd/Dockerfile
args:
- IMAGE=${SPARKD__IMAGE}
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
- CONFIG_DIR=${SPARKD__CONFIG_DIR}
shm_size: "${SPARKD__SHM_SIZE:-512mb}"
command: >
sh -c "
echo bts | sudo -S chown -R bts:bts /home/bts/sparkdata
if [ -e "/home/bts/sparkdata/data/logging.sparkd/log" ]; then
mv "/home/bts/sparkdata/data/logging.sparkd/log" "/home/bts/sparkdata/data/logging.sparkd/log_$(date '+%Y%m%d-%H%M')"
fi
ls -alh /home/bts/sparkdata/conf/
cat /home/bts/sparkdata/conf/.env.local
if [ -e "/home/bts/sparkdata/conf/.env.local" ]; then
echo 'Sourcing /home/bts/sparkdata/conf/.env.local'
set -a
. /home/bts/sparkdata/conf/.env.local
set +a
fi
./sparkd run"
env_file:
- .env
- ${SPARKD__CONFIG_DIR}/.env
ports:
- "${SPARKD__CONFIG_PORT}:${SPARKD__CONFIG_PORT}"
- "${SPARKD__QUICKBUS_PORT}:${SPARKD__QUICKBUS_PORT}"
- "${SPARKD__SIM_FIX_PORT}:${SPARKD__SIM_FIX_PORT}"
deploy:
restart_policy:
condition: any
delay: 3s
resources:
limits:
memory: "${SPARKD__MEMORY:-4gb}"
sparkd-tail:
image: bluetradingsystems/linux_dotnet7
volumes:
- type: volume
read_only: true
source: sparkd_data
target: /home/bts/sparkdata/data/logging.sparkd
volume:
subpath: logging.sparkd
command: ["tail", "-f", "/home/bts/sparkdata/data/logging.sparkd/log"]
sparkd-ping-test:
depends_on:
- sparkd
profiles:
- ping-test
build:
context: .
dockerfile_inline: |
FROM bluetradingsystems/linux_dotnet7
USER "root"
RUN apt-get update && apt-get -y install iputils-ping
command: [ "ping", "sparkd" ]
volumes:
sparkd_data:
name: "sparkd_${SPARKD__CONFIG_PORT:-8000}"
@@ -0,0 +1,38 @@
FROM ubuntu:22.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y pkg-config
RUN apt-get update && apt-get install -y locales
RUN apt-get update && apt-get install -y ca-certificates
RUN apt-get update && apt-get install -y libssh2-1-dev
RUN apt-get update && apt-get install -y software-properties-common
RUN apt-get update && apt-get install -y sudo
# GCC
ARG gcc_major=13
RUN add-apt-repository ppa:ubuntu-toolchain-r/test \
&& apt-get update \
&& apt-get install -y g++-$gcc_major
RUN apt-get update \
&& apt-get install -y dotnet7
RUN locale-gen en_US.UTF-8
ARG docker_user="bts"
ARG docker_uid="1000"
ARG docker_pass="bts"
RUN \
groupadd -g "$docker_uid" "$docker_user" \
&& useradd \
-m \
-u "$docker_uid" \
-g "$docker_uid" \
-G sudo \
--password "$(openssl passwd -1 "$docker_pass")" \
"$docker_user"
USER bts
WORKDIR /home/bts
Submodule
+1
Submodule docker/linux added at 6537812262.
+1
Submodule docker/windows added at de7d40c09d.
-45
View File
@@ -1,45 +0,0 @@
/* global use, db */
// MongoDB Playground
// To disable this template go to Settings | MongoDB | Use Default Template For Playground.
// Make sure you are connected to enable completions and to be able to run a playground.
// Use Ctrl+Space inside a snippet or a string literal to trigger completions.
// The result of the last command run in a playground is shown on the results panel.
// By default the first 20 documents will be returned with a cursor.
// Use 'console.log()' to print to the debug output.
// For more documentation on playgrounds please refer to
// https://www.mongodb.com/docs/mongodb-vscode/playgrounds/
// Select the database to use.
use('mongodbVSCodePlaygroundDB');
// Insert a few documents into the sales collection.
db.getCollection('sales').insertMany([
{ 'item': 'abc', 'price': 10, 'quantity': 2, 'date': new Date('2014-03-01T08:00:00Z') },
{ 'item': 'jkl', 'price': 20, 'quantity': 1, 'date': new Date('2014-03-01T09:00:00Z') },
{ 'item': 'xyz', 'price': 5, 'quantity': 10, 'date': new Date('2014-03-15T09:00:00Z') },
{ 'item': 'xyz', 'price': 5, 'quantity': 20, 'date': new Date('2014-04-04T11:21:39.736Z') },
{ 'item': 'abc', 'price': 10, 'quantity': 10, 'date': new Date('2014-04-04T21:23:13.331Z') },
{ 'item': 'def', 'price': 7.5, 'quantity': 5, 'date': new Date('2015-06-04T05:08:13Z') },
{ 'item': 'def', 'price': 7.5, 'quantity': 10, 'date': new Date('2015-09-10T08:43:00Z') },
{ 'item': 'abc', 'price': 10, 'quantity': 5, 'date': new Date('2016-02-06T20:20:13Z') },
]);
// Run a find command to view items sold on April 4th, 2014.
const salesOnApril4th = db.getCollection('sales').find({
date: { $gte: new Date('2014-04-04'), $lt: new Date('2014-04-05') }
}).count();
// Print a message to the output window.
console.log(`${salesOnApril4th} sales occurred in 2014.`);
// Here we run an aggregation and open a cursor to the results.
// Use '.toArray()' to exhaust the cursor to return the whole result set.
// You can use '.hasNext()/.next()' to iterate through the cursor page by page.
db.getCollection('sales').aggregate([
// Find all of the sales that occurred in 2014.
{ $match: { date: { $gte: new Date('2014-01-01'), $lt: new Date('2015-01-01') } } },
// Group the total sales for each product.
{ $group: { _id: '$item', totalSaleAmount: { $sum: { $multiply: ['$price', '$quantity'] } } } }
]);
+14
View File
@@ -1,11 +1,20 @@
astroid==2.7.3
autopep8==1.5.7
blinker==1.9.0
boto3==1.37.9
botocore==1.37.9
certifi==2023.5.7
charset-normalizer==3.1.0
click==8.1.8
colorama==0.4.4
Flask==3.1.0
idna==3.4
isort==5.9.3
itsdangerous==2.2.0
Jinja2==3.1.6
jmespath==1.0.1
lazy-object-proxy==1.6.0
MarkupSafe==3.0.2
mccabe==0.6.1
platformdirs==2.3.0
protobuf==4.21.12
@@ -14,9 +23,14 @@ pycodestyle==2.7.0
pycparser==2.20
pylint==2.10.2
PyMeta3==0.5.1
python-dateutil==2.9.0.post0
python-dotenv==1.0.1
requests==2.31.0
s3transfer==0.11.4
six==1.17.0
termcolor==1.1.0
toml==0.10.2
urllib3==2.0.3
Werkzeug==3.1.3
wrapt==1.12.1
yapf==0.31.0
@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
<PackageReference Include="YaccLexTools" Version="1.2.0" />
<PackageReference Include="YaccLexTools" Version="1.2.2" />
</ItemGroup>
<ItemGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
+15 -34
View File
@@ -1,41 +1,22 @@
using mbts.spark;
using System.Diagnostics;
using System;
using System.Runtime;
namespace BCG.Utilities.General;
namespace BCG.Utilities.General
{
/// <summary>
/// Summary description for Crono.
/// </summary>
public class Crono
{
public Crono()
{
myTimer = new HighPerformanceTimer();
}
/// <summary>
/// Summary description for Crono.
/// </summary>
public class Crono {
readonly Stopwatch myTimer = new();
public void start()
{myTimer.start();}
public void start() =>
myTimer.Start();
public void stop()
{myTimer.stop();}
public void stop() =>
myTimer.Stop();
public TimeSpan time
{
get
{
return new TimeSpan((long) (myTimer.totalMilliseconds * TimeSpan.TicksPerMillisecond));
}
}
public double miliseconds
{
get
{return myTimer.totalMilliseconds;}
}
private HighPerformanceTimer myTimer;
}
public TimeSpan time =>
myTimer.Elapsed;
public double miliseconds =>
myTimer.Elapsed.TotalMilliseconds;
}
+192 -192
View File
@@ -1,192 +1,192 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Reflection;
using Microsoft.Win32;
namespace BCG
{
public enum RegistryRoot { HKCU, HKLM }
[Serializable]
public class BlueRegistry
{
public const string BlueSubKey = @"Software\Blue Capital Group\";
public static readonly string ApplicationPrefix;
protected string myFullPath;
public BlueRegistry(string subPath)
{
myFullPath = string.Concat(BlueRegistry.ApplicationPrefix, @"\", subPath);
}
public BlueRegistry(BlueRegistry parent, string subPath)
{
myFullPath = string.Concat(parent.myFullPath, @"\", subPath);
}
static BlueRegistry()
{
string app = "Applications";
Assembly ass = Assembly.GetEntryAssembly();
if (ass != null)
{
app = ass.GetName().Name;
object[] attrs = ass.GetCustomAttributes(
Type.GetType("System.Reflection.AssemblyTitleAttribute"), true);
if (attrs.Length > 0 && ((AssemblyTitleAttribute)attrs[0]).Title != string.Empty)
{
app = ((AssemblyTitleAttribute)attrs[0]).Title;
}
}
ApplicationPrefix = string.Concat(BlueRegistry.BlueSubKey, app);
}
public object getValue(string name)
{
return getValue(RegistryRoot.HKCU, name);
}
public object getValue(string name, object defaultValue)
{
return getValue(RegistryRoot.HKCU, name, defaultValue);
}
public void setValue(string name, object value)
{
setValue(RegistryRoot.HKCU, name, value);
}
public void deleteValue(string name)
{
deleteValue(RegistryRoot.HKCU, name);
}
private RegistryKey myGetRegistryKey(RegistryRoot root)
{
if (root == RegistryRoot.HKCU)
return Registry.CurrentUser.CreateSubKey(myFullPath);
else
return Registry.LocalMachine.CreateSubKey(myFullPath);
}
#region Generic Methods
internal virtual void setValue(RegistryRoot root, string name, object value)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
rk.SetValue(name, value);
}
}
internal virtual object getValue(RegistryRoot root, string name)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return rk.GetValue(name);
}
}
internal virtual void deleteValue(RegistryRoot root, string name)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
rk.DeleteValue(name);
}
}
internal virtual object getValue(RegistryRoot root, string name, object defaultValue)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return rk.GetValue(name, defaultValue);
}
}
#endregion
#region Double
internal virtual void setDouble(RegistryRoot root, string name, double value)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
DoubleRegistryHandler.setValue(rk, name, value);
}
}
internal virtual double getDouble(RegistryRoot root, string name)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return DoubleRegistryHandler.getValue(rk, name);
}
}
#endregion
#region Enum
internal virtual void setEnum(RegistryRoot root, string name, Enum value)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
EnumRegistryHandler.setValue(rk, name, value);
}
}
internal virtual Enum getEnum(RegistryRoot root, string name, Type enumType)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return EnumRegistryHandler.getValue(rk, name, enumType);
}
}
#endregion
#region Array
internal virtual void setArray(RegistryRoot root, string name, Array array)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
ArrayRegistryHandler.setValue(rk, name, array);
}
}
internal virtual Array getArray(RegistryRoot root, string name, Type elementType)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return ArrayRegistryHandler.getValue(rk, name, elementType);
}
}
#endregion
#region SortedList
internal virtual void setSortedList(RegistryRoot root, string name, SortedList slist)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
SortedListRegistryHandler.setValue(rk, name, slist);
}
}
internal virtual SortedList getSortedList(RegistryRoot root, string name)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return SortedListRegistryHandler.getValue(rk, name);
}
}
internal virtual void deleteSortedList(RegistryRoot root, string name)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
SortedListRegistryHandler.deleteValue(rk, name);
}
}
#endregion
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Reflection;
using Microsoft.Win32;
namespace BCG
{
public enum RegistryRoot { HKCU, HKLM }
[Serializable]
public class BlueRegistry
{
public const string BlueSubKey = @"Software\Blue Capital Group\";
public static readonly string ApplicationPrefix;
protected string myFullPath;
public BlueRegistry(string subPath)
{
myFullPath = string.Concat(BlueRegistry.ApplicationPrefix, @"\", subPath);
}
public BlueRegistry(BlueRegistry parent, string subPath)
{
myFullPath = string.Concat(parent.myFullPath, @"\", subPath);
}
static BlueRegistry()
{
string app = "Applications";
Assembly ass = Assembly.GetEntryAssembly();
if (ass != null)
{
app = ass.GetName().Name;
object[] attrs = ass.GetCustomAttributes(
Type.GetType("System.Reflection.AssemblyTitleAttribute"), true);
if (attrs.Length > 0 && ((AssemblyTitleAttribute)attrs[0]).Title != string.Empty)
{
app = ((AssemblyTitleAttribute)attrs[0]).Title;
}
}
ApplicationPrefix = string.Concat(BlueRegistry.BlueSubKey, app);
}
public object getValue(string name)
{
return getValue(RegistryRoot.HKCU, name);
}
public object getValue(string name, object defaultValue)
{
return getValue(RegistryRoot.HKCU, name, defaultValue);
}
public void setValue(string name, object value)
{
setValue(RegistryRoot.HKCU, name, value);
}
public void deleteValue(string name)
{
deleteValue(RegistryRoot.HKCU, name);
}
private RegistryKey myGetRegistryKey(RegistryRoot root)
{
if (root == RegistryRoot.HKCU)
return Registry.CurrentUser.CreateSubKey(myFullPath);
else
return Registry.LocalMachine.CreateSubKey(myFullPath);
}
#region Generic Methods
public virtual void setValue(RegistryRoot root, string name, object value)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
rk.SetValue(name, value);
}
}
internal virtual object getValue(RegistryRoot root, string name)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return rk.GetValue(name);
}
}
internal virtual void deleteValue(RegistryRoot root, string name)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
rk.DeleteValue(name);
}
}
public virtual object getValue(RegistryRoot root, string name, object defaultValue)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return rk.GetValue(name, defaultValue);
}
}
#endregion
#region Double
internal virtual void setDouble(RegistryRoot root, string name, double value)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
DoubleRegistryHandler.setValue(rk, name, value);
}
}
internal virtual double getDouble(RegistryRoot root, string name)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return DoubleRegistryHandler.getValue(rk, name);
}
}
#endregion
#region Enum
internal virtual void setEnum(RegistryRoot root, string name, Enum value)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
EnumRegistryHandler.setValue(rk, name, value);
}
}
internal virtual Enum getEnum(RegistryRoot root, string name, Type enumType)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return EnumRegistryHandler.getValue(rk, name, enumType);
}
}
#endregion
#region Array
internal virtual void setArray(RegistryRoot root, string name, Array array)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
ArrayRegistryHandler.setValue(rk, name, array);
}
}
internal virtual Array getArray(RegistryRoot root, string name, Type elementType)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return ArrayRegistryHandler.getValue(rk, name, elementType);
}
}
#endregion
#region SortedList
internal virtual void setSortedList(RegistryRoot root, string name, SortedList slist)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
SortedListRegistryHandler.setValue(rk, name, slist);
}
}
internal virtual SortedList getSortedList(RegistryRoot root, string name)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
return SortedListRegistryHandler.getValue(rk, name);
}
}
internal virtual void deleteSortedList(RegistryRoot root, string name)
{
using (RegistryKey rk = myGetRegistryKey(root))
{
SortedListRegistryHandler.deleteValue(rk, name);
}
}
#endregion
}
}
@@ -1,10 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
</Project>
@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
<PackageReference Include="YaccLexTools" Version="1.2.0" />
<PackageReference Include="YaccLexTools" Version="1.2.3" />
</ItemGroup>
<ItemGroup>
@@ -24,8 +24,6 @@ namespace QUT.GplexBuffers
public BufferException(string message) : base(message) { }
public BufferException(string message, Exception innerException)
: base(message, innerException) { }
protected BufferException(SerializationInfo info, StreamingContext context)
: base(info, context) { }
}
internal abstract class ScanBuff
@@ -60,12 +58,10 @@ namespace QUT.GplexBuffers
return new BuildBuffer(source);
}
#if (!BYTEMODE)
public static ScanBuff GetBuffer(Stream source, int fallbackCodePage)
{
return new BuildBuffer(source, fallbackCodePage);
}
#endif // !BYTEMODE
#endif // !NOFILES
}
@@ -353,17 +349,15 @@ namespace QUT.GplexBuffers
{
FileStream fStrm = (stream as FileStream);
if (fStrm != null) FileName = fStrm.Name;
NextBlk = BlockReaderFactory.Raw(stream);
NextBlk = BlockReaderFactory.Get(stream);
}
#if (!BYTEMODE)
public BuildBuffer(Stream stream, int fallbackCodePage)
{
FileStream fStrm = (stream as FileStream);
if (fStrm != null) FileName = fStrm.Name;
NextBlk = BlockReaderFactory.Get(stream, fallbackCodePage);
}
#endif
/// <summary>
/// Marks a conservative lower bound for the buffer,
@@ -434,43 +428,19 @@ namespace QUT.GplexBuffers
//
internal static class BlockReaderFactory
{
public static BlockReader Raw(Stream stream)
{
return delegate(char[] block, int index, int number)
{
byte[] b = new byte[number];
int count = stream.Read(b, 0, number);
int i = 0;
int j = index;
for (; i < count; i++, j++)
block[j] = (char)b[i];
return count;
};
}
#if (!BYTEMODE)
public static BlockReader Get(Stream stream, int fallbackCodePage)
public static BlockReader Get(Stream stream, int fallbackCodePage = -2)
{
Encoding encoding;
int preamble = Preamble(stream);
if (preamble != 0) // There is a valid BOM here!
encoding = Encoding.GetEncoding(preamble);
else if (fallbackCodePage == -1) // Fallback is "raw" bytes
return Raw(stream);
else if (fallbackCodePage != -2) // Anything but "guess"
else if (fallbackCodePage >= 0) // Anything but "guess"
encoding = Encoding.GetEncoding(fallbackCodePage);
else // This is the "guess" option
{
int guess = new Guesser(stream).GuessCodePage();
stream.Seek(0, SeekOrigin.Begin);
if (guess == -1) // ==> this is a 7-bit file
encoding = Encoding.ASCII;
else if (guess == 65001)
encoding = Encoding.UTF8;
else // ==> use the machine default
encoding = Encoding.Default;
}
encoding = GuessEncoding(stream);
StreamReader reader = new StreamReader(stream, encoding);
return reader.Read;
}
@@ -488,6 +458,14 @@ namespace QUT.GplexBuffers
int b2 = stream.ReadByte();
if (b0 == 0xef && b1 == 0xbb && b2 == 0xbf)
return 65001; // UTF8
int b3 = stream.ReadByte();
// Check for UTF-32 BOM (Byte Order Mark)
if (b0 == 0x00 && b1 == 0x00 && b2 == 0xFE && b3 == 0xFF)
return 12001; // UTF-32BE
if (b0 == 0xFF && b1 == 0xFE && b2 == 0x00 && b3 == 0x00)
return 12000; // UTF-32LE
//
// There is no unicode preamble, so we
// return denoter for the machine default.
@@ -495,7 +473,150 @@ namespace QUT.GplexBuffers
stream.Seek(0, SeekOrigin.Begin);
return 0;
}
#endif // !BYTEMODE
private static Encoding GuessEncoding(Stream stream)
{
stream.Seek(0, SeekOrigin.Begin);
if (IsUtf16(stream, out Encoding encoding))
{
stream.Seek(0, SeekOrigin.Begin);
return encoding;
}
stream.Seek(0, SeekOrigin.Begin);
if (IsUtf8(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return Encoding.UTF8;
}
stream.Seek(0, SeekOrigin.Begin);
if (IsAscii(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return Encoding.ASCII;
}
#if !NET462_OR_GREATER
stream.Seek(0, SeekOrigin.Begin);
if (IsLatin1(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return Encoding.Latin1;
}
#endif
stream.Seek(0, SeekOrigin.Begin);
return Encoding.Default;
}
private static bool IsUtf8(Stream stream)
{
int b;
while ((b = stream.ReadByte()) != -1)
{
if ((b & 0x80) == 0) // 0xxxxxxx
{
continue;
}
else if ((b & 0xE0) == 0xC0) // 110xxxxx 10xxxxxx
{
if (!IsValidUtf8ContinuationByte(stream)) return false;
}
else if ((b & 0xF0) == 0xE0) // 1110xxxx 10xxxxxx 10xxxxxx
{
if (!IsValidUtf8ContinuationByte(stream) || !IsValidUtf8ContinuationByte(stream)) return false;
}
else if ((b & 0xF8) == 0xF0) // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
{
if (!IsValidUtf8ContinuationByte(stream) || !IsValidUtf8ContinuationByte(stream) || !IsValidUtf8ContinuationByte(stream)) return false;
}
else
{
return false;
}
}
return true;
}
private static bool IsValidUtf8ContinuationByte(Stream stream)
{
int b = stream.ReadByte();
return b != -1 && (b & 0xC0) == 0x80; // 10xxxxxx
}
private static bool IsUtf16(Stream stream, out Encoding encoding)
{
encoding = Encoding.Default;
if (stream.Length >= 2)
{
// Read the first two bytes
int b0 = stream.ReadByte();
int b1 = stream.ReadByte();
// Check for UTF-16 BOM (Byte Order Mark)
if (b0 == 0xFF && b1 == 0xFE)
{
encoding = Encoding.Unicode;
return true; // UTF-16LE
}
if (b0 == 0xFE && b1 == 0xFF)
{
encoding = Encoding.BigEndianUnicode;
return true; // UTF-16BE
}
// Reset the stream position
stream.Seek(0, SeekOrigin.Begin);
// Check for common UTF-16 patterns
byte[] buffer = new byte[2];
while (stream.Read(buffer, 0, 2) == 2)
{
if (buffer[0] == 0x00 && buffer[1] != 0x00)
{
encoding = Encoding.BigEndianUnicode;
return true; // Likely UTF-16BE
}
if (buffer[0] != 0x00 && buffer[1] == 0x00)
{
encoding = Encoding.Unicode;
return true; // Likely UTF-16LE
}
}
}
return false;
}
private static bool IsAscii(Stream stream)
{
int b;
while ((b = stream.ReadByte()) != -1)
{
// Latin1 includes byte values from 0x00 to 0xFF
if (b > 0x7F)
{
return false;
}
}
return true;
}
private static bool IsLatin1(Stream stream)
{
int b;
while ((b = stream.ReadByte()) != -1)
{
// Latin1 includes byte values from 0x00 to 0xFF
if (b > 0xFF)
{
return false;
}
}
return true;
}
}
#endif // !NOFILES
#endregion Buffer classes
@@ -540,180 +661,6 @@ namespace QUT.GplexBuffers
return 0;
}
}
#region guesser
#if (!BYTEMODE)
// ==============================================================
// ============ Encoding Guesser =============
// ==============================================================
/// <summary>
/// This class provides a simple finite state automaton that
/// scans the file looking for (1) valid UTF-8 byte patterns,
/// (2) bytes >= 0x80 which are not part of a UTF-8 sequence.
/// The method then guesses whether it is UTF-8 or maybe some
/// local machine default encoding. This works well for the
/// various Latin encodings.
/// </summary>
internal class Guesser
{
ScanBuff buffer;
public int GuessCodePage() { return Scan(); }
const int maxAccept = 10;
const int initial = 0;
const int eofNum = 0;
const int goStart = -1;
const int INITIAL = 0;
const int EndToken = 0;
#region user code
/*
* Reads the bytes of a file to determine if it is
* UTF-8 or a single-byte code page file.
*/
public long utfX;
public long uppr;
#endregion user code
int state;
int currentStart = startState[0];
int code;
#region ScannerTables
static int[] startState = new int[] { 11, 0 };
#region CharacterMap
static sbyte[] map = new sbyte[256] {
/* '\0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '\x10' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '\x20' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '@' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 'P' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '`' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 'p' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '\x80' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\x90' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\xA0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\xB0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\xC0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* '\xD0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* '\xE0' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
/* '\xF0' */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5 };
#endregion
static sbyte[][] nextState = new sbyte[][] {
new sbyte[] {0, 0, 0, 0, 0, 0},
new sbyte[] {-1, -1, 10, -1, -1, -1},
new sbyte[] {-1, -1, -1, -1, -1, -1},
new sbyte[] {-1, -1, 8, -1, -1, -1},
new sbyte[] {-1, -1, 5, -1, -1, -1},
new sbyte[] {-1, -1, 6, -1, -1, -1},
new sbyte[] {-1, -1, 7, -1, -1, -1},
null,
new sbyte[] {-1, -1, 9, -1, -1, -1},
null,
null,
new sbyte[] {-1, 1, 2, 3, 4, 2}
};
[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
// Reason for suppression: cannot have self-reference in array initializer.
static Guesser()
{
nextState[7] = nextState[2];
nextState[9] = nextState[2];
nextState[10] = nextState[2];
}
int NextState()
{
if (code == ScanBuff.EndOfFile)
return eofNum;
else
return nextState[state][map[code]];
}
#endregion
public Guesser(System.IO.Stream file) { SetSource(file); }
public void SetSource(System.IO.Stream source)
{
this.buffer = new BuildBuffer(source);
code = buffer.Read();
}
int Scan()
{
for (; ; )
{
int next;
state = currentStart;
while ((next = NextState()) == goStart)
code = buffer.Read();
state = next;
code = buffer.Read();
while ((next = NextState()) > eofNum)
{
state = next;
code = buffer.Read();
}
if (state <= maxAccept)
{
#region ActionSwitch
#pragma warning disable 162
switch (state)
{
case eofNum:
switch (currentStart)
{
case 11:
if (utfX == 0 && uppr == 0) return -1; /* raw ascii */
else if (uppr * 10 > utfX) return 0; /* default code page */
else return 65001; /* UTF-8 encoding */
break;
}
return EndToken;
case 1: // Recognized '{Upper128}', Shortest string "\xC0"
case 2: // Recognized '{Upper128}', Shortest string "\x80"
case 3: // Recognized '{Upper128}', Shortest string "\xE0"
case 4: // Recognized '{Upper128}', Shortest string "\xF0"
uppr++;
break;
case 5: // Recognized '{Utf8pfx4}{Utf8cont}', Shortest string "\xF0\x80"
uppr += 2;
break;
case 6: // Recognized '{Utf8pfx4}{Utf8cont}{2}', Shortest string "\xF0\x80\x80"
uppr += 3;
break;
case 7: // Recognized '{Utf8pfx4}{Utf8cont}{3}', Shortest string "\xF0\x80\x80\x80"
utfX += 3;
break;
case 8: // Recognized '{Utf8pfx3}{Utf8cont}', Shortest string "\xE0\x80"
uppr += 2;
break;
case 9: // Recognized '{Utf8pfx3}{Utf8cont}{2}', Shortest string "\xE0\x80\x80"
utfX += 2;
break;
case 10: // Recognized '{Utf8pfx2}{Utf8cont}', Shortest string "\xC0\x80"
utfX++;
break;
default:
break;
}
#pragma warning restore 162
#endregion
}
}
}
} // end class Guesser
#endif // !BYTEMODE
#endregion
#endif // !NOFILES
// End of code copied from embedded resource
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="YaccLexTools" Version="1.2.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DataStreamCore\DataStreamCore.csproj" />
<ProjectReference Include="..\ExpressionCore\ExpressionCore.csproj" />
<ProjectReference Include="..\..\client\spark_core\spark_core.csproj" />
</ItemGroup>
<ItemGroup Label="ColumnExpression">
<Scanner Include="ColumnExpressionTokens.lex" />
<Parser Include="ColumnExpressionGrammar.y" />
</ItemGroup>
</Project>
Whitespace-only changes.
@@ -0,0 +1,62 @@
namespace Bts.ColumnExpressions;
public class ColumnExpression {
public ColumnExpression(string name, Type? type = null, object? value = null) {
Name = name;
Type = type
?? value?.GetType()
?? throw new ArgumentException(
"Type must be specified explicitly when value is null", nameof(type));
Value = value
?? DBNull.Value;
}
public string Name { get; }
public Type Type { get; }
public object Value { get; }
public static ColumnExpression Create<T>(string name, T value, Type? type = null) {
// Try to convert value to 'type' to verify they are compatible
// Note: Can't use `System.Type.IsAssignableFrom` because it doesn't
// account for implicit conversions (e.g., int -> long), just inheritance.
if (type is not null && !ConvertUtils.try_convert(type, value, out _)) {
throw new ArgumentException(
$"Type '{type}' is not assignable from value type '{value?.GetType()}'");
}
return new(name, type ?? typeof(T), value);
}
internal static Type ParseType(string typeId) {
return Candidates().ExceptNull().FirstOrDefault() ??
throw new ArgumentException($"Failed to parse Type from '{typeId}'", nameof(typeId));
IEnumerable<Type?> Candidates() {
if (typeId.Length == 0) {
yield break;
}
yield return Type.GetType(typeId);
yield return Type.GetType($"System.{typeId}");
if (typeId.Length > 1) {
yield return Type.GetType($"System.{char.ToUpper(typeId[0]) + typeId[1..]}");
}
yield return typeId.ToLower() switch {
"float64" or "double" or "real64" or "number" => typeof(double),
"float32" or "single" or "real32" or "real" or "float" => typeof(float),
"int16" or "short" or "integer16" or "signed16" => typeof(short),
"int32" or "int" or "integer" or "integer32" or "signed" => typeof(int),
"int64" or "long" or "integer64" or "signed64" => typeof(long),
"uint16" or "ushort" or "unsigned16" => typeof(ushort),
"uint32" or "uint" or "unsigned" => typeof(uint),
"uint64" or "ulong" or "unsigned64" => typeof(ulong),
"char" => typeof(char),
"byte" or "uint8" => typeof(byte),
"bool" or "boolean" => typeof(bool),
"string" or "text" => typeof(string),
"date" or "datetime" => typeof(DateTime),
_ => null
};
}
}
}
@@ -0,0 +1,49 @@
%namespace Bts.ColumnExpressions
%partial
%visibility internal
%tokentype ColumnExpressionToken
%parsertype ColumnExpressionParser
%union {
public int Integer;
public double Real;
public bool Boolean;
public string String;
public string Identifier;
public string TypeId;
public DateTime DateTime;
public Tuple<string, Type> ColumnDefinition;
public ColumnExpression ColumnExpression;
public ImmutableList<ColumnExpression> ColumnExpressions;
}
%token BOOLEAN_CONSTANT, INTEGER_CONSTANT, REAL_CONSTANT, DATE_TIME_CONSTANT, STRING_CONSTANT
%token IDENTIFIER, EQUALS, TYPE_ID, OF_TYPE
%nonassoc EQUALS
%type <ColumnDefinition> ColumnDefinition
%type <ColumnExpression> ColumnExpression
%type <ColumnExpressions> ColumnExpressions
%%
ColumnExpressions :
ColumnExpression { $$ = ImmutableList.CreateRange(new[] { $1 }); }
| ColumnExpressions ColumnExpression { $$ = $1.Add($2); }
;
ColumnExpression :
ColumnDefinition EQUALS INTEGER_CONSTANT { $$ = ColumnExpression.Create($1.Item1, $3.Integer, $1.Item2); }
| ColumnDefinition EQUALS REAL_CONSTANT { $$ = ColumnExpression.Create($1.Item1, $3.Real, $1.Item2); }
| ColumnDefinition EQUALS DATE_TIME_CONSTANT { $$ = ColumnExpression.Create($1.Item1, $3.DateTime, $1.Item2); }
| ColumnDefinition EQUALS BOOLEAN_CONSTANT { $$ = ColumnExpression.Create($1.Item1, $3.Boolean, $1.Item2); }
| ColumnDefinition EQUALS STRING_CONSTANT { $$ = ColumnExpression.Create($1.Item1, $3.String, $1.Item2); }
| ColumnDefinition { $$ = new($1.Item1, $1.Item2); }
;
ColumnDefinition :
IDENTIFIER { $$ = new($1.Identifier, null); }
| IDENTIFIER OF_TYPE IDENTIFIER { $$ = new($1.Identifier, ColumnExpression.ParseType($3.Identifier)); }
| IDENTIFIER OF_TYPE TYPE_ID { $$ = new($1.Identifier, ColumnExpression.ParseType($3.TypeId)); }
;
@@ -0,0 +1,18 @@
namespace Bts.ColumnExpressions;
using System.IO;
using System.Text;
public class ColumnExpressionInterpreter {
public static IList<ColumnExpression> Evaluate(Stream stream) {
var parser = new ColumnExpressionParser();
var res = parser.Parse(stream);
return res?.ColumnExpressions ?? ImmutableList<ColumnExpression>.Empty.Add(
res?.ColumnExpression ?? throw new Exception("Failed to parse column(s) expression"));
}
public static IList<ColumnExpression> Evaluate(string str) {
using var ms = new MemoryStream(Encoding.Default.GetBytes(str));
return Evaluate(ms);
}
}
@@ -0,0 +1,18 @@
namespace Bts.ColumnExpressions;
using System.Text;
partial class ColumnExpressionParser {
public ColumnExpressionParser() : base(null) { }
public ValueType? Parse(string s) {
using var ms = new MemoryStream(Encoding.Default.GetBytes(s));
return Parse(ms);
}
public ValueType? Parse(Stream stream) {
Scanner = new ColumnExpressionScanner(stream);
Parse();
return CurrentSemanticValue;
}
}
@@ -0,0 +1,9 @@
namespace Bts.ColumnExpressions;
partial class ColumnExpressionScanner {
public override void yyerror(string format, params object[] args) {
base.yyerror(format, args);
Console.WriteLine(format, args);
Console.WriteLine();
}
}
@@ -0,0 +1,85 @@
%namespace Bts.ColumnExpressions
%scannertype ColumnExpressionScanner
%visibility internal
%tokentype ColumnExpressionToken
%option stack, minimize, parser, verbose, persistbuffer, noembedbuffers
/* Literal Constants */
Letter [a-zA-Z]
BooleanConstant true|false
StringConstant '([^\'\\]*|\\.)*'
DateTimeConstant ([1-9]|'10'|'11'|'12')\/([1-9]|([1-2][0-9])|'30'|'31')\/[0-9][0-9][0-9]*
IntegerConstant -?[0-9]+
NullConstant 'null'
RealConstant -?[0-9]+\.[0-9]+
/* Relational Operators */
Equals =
OfType /
Identifier {Letter}({Letter}*[0-9]*_*)*
NamespacePrefix {Identifier}\.
TypeId {NamespacePrefix}*{Identifier}
/* Utility Tokens */
OpenParenthesis \(
CloseParenthesis \)
Comma ,
QuoteOpen \[
QuoteClose \]
/* Comments */
LineComment \/\/[^\n\r]*(\n|\r|\r\n)
%%
{Equals} {
return (int)ColumnExpressionToken.EQUALS;
}
{OfType} {
return (int)ColumnExpressionToken.OF_TYPE;
}
{StringConstant} {
yylval.String = yytext.Substring(1, yytext.Length - 2).Replace(@"\'","'");
return (int)ColumnExpressionToken.STRING_CONSTANT;
}
{BooleanConstant} {
yylval.Boolean = yytext.ToLower() switch {
"true" => true,
"false" => false,
_ => throw new Exception(
string.Format("Expected yytext to be 'true' or 'false' (actually '{0}')", yytext))
};
return (int)ColumnExpressionToken.BOOLEAN_CONSTANT;
}
{DateTimeConstant} {
yylval.DateTime = DateTime.Parse(yytext);
return (int)ColumnExpressionToken.DATE_TIME_CONSTANT;
}
{IntegerConstant} {
yylval.Integer = int.Parse(yytext);
return (int)ColumnExpressionToken.INTEGER_CONSTANT;
}
{RealConstant} {
yylval.Real = double.Parse(yytext);
return (int)ColumnExpressionToken.REAL_CONSTANT;
}
{Identifier} {
yylval.Identifier = yytext;
return (int)ColumnExpressionToken.IDENTIFIER;
}
{TypeId} {
yylval.TypeId = yytext;
return (int)ColumnExpressionToken.TYPE_ID;
}
%%
@@ -0,0 +1,720 @@
// ==============================================================
// <auto-generated>
// This code automatically produced from an embedded resource.
// Do not edit this file, or it will become incompatible with
// the specification from which it was generated.
// </auto-generated>
// ==============================================================
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using System.Globalization;
namespace QUT.GplexBuffers
{
// Code copied from GPLEX embedded resource
[Serializable]
internal class BufferException : Exception
{
public BufferException() { }
public BufferException(string message) : base(message) { }
public BufferException(string message, Exception innerException)
: base(message, innerException) { }
protected BufferException(SerializationInfo info, StreamingContext context)
: base(info, context) { }
}
internal abstract class ScanBuff
{
private string fileNm;
public const int EndOfFile = -1;
public const int UnicodeReplacementChar = 0xFFFD;
public bool IsFile { get { return (fileNm != null); } }
public string FileName { get { return fileNm; } set { fileNm = value; } }
public abstract int Pos { get; set; }
public abstract int Read();
public virtual void Mark() { }
public abstract string GetString(int begin, int limit);
public static ScanBuff GetBuffer(string source)
{
return new StringBuffer(source);
}
public static ScanBuff GetBuffer(IList<string> source)
{
return new LineBuffer(source);
}
#if (!NOFILES)
public static ScanBuff GetBuffer(Stream source)
{
return new BuildBuffer(source);
}
#if (!BYTEMODE)
public static ScanBuff GetBuffer(Stream source, int fallbackCodePage)
{
return new BuildBuffer(source, fallbackCodePage);
}
#endif // !BYTEMODE
#endif // !NOFILES
}
#region Buffer classes
// ==============================================================
// ===== Definitions for various ScanBuff derived classes ====
// ==============================================================
// =============== String input ================
// ==============================================================
/// <summary>
/// This class reads characters from a single string as
/// required, for example, by Visual Studio language services
/// </summary>
sealed class StringBuffer : ScanBuff
{
string str; // input buffer
int bPos; // current position in buffer
int sLen;
public StringBuffer(string source)
{
this.str = source;
this.sLen = source.Length;
this.FileName = null;
}
public override int Read()
{
if (bPos < sLen) return str[bPos++];
else if (bPos == sLen) { bPos++; return '\n'; } // one strike, see new line
else { bPos++; return EndOfFile; } // two strikes and you're out!
}
public override string GetString(int begin, int limit)
{
// "limit" can be greater than sLen with the BABEL
// option set. Read returns a "virtual" EOL if
// an attempt is made to read past the end of the
// string buffer. Without the guard any attempt
// to fetch yytext for a token that includes the
// EOL will throw an index exception.
if (limit > sLen) limit = sLen;
if (limit <= begin) return "";
else return str.Substring(begin, limit - begin);
}
public override int Pos
{
get { return bPos; }
set { bPos = value; }
}
public override string ToString() { return "StringBuffer"; }
}
// ==============================================================
// The LineBuff class contributed by Nigel Horspool,
// nigelh@cs.uvic.cs
// ==============================================================
sealed class LineBuffer : ScanBuff
{
IList<string> line; // list of source lines from a file
int numLines; // number of strings in line list
string curLine; // current line in that list
int cLine; // index of current line in the list
int curLen; // length of current line
int curLineStart; // position of line start in whole file
int curLineEnd; // position of line end in whole file
int maxPos; // max position ever visited in whole file
int cPos; // ordinal number of code in source
// Constructed from a list of strings, one per source line.
// The lines have had trailing '\n' characters removed.
public LineBuffer(IList<string> lineList)
{
line = lineList;
numLines = line.Count;
cPos = curLineStart = 0;
curLine = (numLines > 0 ? line[0] : "");
maxPos = curLineEnd = curLen = curLine.Length;
cLine = 1;
FileName = null;
}
public override int Read()
{
if (cPos < curLineEnd)
return curLine[cPos++ - curLineStart];
if (cPos++ == curLineEnd)
return '\n';
if (cLine >= numLines)
return EndOfFile;
curLine = line[cLine];
curLen = curLine.Length;
curLineStart = curLineEnd + 1;
curLineEnd = curLineStart + curLen;
if (curLineEnd > maxPos)
maxPos = curLineEnd;
cLine++;
return curLen > 0 ? curLine[0] : '\n';
}
// To speed up searches for the line containing a position
private int cachedPosition;
private int cachedIxdex;
private int cachedLineStart;
// Given a position pos within the entire source, the results are
// ix -- the index of the containing line
// lstart -- the position of the first character on that line
private void findIndex(int pos, out int ix, out int lstart)
{
if (pos >= cachedPosition)
{
ix = cachedIxdex; lstart = cachedLineStart;
}
else
{
ix = lstart = 0;
}
while (ix < numLines)
{
int len = line[ix].Length + 1;
if (pos < lstart + len) break;
lstart += len;
ix++;
}
cachedPosition = pos;
cachedIxdex = ix;
cachedLineStart = lstart;
}
public override string GetString(int begin, int limit)
{
if (begin >= maxPos || limit <= begin) return "";
int endIx, begIx, endLineStart, begLineStart;
findIndex(begin, out begIx, out begLineStart);
int begCol = begin - begLineStart;
findIndex(limit, out endIx, out endLineStart);
int endCol = limit - endLineStart;
string s = line[begIx];
if (begIx == endIx)
{
// the usual case, substring all on one line
return (endCol <= s.Length) ?
s.Substring(begCol, endCol - begCol)
: s.Substring(begCol) + "\n";
}
// the string spans multiple lines, yuk!
StringBuilder sb = new StringBuilder();
if (begCol < s.Length)
sb.Append(s.Substring(begCol));
for (; ; )
{
sb.Append("\n");
s = line[++begIx];
if (begIx >= endIx) break;
sb.Append(s);
}
if (endCol <= s.Length)
{
sb.Append(s.Substring(0, endCol));
}
else
{
sb.Append(s);
sb.Append("\n");
}
return sb.ToString();
}
public override int Pos
{
get { return cPos; }
set
{
cPos = value;
findIndex(cPos, out cLine, out curLineStart);
// cLine should be the *next* line after curLine.
curLine = (cLine < numLines ? line[cLine++] : "");
curLineEnd = curLineStart + curLine.Length;
}
}
public override string ToString() { return "LineBuffer"; }
}
#if (!NOFILES)
// ==============================================================
// ===== class BuildBuff : for unicode text files ========
// ==============================================================
class BuildBuffer : ScanBuff
{
// Double buffer for char stream.
class BufferElement
{
StringBuilder bldr = new StringBuilder();
StringBuilder next = new StringBuilder();
int minIx;
int maxIx;
int brkIx;
bool appendToNext;
internal BufferElement() { }
internal int MaxIndex { get { return maxIx; } }
// internal int MinIndex { get { return minIx; } }
internal char this[int index]
{
get
{
if (index < minIx || index >= maxIx)
throw new BufferException("Index was outside data buffer");
else if (index < brkIx)
return bldr[index - minIx];
else
return next[index - brkIx];
}
}
internal void Append(char[] block, int count)
{
maxIx += count;
if (appendToNext)
this.next.Append(block, 0, count);
else
{
this.bldr.Append(block, 0, count);
brkIx = maxIx;
appendToNext = true;
}
}
internal string GetString(int start, int limit)
{
if (limit <= start)
return "";
if (start >= minIx && limit <= maxIx)
if (limit < brkIx) // String entirely in bldr builder
return bldr.ToString(start - minIx, limit - start);
else if (start >= brkIx) // String entirely in next builder
return next.ToString(start - brkIx, limit - start);
else // Must do a string-concatenation
return
bldr.ToString(start - minIx, brkIx - start) +
next.ToString(0, limit - brkIx);
else
throw new BufferException("String was outside data buffer");
}
internal void Mark(int limit)
{
if (limit > brkIx + 16) // Rotate blocks
{
StringBuilder temp = bldr;
bldr = next;
next = temp;
next.Length = 0;
minIx = brkIx;
brkIx = maxIx;
}
}
}
BufferElement data = new BufferElement();
int bPos; // Postion index in the StringBuilder
BlockReader NextBlk; // Delegate that serves char-arrays;
private string EncodingName
{
get
{
StreamReader rdr = NextBlk.Target as StreamReader;
return (rdr == null ? "raw-bytes" : rdr.CurrentEncoding.BodyName);
}
}
public BuildBuffer(Stream stream)
{
FileStream fStrm = (stream as FileStream);
if (fStrm != null) FileName = fStrm.Name;
NextBlk = BlockReaderFactory.Raw(stream);
}
#if (!BYTEMODE)
public BuildBuffer(Stream stream, int fallbackCodePage)
{
FileStream fStrm = (stream as FileStream);
if (fStrm != null) FileName = fStrm.Name;
NextBlk = BlockReaderFactory.Get(stream, fallbackCodePage);
}
#endif
/// <summary>
/// Marks a conservative lower bound for the buffer,
/// allowing space to be reclaimed. If an application
/// needs to call GetString at arbitrary past locations
/// in the input stream, Mark() is not called.
/// </summary>
public override void Mark() { data.Mark(bPos - 2); }
public override int Pos
{
get { return bPos; }
set { bPos = value; }
}
/// <summary>
/// Read returns the ordinal number of the next char, or
/// EOF (-1) for an end of stream. Note that the next
/// code point may require *two* calls of Read().
/// </summary>
/// <returns></returns>
public override int Read()
{
//
// Characters at positions
// [data.offset, data.offset + data.bldr.Length)
// are available in data.bldr.
//
if (bPos < data.MaxIndex)
{
// ch0 cannot be EOF
return (int)data[bPos++];
}
else // Read from underlying stream
{
// Experimental code, blocks of page size
char[] chrs = new char[4096];
int count = NextBlk(chrs, 0, 4096);
if (count == 0)
return EndOfFile;
else
{
data.Append(chrs, count);
return (int)data[bPos++];
}
}
}
public override string GetString(int begin, int limit)
{
return data.GetString(begin, limit);
}
public override string ToString()
{
return "StringBuilder buffer, encoding: " + this.EncodingName;
}
}
// =============== End ScanBuff-derived classes ==================
internal delegate int BlockReader(char[] block, int index, int number);
// A delegate factory, serving up a delegate that
// reads a block of characters from the underlying
// encoded stream, via a StreamReader object.
//
internal static class BlockReaderFactory
{
public static BlockReader Raw(Stream stream)
{
return delegate(char[] block, int index, int number)
{
byte[] b = new byte[number];
int count = stream.Read(b, 0, number);
int i = 0;
int j = index;
for (; i < count; i++, j++)
block[j] = (char)b[i];
return count;
};
}
#if (!BYTEMODE)
public static BlockReader Get(Stream stream, int fallbackCodePage)
{
Encoding encoding;
int preamble = Preamble(stream);
if (preamble != 0) // There is a valid BOM here!
encoding = Encoding.GetEncoding(preamble);
else if (fallbackCodePage == -1) // Fallback is "raw" bytes
return Raw(stream);
else if (fallbackCodePage != -2) // Anything but "guess"
encoding = Encoding.GetEncoding(fallbackCodePage);
else // This is the "guess" option
{
int guess = new Guesser(stream).GuessCodePage();
stream.Seek(0, SeekOrigin.Begin);
if (guess == -1) // ==> this is a 7-bit file
encoding = Encoding.ASCII;
else if (guess == 65001)
encoding = Encoding.UTF8;
else // ==> use the machine default
encoding = Encoding.Default;
}
StreamReader reader = new StreamReader(stream, encoding);
return reader.Read;
}
static int Preamble(Stream stream)
{
int b0 = stream.ReadByte();
int b1 = stream.ReadByte();
if (b0 == 0xfe && b1 == 0xff)
return 1201; // UTF16BE
if (b0 == 0xff && b1 == 0xfe)
return 1200; // UTF16LE
int b2 = stream.ReadByte();
if (b0 == 0xef && b1 == 0xbb && b2 == 0xbf)
return 65001; // UTF8
//
// There is no unicode preamble, so we
// return denoter for the machine default.
//
stream.Seek(0, SeekOrigin.Begin);
return 0;
}
#endif // !BYTEMODE
}
#endif // !NOFILES
#endregion Buffer classes
// ==============================================================
// ============ class CodePageHandling =============
// ==============================================================
#if (!NOFILES)
public static class CodePageHandling
{
public static int GetCodePage(string option)
{
string command = option.ToUpperInvariant();
if (command.StartsWith("CodePage:", StringComparison.OrdinalIgnoreCase))
command = command.Substring(9);
try
{
if (command.Equals("RAW"))
return -1;
else if (command.Equals("GUESS"))
return -2;
else if (command.Equals("DEFAULT"))
return 0;
else if (char.IsDigit(command[0]))
return int.Parse(command, CultureInfo.InvariantCulture);
else
{
Encoding enc = Encoding.GetEncoding(command);
return enc.CodePage;
}
}
catch (FormatException)
{
Console.Error.WriteLine(
"Invalid format \"{0}\", using machine default", option);
}
catch (ArgumentException)
{
Console.Error.WriteLine(
"Unknown code page \"{0}\", using machine default", option);
}
return 0;
}
}
#region guesser
#if (!BYTEMODE)
// ==============================================================
// ============ Encoding Guesser =============
// ==============================================================
/// <summary>
/// This class provides a simple finite state automaton that
/// scans the file looking for (1) valid UTF-8 byte patterns,
/// (2) bytes >= 0x80 which are not part of a UTF-8 sequence.
/// The method then guesses whether it is UTF-8 or maybe some
/// local machine default encoding. This works well for the
/// various Latin encodings.
/// </summary>
internal class Guesser
{
ScanBuff buffer;
public int GuessCodePage() { return Scan(); }
const int maxAccept = 10;
const int initial = 0;
const int eofNum = 0;
const int goStart = -1;
const int INITIAL = 0;
const int EndToken = 0;
#region user code
/*
* Reads the bytes of a file to determine if it is
* UTF-8 or a single-byte code page file.
*/
public long utfX;
public long uppr;
#endregion user code
int state;
int currentStart = startState[0];
int code;
#region ScannerTables
static int[] startState = new int[] { 11, 0 };
#region CharacterMap
static sbyte[] map = new sbyte[256] {
/* '\0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '\x10' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '\x20' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '@' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 'P' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '`' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 'p' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '\x80' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\x90' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\xA0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\xB0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\xC0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* '\xD0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* '\xE0' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
/* '\xF0' */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5 };
#endregion
static sbyte[][] nextState = new sbyte[][] {
new sbyte[] {0, 0, 0, 0, 0, 0},
new sbyte[] {-1, -1, 10, -1, -1, -1},
new sbyte[] {-1, -1, -1, -1, -1, -1},
new sbyte[] {-1, -1, 8, -1, -1, -1},
new sbyte[] {-1, -1, 5, -1, -1, -1},
new sbyte[] {-1, -1, 6, -1, -1, -1},
new sbyte[] {-1, -1, 7, -1, -1, -1},
null,
new sbyte[] {-1, -1, 9, -1, -1, -1},
null,
null,
new sbyte[] {-1, 1, 2, 3, 4, 2}
};
[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
// Reason for suppression: cannot have self-reference in array initializer.
static Guesser()
{
nextState[7] = nextState[2];
nextState[9] = nextState[2];
nextState[10] = nextState[2];
}
int NextState()
{
if (code == ScanBuff.EndOfFile)
return eofNum;
else
return nextState[state][map[code]];
}
#endregion
public Guesser(System.IO.Stream file) { SetSource(file); }
public void SetSource(System.IO.Stream source)
{
this.buffer = new BuildBuffer(source);
code = buffer.Read();
}
int Scan()
{
for (; ; )
{
int next;
state = currentStart;
while ((next = NextState()) == goStart)
code = buffer.Read();
state = next;
code = buffer.Read();
while ((next = NextState()) > eofNum)
{
state = next;
code = buffer.Read();
}
if (state <= maxAccept)
{
#region ActionSwitch
#pragma warning disable 162
switch (state)
{
case eofNum:
switch (currentStart)
{
case 11:
if (utfX == 0 && uppr == 0) return -1; /* raw ascii */
else if (uppr * 10 > utfX) return 0; /* default code page */
else return 65001; /* UTF-8 encoding */
break;
}
return EndToken;
case 1: // Recognized '{Upper128}', Shortest string "\xC0"
case 2: // Recognized '{Upper128}', Shortest string "\x80"
case 3: // Recognized '{Upper128}', Shortest string "\xE0"
case 4: // Recognized '{Upper128}', Shortest string "\xF0"
uppr++;
break;
case 5: // Recognized '{Utf8pfx4}{Utf8cont}', Shortest string "\xF0\x80"
uppr += 2;
break;
case 6: // Recognized '{Utf8pfx4}{Utf8cont}{2}', Shortest string "\xF0\x80\x80"
uppr += 3;
break;
case 7: // Recognized '{Utf8pfx4}{Utf8cont}{3}', Shortest string "\xF0\x80\x80\x80"
utfX += 3;
break;
case 8: // Recognized '{Utf8pfx3}{Utf8cont}', Shortest string "\xE0\x80"
uppr += 2;
break;
case 9: // Recognized '{Utf8pfx3}{Utf8cont}{2}', Shortest string "\xE0\x80\x80"
utfX += 2;
break;
case 10: // Recognized '{Utf8pfx2}{Utf8cont}', Shortest string "\xC0\x80"
utfX++;
break;
default:
break;
}
#pragma warning restore 162
#endregion
}
}
}
} // end class Guesser
#endif // !BYTEMODE
#endregion
#endif // !NOFILES
// End of code copied from embedded resource
}
@@ -0,0 +1,884 @@
// ==============================================================
// <auto-generated>
// This code automatically produced from an embedded resource.
// Do not edit this file, or it will become incompatible with
// the specification from which it was generated.
// </auto-generated>
// ==============================================================
// Gardens Point Parser Generator
// Copyright (c) Wayne Kelly, QUT 2005-2010
// (see accompanying GPPGcopyright.rtf)
using System;
using System.Text;
using System.Globalization;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Diagnostics.CodeAnalysis;
namespace QUT.Gppg {
/// <summary>
/// Abstract class for GPPG shift-reduce parsers.
/// Parsers generated by GPPG derive from this base
/// class, overriding the abstract Initialize() and
/// DoAction() methods.
/// </summary>
/// <typeparam name="TValue">Semantic value type</typeparam>
/// <typeparam name="TSpan">Location type</typeparam>
#if EXPORT_GPPG
public abstract class ShiftReduceParser<TValue, TSpan>
#else
internal abstract class ShiftReduceParser<TValue, TSpan>
#endif
where TSpan : IMerge<TSpan>, new() {
private AbstractScanner<TValue, TSpan> scanner;
/// <summary>
/// The abstract scanner for this parser.
/// </summary>
protected AbstractScanner<TValue, TSpan> Scanner {
get { return scanner; }
set { scanner = value; }
}
/// <summary>
/// Constructor for base class
/// </summary>
/// <param name="scanner">Scanner instance for this parser</param>
protected ShiftReduceParser( AbstractScanner<TValue, TSpan> scanner ) {
this.scanner = scanner;
}
// ==============================================================
// TECHNICAL EXPLANATION.
// Why the next two fields are not exposed via properties.
// ==============================================================
// These fields are of the generic parameter types, and are
// frequently instantiated as struct types in derived classes.
// Semantic actions are defined in the derived classes and refer
// to instance fields of these structs. In such cases the code
// "get_CurrentSemanticValue().myField = blah;" will fail since
// the getter pushes the value of the field, not the reference.
// So, in the presence of properties, gppg would need to encode
// such field accesses as ...
// "tmp = get_CurrentSemanticValue(); // Fetch value
// tmp.myField = blah; // update
// set_CurrentSemanticValue(tmp); " // Write update back.
// There is no issue if TValue is restricted to be a ref type.
// The same explanation applies to scanner.yylval.
// ==============================================================
/// <summary>
/// The current value of the "$$" symbolic variable in the parser
/// </summary>
[SuppressMessage( "Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields" )]
protected TValue CurrentSemanticValue;
/// <summary>
/// The current value of the "@$" symbolic variable in the parser
/// </summary>
[SuppressMessage( "Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields" )]
protected TSpan CurrentLocationSpan;
protected int NextToken;
private TSpan LastSpan;
private State FsaState;
private bool recovering;
private int tokensSinceLastError;
private PushdownPrefixState<State> StateStack = new PushdownPrefixState<State>();
private PushdownPrefixState<TValue> valueStack = new PushdownPrefixState<TValue>();
private PushdownPrefixState<TSpan> locationStack = new PushdownPrefixState<TSpan>();
/// <summary>
/// The stack of semantic value (YYSTYPE) values.
/// </summary>
protected PushdownPrefixState<TValue> ValueStack { get { return valueStack; } }
/// <summary>
/// The stack of location value (YYLTYPE) varlues.
/// </summary>
protected PushdownPrefixState<TSpan> LocationStack { get { return locationStack; } }
private int errorToken;
private int endOfFileToken;
private string[] nonTerminals;
private State[] states;
private Rule[] rules;
/// <summary>
/// Initialization method to allow derived classes
/// to insert the rule list into this base class.
/// </summary>
/// <param name="rules">The array of Rule objects</param>
protected void InitRules( Rule[] rules ) { this.rules = rules; }
/// <summary>
/// Initialization method to allow derived classes to
/// insert the states table into this base class.
/// </summary>
/// <param name="states">The pre-initialized states table</param>
protected void InitStates( State[] states ) { this.states = states; }
/// <summary>
/// OBSOLETE FOR VERSION 1.4.0
/// </summary>
/// <param name="size"></param>
protected void InitStateTable( int size ) { states = new State[size]; }
/// <summary>
/// Initialization method to allow derived classes
/// to insert the special value for the error and EOF tokens.
/// </summary>
/// <param name="err">The error state ordinal</param>
/// <param name="end">The EOF stat ordinal</param>
protected void InitSpecialTokens( int err, int end ) {
errorToken = err;
endOfFileToken = end;
}
/// <summary>
/// Initialization method to allow derived classes to
/// insert the non-terminal symbol names into this base class.
/// </summary>
/// <param name="names">Non-terminal symbol names</param>
protected void InitNonTerminals( string[] names ) { nonTerminals = names; }
#region YYAbort, YYAccept etcetera.
[Serializable]
[SuppressMessage( "Microsoft.Design", "CA1064:ExceptionsShouldBePublic" )]
// Reason for FxCop message suppression -
// This exception cannot escape from the local context
private class AcceptException : Exception {
internal AcceptException() { }
protected AcceptException( SerializationInfo i, StreamingContext c ) : base( i, c ) { }
}
[Serializable]
[SuppressMessage( "Microsoft.Design", "CA1064:ExceptionsShouldBePublic" )]
// Reason for FxCop message suppression -
// This exception cannot escape from the local context
private class AbortException : Exception {
internal AbortException() { }
protected AbortException( SerializationInfo i, StreamingContext c ) : base( i, c ) { }
}
[Serializable]
[SuppressMessage( "Microsoft.Design", "CA1064:ExceptionsShouldBePublic" )]
// Reason for FxCop message suppression -
// This exception cannot escape from the local context
private class ErrorException : Exception {
internal ErrorException() { }
protected ErrorException( SerializationInfo i, StreamingContext c ) : base( i, c ) { }
}
// The following methods are only called from within
// a semantic action. The thrown exceptions can never
// propagate outside the ShiftReduceParser class in
// which they are nested.
/// <summary>
/// Force parser to terminate, returning "true"
/// </summary>
protected static void YYAccept() { throw new AcceptException(); }
/// <summary>
/// Force parser to terminate, returning "false"
/// </summary>
protected static void YYAbort() { throw new AbortException(); }
/// <summary>
/// Force parser to terminate, returning
/// "false" if error recovery fails.
/// </summary>
protected static void YYError() { throw new ErrorException(); }
/// <summary>
/// Check if parser in error recovery state.
/// </summary>
protected bool YYRecovering { get { return recovering; } }
#endregion
/// <summary>
/// Abstract base method. ShiftReduceParser calls this
/// to initialize the base class data structures. Concrete
/// parser classes must override this method.
/// </summary>
protected abstract void Initialize();
/// <summary>
/// Main entry point of the Shift-Reduce Parser.
/// </summary>
/// <returns>True if parse succeeds, else false for
/// unrecoverable errors</returns>
public bool Parse() {
Initialize(); // allow derived classes to instantiate rules, states and nonTerminals
NextToken = 0;
FsaState = states[0];
StateStack.Push( FsaState );
valueStack.Push( CurrentSemanticValue );
LocationStack.Push( CurrentLocationSpan );
while (true) {
#if TRACE_ACTIONS
Console.Error.WriteLine("Entering state {0} ", FsaState.number);
DisplayStack();
#endif
int action = FsaState.defaultAction;
if (FsaState.ParserTable != null) {
if (NextToken == 0) {
// We save the last token span, so that the location span
// of production right hand sides that begin or end with a
// nullable production will be correct.
LastSpan = scanner.yylloc;
NextToken = scanner.yylex();
#if TRACE_ACTIONS
Console.Error.WriteLine( "Reading: Next token is {0}", TerminalToString( NextToken ) );
#endif
}
#if TRACE_ACTIONS
else
Console.Error.WriteLine( "Next token is still {0}", TerminalToString( NextToken ) );
#endif
if (FsaState.ParserTable.ContainsKey( NextToken ))
action = FsaState.ParserTable[NextToken];
}
if (action > 0) // shift
{
Shift( action );
}
else if (action < 0) // reduce
{
try {
Reduce( -action );
if (action == -1) // accept
return true;
}
catch (AbortException) {
return false;
}
catch (AcceptException) {
return true;
}
catch (ErrorException) {
if (!ErrorRecovery())
return false;
else
throw; // Rethrow x, preserving information.
}
}
else if (action == 0 && !ErrorRecovery()) // error
return false;
}
}
private void Shift( int stateIndex ) {
#if TRACE_ACTIONS
Console.Error.Write("Shifting token {0}, ", TerminalToString(NextToken));
#endif
FsaState = states[stateIndex];
valueStack.Push( scanner.yylval );
StateStack.Push( FsaState );
LocationStack.Push( scanner.yylloc );
if (recovering) {
if (NextToken != errorToken)
tokensSinceLastError++;
if (tokensSinceLastError > 5)
recovering = false;
}
if (NextToken != endOfFileToken)
NextToken = 0;
}
private void Reduce( int ruleNumber ) {
#if TRACE_ACTIONS
DisplayRule(ruleNumber);
#endif
Rule rule = rules[ruleNumber];
int rhLen = rule.RightHandSide.Length;
//
// Default actions for unit productions.
//
if (rhLen == 1) {
CurrentSemanticValue = valueStack.TopElement(); // Default action: $$ = $1;
CurrentLocationSpan = LocationStack.TopElement(); // Default action "@$ = @1;
}
else if (rhLen == 0) {
// Create a new blank value.
// Explicit semantic action may mutate this value
CurrentSemanticValue = default( TValue );
// The location span for an empty production will start with the
// beginning of the next lexeme, and end with the finish of the
// previous lexeme. This gives the correct behaviour when this
// nonsense value is used in later Merge operations.
CurrentLocationSpan = (scanner.yylloc != null && LastSpan != null ?
scanner.yylloc.Merge( LastSpan ) :
default( TSpan ));
}
else {
// Default action: $$ = $1;
CurrentSemanticValue = valueStack[LocationStack.Depth - rhLen];
// Default action "@$ = @1.Merge(@N)" for location info.
TSpan at1 = LocationStack[LocationStack.Depth - rhLen];
TSpan atN = LocationStack[LocationStack.Depth - 1];
CurrentLocationSpan =
((at1 != null && atN != null) ? at1.Merge( atN ) : default( TSpan ));
}
DoAction( ruleNumber );
for (int i = 0; i < rule.RightHandSide.Length; i++) {
StateStack.Pop();
valueStack.Pop();
LocationStack.Pop();
}
FsaState = StateStack.TopElement();
if (FsaState.Goto.ContainsKey( rule.LeftHandSide ))
FsaState = states[FsaState.Goto[rule.LeftHandSide]];
StateStack.Push( FsaState );
valueStack.Push( CurrentSemanticValue );
LocationStack.Push( CurrentLocationSpan );
}
/// <summary>
/// Execute the selected action from array.
/// Must be overriden in derived classes.
/// </summary>
/// <param name="actionNumber">Index of the action to perform</param>
protected abstract void DoAction( int actionNumber );
private bool ErrorRecovery() {
bool discard;
if (!recovering) // if not recovering from previous error
ReportError();
if (!FindErrorRecoveryState())
return false;
//
// The interim fix for the "looping in error recovery"
// artifact involved moving the setting of the recovering
// bool until after invalid tokens have been discarded.
//
ShiftErrorToken();
discard = DiscardInvalidTokens();
recovering = true;
tokensSinceLastError = 0;
return discard;
}
private void ReportError() {
StringBuilder errorMsg = new StringBuilder();
errorMsg.AppendFormat( "Syntax error, unexpected {0}", TerminalToString( NextToken ) );
if (FsaState.ParserTable.Count < 7) {
bool first = true;
foreach (int terminal in FsaState.ParserTable.Keys) {
if (first)
errorMsg.Append( ", expecting " );
else
errorMsg.Append( ", or " );
errorMsg.Append( TerminalToString( terminal ) );
first = false;
}
}
scanner.yyerror( errorMsg.ToString() );
}
private void ShiftErrorToken() {
int old_next = NextToken;
NextToken = errorToken;
Shift( FsaState.ParserTable[NextToken] );
#if TRACE_ACTIONS
Console.Error.WriteLine("Entering state {0} ", FsaState.number);
#endif
NextToken = old_next;
}
private bool FindErrorRecoveryState() {
while (true) // pop states until one found that accepts error token
{
if (FsaState.ParserTable != null &&
FsaState.ParserTable.ContainsKey( errorToken ) &&
FsaState.ParserTable[errorToken] > 0) // shift
return true;
#if TRACE_ACTIONS
Console.Error.WriteLine("Error: popping state {0}", StateStack.TopElement().number);
#endif
StateStack.Pop();
valueStack.Pop();
LocationStack.Pop();
#if TRACE_ACTIONS
DisplayStack();
#endif
if (StateStack.IsEmpty()) {
#if TRACE_ACTIONS
Console.Error.WriteLine("Aborting: didn't find a state that accepts error token");
#endif
return false;
}
else
FsaState = StateStack.TopElement();
}
}
private bool DiscardInvalidTokens() {
int action = FsaState.defaultAction;
if (FsaState.ParserTable != null) {
// Discard tokens until find one that works ...
while (true) {
if (NextToken == 0) {
#if TRACE_ACTIONS
Console.Error.Write("Reading a token: ");
#endif
NextToken = scanner.yylex();
}
#if TRACE_ACTIONS
Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken));
#endif
if (NextToken == endOfFileToken)
return false;
if (FsaState.ParserTable.ContainsKey( NextToken ))
action = FsaState.ParserTable[NextToken];
if (action != 0)
return true;
else {
#if TRACE_ACTIONS
Console.Error.WriteLine("Error: Discarding {0}", TerminalToString(NextToken));
#endif
NextToken = 0;
}
}
}
else if (recovering && tokensSinceLastError == 0) {
//
// Boolean recovering is not set until after the first
// error token has been shifted. Thus if we get back
// here with recovering set and no tokens read we are
// looping on the same error recovery action. This
// happens if current_state.ParserTable is null because
// the state has an LR(0) reduction, but not all
// lookahead tokens are valid. This only occurs for
// error productions that *end* on "error".
//
// This action discards tokens one at a time until
// the looping stops. Another attack would be to always
// use the LALR(1) table if a production ends on "error"
//
#if TRACE_ACTIONS
Console.Error.WriteLine("Error: panic discard of {0}", TerminalToString(NextToken));
#endif
if (NextToken == endOfFileToken)
return false;
NextToken = 0;
return true;
}
else
return true;
}
/// <summary>
/// Traditional YACC method. Discards the next input token.
/// </summary>
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyclearin" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyclearin" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
protected void yyclearin() { NextToken = 0; }
/// <summary>
/// Tradional YACC method. Clear the "recovering" flag.
/// </summary>
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerrok" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerrok" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
protected void yyerrok() { recovering = false; }
/// <summary>
/// OBSOLETE FOR VERSION 1.4.0
/// Method used by derived types to insert new
/// state instances in the "states" array.
/// </summary>
/// <param name="stateNumber">index of the state</param>
/// <param name="state">data for the state</param>
protected void AddState( int stateNumber, State state ) {
states[stateNumber] = state;
state.number = stateNumber;
}
private void DisplayStack() {
Console.Error.Write( "State stack is now:" );
for (int i = 0; i < StateStack.Depth; i++)
Console.Error.Write( " {0}", StateStack[i].number );
Console.Error.WriteLine();
}
private void DisplayRule( int ruleNumber ) {
Console.Error.Write( "Reducing stack by rule {0}, ", ruleNumber );
DisplayProduction( rules[ruleNumber] );
}
private void DisplayProduction( Rule rule ) {
if (rule.RightHandSide.Length == 0)
Console.Error.Write( "/* empty */ " );
else
foreach (int symbol in rule.RightHandSide)
Console.Error.Write( "{0} ", SymbolToString( symbol ) );
Console.Error.WriteLine( "-> {0}", SymbolToString( rule.LeftHandSide ) );
}
/// <summary>
/// Abstract state class naming terminal symbols.
/// This is overridden by derived classes with the
/// name (or alias) to be used in error messages.
/// </summary>
/// <param name="terminal">The terminal ordinal</param>
/// <returns></returns>
protected abstract string TerminalToString( int terminal );
private string SymbolToString( int symbol ) {
if (symbol < 0)
return nonTerminals[-symbol - 1];
else
return TerminalToString( symbol );
}
/// <summary>
/// Return text representation of argument character
/// </summary>
/// <param name="input">The character to convert</param>
/// <returns>String representation of the character</returns>
protected static string CharToString( char input ) {
switch (input) {
case '\a': return @"'\a'";
case '\b': return @"'\b'";
case '\f': return @"'\f'";
case '\n': return @"'\n'";
case '\r': return @"'\r'";
case '\t': return @"'\t'";
case '\v': return @"'\v'";
case '\0': return @"'\0'";
default: return string.Format( CultureInfo.InvariantCulture, "'{0}'", input );
}
}
}
/// <summary>
/// Classes implementing this interface must supply a
/// method that merges two location objects to return
/// a new object of the same type.
/// GPPG-generated parsers have the default location
/// action equivalent to "@$ = @1.Merge(@N);" where N
/// is the right-hand-side length of the production.
/// </summary>
/// <typeparam name="TSpan">The Location type</typeparam>
#if EXPORT_GPPG
public interface IMerge<TSpan>
#else
internal interface IMerge<TSpan>
#endif
{
/// <summary>
/// Interface method that creates a location object from
/// the current and last object. Typically used to create
/// a location object extending from the start of the @1
/// object to the end of the @N object.
/// </summary>
/// <param name="last">The lexically last object to merge</param>
/// <returns>The merged location object</returns>
TSpan Merge( TSpan last );
}
/// <summary>
/// This is the default class that carries location
/// information from the scanner to the parser.
/// If you don't declare "%YYLTYPE Foo" the parser
/// will expect to deal with this type.
/// </summary>
#if EXPORT_GPPG
public class LexLocation : IMerge<LexLocation>
#else
[SuppressMessage( "Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses" )]
internal class LexLocation : IMerge<LexLocation>
#endif
{
private int startLine; // start line
private int startColumn; // start column
private int endLine; // end line
private int endColumn; // end column
/// <summary>
/// The line at which the text span starts.
/// </summary>
public int StartLine { get { return startLine; } }
/// <summary>
/// The column at which the text span starts.
/// </summary>
public int StartColumn { get { return startColumn; } }
/// <summary>
/// The line on which the text span ends.
/// </summary>
public int EndLine { get { return endLine; } }
/// <summary>
/// The column of the first character
/// beyond the end of the text span.
/// </summary>
public int EndColumn { get { return endColumn; } }
/// <summary>
/// Default no-arg constructor.
/// </summary>
public LexLocation() { }
/// <summary>
/// Constructor for text-span with given start and end.
/// </summary>
/// <param name="sl">start line</param>
/// <param name="sc">start column</param>
/// <param name="el">end line </param>
/// <param name="ec">end column</param>
public LexLocation( int sl, int sc, int el, int ec ) { startLine = sl; startColumn = sc; endLine = el; endColumn = ec; }
/// <summary>
/// Create a text location which spans from the
/// start of "this" to the end of the argument "last"
/// </summary>
/// <param name="last">The last location in the result span</param>
/// <returns>The merged span</returns>
public LexLocation Merge( LexLocation last ) { return new LexLocation( this.startLine, this.startColumn, last.endLine, last.endColumn ); }
}
/// <summary>
/// Abstract scanner class that GPPG expects its scanners to
/// extend.
/// </summary>
/// <typeparam name="TValue">Semantic value type YYSTYPE</typeparam>
/// <typeparam name="TSpan">Source location type YYLTYPE</typeparam>
#if EXPORT_GPPG
public abstract class AbstractScanner<TValue, TSpan>
#else
internal abstract class AbstractScanner<TValue, TSpan>
#endif
where TSpan : IMerge<TSpan> {
/// <summary>
/// Lexical value optionally set by the scanner. The value
/// is of the %YYSTYPE type declared in the parser spec.
/// </summary>
[SuppressMessage( "Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields" )]
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylval" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylval" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
// A field must be declared for this value of parametric type,
// since it may be instantiated by a value struct. If it were
// implemented as a property, machine generated code in derived
// types would not be able to select on the returned value.
#pragma warning disable 649
public TValue yylval; // Lexical value: set by scanner
#pragma warning restore 649
/// <summary>
/// Current scanner location property. The value is of the
/// type declared by %YYLTYPE in the parser specification.
/// </summary>
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylloc" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylloc" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
public virtual TSpan yylloc {
get { return default( TSpan ); } // Empty implementation allowing
set { /* skip */ } // yylloc to be ignored entirely.
}
/// <summary>
/// Main call point for LEX-like scanners. Returns an int
/// corresponding to the token recognized by the scanner.
/// </summary>
/// <returns>An int corresponding to the token</returns>
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
public abstract int yylex();
/// <summary>
/// Traditional error reporting provided by LEX-like scanners
/// to their YACC-like clients.
/// </summary>
/// <param name="format">Message format string</param>
/// <param name="args">Optional array of args</param>
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerror" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerror" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
public virtual void yyerror( string format, params object[] args ) { }
}
/// <summary>
/// Encapsulated state for the parser.
/// Opaque to users, visible to the tool-generated code.
/// </summary>
#if EXPORT_GPPG
public class State
{
/// <summary>
/// The number of states in the automaton.
/// </summary>
public int number;
#else
internal class State {
/// <summary>
/// The index of this state in the states array.
/// </summary>
internal int number;
#endif
internal Dictionary<int, int> ParserTable; // Terminal -> ParseAction
internal Dictionary<int, int> Goto; // NonTerminal -> State;
internal int defaultAction; // = 0; // ParseAction
/// <summary>
/// State transition data for this state. Pairs of elements of the
/// goto array associate symbol ordinals with next state indices.
/// The actions array is passed to another constructor.
/// </summary>
/// <param name="actions">The action list</param>c
/// <param name="goToList">Next state data</param>
public State( int[] actions, int[] goToList )
: this( actions ) {
Goto = new Dictionary<int, int>();
for (int i = 0; i < goToList.Length; i += 2)
Goto.Add( goToList[i], goToList[i + 1] );
}
/// <summary>
/// Action data for this state. Pairs of elements of the
/// action array associate action ordinals with each of
/// those symbols that have actions in the current state.
/// </summary>
/// <param name="actions">The action array</param>
public State( int[] actions ) {
ParserTable = new Dictionary<int, int>();
for (int i = 0; i < actions.Length; i += 2)
ParserTable.Add( actions[i], actions[i + 1] );
}
/// <summary>
/// Set the default action for this state.
/// </summary>
/// <param name="defaultAction">Ordinal of the default action</param>
public State( int defaultAction ) {
this.defaultAction = defaultAction;
}
/// <summary>
/// Set the default action and the state transition table.
/// </summary>
/// <param name="defaultAction">The default action</param>
/// <param name="goToList">Transitions from this state</param>
public State( int defaultAction, int[] goToList )
: this( defaultAction ) {
Goto = new Dictionary<int, int>();
for (int i = 0; i < goToList.Length; i += 2)
Goto.Add( goToList[i], goToList[i + 1] );
}
}
/// <summary>
/// Rule representation at runtime.
/// </summary>
#if EXPORT_GPPG
public class Rule
#else
internal class Rule
#endif
{
internal int LeftHandSide; // symbol
internal int[] RightHandSide; // symbols
/// <summary>
/// Rule constructor. This holds the ordinal of
/// the left hand side symbol, and the list of
/// right hand side symbols, in lexical order.
/// </summary>
/// <param name="left">The LHS non-terminal</param>
/// <param name="right">The RHS symbols, in lexical order</param>
public Rule( int left, int[] right ) {
this.LeftHandSide = left;
this.RightHandSide = right;
}
}
/// <summary>
/// Stack utility for the shift-reduce parser.
/// GPPG parsers have three instances:
/// (1) The parser state stack, T = QUT.Gppg.State,
/// (2) The semantic value stack, T = TValue,
/// (3) The location stack, T = TSpan.
/// </summary>
/// <typeparam name="T"></typeparam>
#if EXPORT_GPPG
public class PushdownPrefixState<T>
#else
internal class PushdownPrefixState<T>
#endif
{
// Note that we cannot use the BCL Stack<T> class
// here as derived types need to index into stacks.
//
private T[] array = new T[8];
private int tos = 0;
/// <summary>
/// Indexer for values of the stack below the top.
/// </summary>
/// <param name="index">index of the element, starting from the bottom</param>
/// <returns>the selected element</returns>
public T this[int index] { get { return array[index]; } }
/// <summary>
/// The current depth of the stack.
/// </summary>
public int Depth { get { return tos; } }
internal void Push( T value ) {
if (tos >= array.Length) {
T[] newarray = new T[array.Length * 2];
System.Array.Copy( array, newarray, tos );
array = newarray;
}
array[tos++] = value;
}
internal T Pop() {
T rslt = array[--tos];
array[tos] = default( T );
return rslt;
}
internal T TopElement() { return array[tos - 1]; }
internal bool IsEmpty() { return tos == 0; }
}
}
@@ -0,0 +1,4 @@
global using System;
global using System.Linq;
global using System.Collections.Generic;
global using System.Collections.Immutable;
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="YaccLexTools" Version="1.2.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DataStreamCore\DataStreamCore.csproj" />
<ProjectReference Include="..\ExpressionCore\ExpressionCore.csproj" />
<ProjectReference Include="..\..\client\spark_core\spark_core.csproj" />
</ItemGroup>
<ItemGroup Label="ColumnSortExpression">
<Scanner Include="ColumnSortExpressionTokens.lex" />
<Parser Include="ColumnSortExpressionGrammar.y" />
</ItemGroup>
</Project>
@@ -0,0 +1,11 @@
namespace Bts.ColumnSortExpressions;
public class ColumnSortExpression {
public ColumnSortExpression(string name, bool isAscending = true) {
Name = name;
IsAscending = isAscending;
}
public string Name { get; }
public bool IsAscending { get; }
}
@@ -0,0 +1,29 @@
%namespace Bts.ColumnSortExpressions
%partial
%visibility internal
%tokentype ColumnSortExpressionToken
%parsertype ColumnSortExpressionParser
%union {
public string Identifier;
public ColumnSortExpression Column;
public ImmutableList<ColumnSortExpression> Columns;
}
%token ASCENDING, DESCENDING, IDENTIFIER
%type <Column> Column
%type <Columns> Columns
%%
Columns :
Column { $$ = ImmutableList.CreateRange(new[] { $1 }); }
| Columns Column { $$ = $1.Add($2); }
;
Column :
IDENTIFIER { $$ = new($1.Identifier, true); }
| ASCENDING IDENTIFIER { $$ = new($2.Identifier, true); }
| DESCENDING IDENTIFIER { $$ = new($2.Identifier, false); }
;
@@ -0,0 +1,18 @@
namespace Bts.ColumnSortExpressions;
using System.IO;
using System.Text;
public class ColumnSortExpressionInterpreter {
public static IList<ColumnSortExpression> Evaluate(Stream stream) {
var parser = new ColumnSortExpressionParser();
var res = parser.Parse(stream);
return res?.Columns ?? ImmutableList<ColumnSortExpression>.Empty.Add(
res?.Column ?? throw new Exception("Failed to parse column(s) expression"));
}
public static IList<ColumnSortExpression> Evaluate(string str) {
using var ms = new MemoryStream(Encoding.Default.GetBytes(str));
return Evaluate(ms);
}
}
@@ -0,0 +1,18 @@
namespace Bts.ColumnSortExpressions;
using System.Text;
partial class ColumnSortExpressionParser {
public ColumnSortExpressionParser() : base(null) { }
public ValueType? Parse(string s) {
using var ms = new MemoryStream(Encoding.Default.GetBytes(s));
return Parse(ms);
}
public ValueType? Parse(Stream stream) {
Scanner = new ColumnSortExpressionScanner(stream);
Parse();
return CurrentSemanticValue;
}
}
@@ -0,0 +1,9 @@
namespace Bts.ColumnSortExpressions;
partial class ColumnSortExpressionScanner {
public override void yyerror(string format, params object[] args) {
base.yyerror(format, args);
Console.WriteLine(format, args);
Console.WriteLine();
}
}
@@ -0,0 +1,30 @@
%namespace Bts.ColumnSortExpressions
%scannertype ColumnSortExpressionScanner
%visibility internal
%tokentype ColumnSortExpressionToken
%option stack, minimize, parser, verbose, persistbuffer, noembedbuffers
/* Literal Constants */
Letter [a-zA-Z]
Identifier {Letter}({Letter}*[0-9]*_*)*
Ascending +
Descending -
%%
{Ascending} {
return (int)ColumnSortExpressionToken.ASCENDING;
}
{Descending} {
return (int)ColumnSortExpressionToken.DESCENDING;
}
{Identifier} {
yylval.Identifier = yytext;
return (int)ColumnSortExpressionToken.IDENTIFIER;
}
%%
@@ -0,0 +1,720 @@
// ==============================================================
// <auto-generated>
// This code automatically produced from an embedded resource.
// Do not edit this file, or it will become incompatible with
// the specification from which it was generated.
// </auto-generated>
// ==============================================================
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using System.Globalization;
namespace QUT.GplexBuffers
{
// Code copied from GPLEX embedded resource
[Serializable]
internal class BufferException : Exception
{
public BufferException() { }
public BufferException(string message) : base(message) { }
public BufferException(string message, Exception innerException)
: base(message, innerException) { }
protected BufferException(SerializationInfo info, StreamingContext context)
: base(info, context) { }
}
internal abstract class ScanBuff
{
private string fileNm;
public const int EndOfFile = -1;
public const int UnicodeReplacementChar = 0xFFFD;
public bool IsFile { get { return (fileNm != null); } }
public string FileName { get { return fileNm; } set { fileNm = value; } }
public abstract int Pos { get; set; }
public abstract int Read();
public virtual void Mark() { }
public abstract string GetString(int begin, int limit);
public static ScanBuff GetBuffer(string source)
{
return new StringBuffer(source);
}
public static ScanBuff GetBuffer(IList<string> source)
{
return new LineBuffer(source);
}
#if (!NOFILES)
public static ScanBuff GetBuffer(Stream source)
{
return new BuildBuffer(source);
}
#if (!BYTEMODE)
public static ScanBuff GetBuffer(Stream source, int fallbackCodePage)
{
return new BuildBuffer(source, fallbackCodePage);
}
#endif // !BYTEMODE
#endif // !NOFILES
}
#region Buffer classes
// ==============================================================
// ===== Definitions for various ScanBuff derived classes ====
// ==============================================================
// =============== String input ================
// ==============================================================
/// <summary>
/// This class reads characters from a single string as
/// required, for example, by Visual Studio language services
/// </summary>
sealed class StringBuffer : ScanBuff
{
string str; // input buffer
int bPos; // current position in buffer
int sLen;
public StringBuffer(string source)
{
this.str = source;
this.sLen = source.Length;
this.FileName = null;
}
public override int Read()
{
if (bPos < sLen) return str[bPos++];
else if (bPos == sLen) { bPos++; return '\n'; } // one strike, see new line
else { bPos++; return EndOfFile; } // two strikes and you're out!
}
public override string GetString(int begin, int limit)
{
// "limit" can be greater than sLen with the BABEL
// option set. Read returns a "virtual" EOL if
// an attempt is made to read past the end of the
// string buffer. Without the guard any attempt
// to fetch yytext for a token that includes the
// EOL will throw an index exception.
if (limit > sLen) limit = sLen;
if (limit <= begin) return "";
else return str.Substring(begin, limit - begin);
}
public override int Pos
{
get { return bPos; }
set { bPos = value; }
}
public override string ToString() { return "StringBuffer"; }
}
// ==============================================================
// The LineBuff class contributed by Nigel Horspool,
// nigelh@cs.uvic.cs
// ==============================================================
sealed class LineBuffer : ScanBuff
{
IList<string> line; // list of source lines from a file
int numLines; // number of strings in line list
string curLine; // current line in that list
int cLine; // index of current line in the list
int curLen; // length of current line
int curLineStart; // position of line start in whole file
int curLineEnd; // position of line end in whole file
int maxPos; // max position ever visited in whole file
int cPos; // ordinal number of code in source
// Constructed from a list of strings, one per source line.
// The lines have had trailing '\n' characters removed.
public LineBuffer(IList<string> lineList)
{
line = lineList;
numLines = line.Count;
cPos = curLineStart = 0;
curLine = (numLines > 0 ? line[0] : "");
maxPos = curLineEnd = curLen = curLine.Length;
cLine = 1;
FileName = null;
}
public override int Read()
{
if (cPos < curLineEnd)
return curLine[cPos++ - curLineStart];
if (cPos++ == curLineEnd)
return '\n';
if (cLine >= numLines)
return EndOfFile;
curLine = line[cLine];
curLen = curLine.Length;
curLineStart = curLineEnd + 1;
curLineEnd = curLineStart + curLen;
if (curLineEnd > maxPos)
maxPos = curLineEnd;
cLine++;
return curLen > 0 ? curLine[0] : '\n';
}
// To speed up searches for the line containing a position
private int cachedPosition;
private int cachedIxdex;
private int cachedLineStart;
// Given a position pos within the entire source, the results are
// ix -- the index of the containing line
// lstart -- the position of the first character on that line
private void findIndex(int pos, out int ix, out int lstart)
{
if (pos >= cachedPosition)
{
ix = cachedIxdex; lstart = cachedLineStart;
}
else
{
ix = lstart = 0;
}
while (ix < numLines)
{
int len = line[ix].Length + 1;
if (pos < lstart + len) break;
lstart += len;
ix++;
}
cachedPosition = pos;
cachedIxdex = ix;
cachedLineStart = lstart;
}
public override string GetString(int begin, int limit)
{
if (begin >= maxPos || limit <= begin) return "";
int endIx, begIx, endLineStart, begLineStart;
findIndex(begin, out begIx, out begLineStart);
int begCol = begin - begLineStart;
findIndex(limit, out endIx, out endLineStart);
int endCol = limit - endLineStart;
string s = line[begIx];
if (begIx == endIx)
{
// the usual case, substring all on one line
return (endCol <= s.Length) ?
s.Substring(begCol, endCol - begCol)
: s.Substring(begCol) + "\n";
}
// the string spans multiple lines, yuk!
StringBuilder sb = new StringBuilder();
if (begCol < s.Length)
sb.Append(s.Substring(begCol));
for (; ; )
{
sb.Append("\n");
s = line[++begIx];
if (begIx >= endIx) break;
sb.Append(s);
}
if (endCol <= s.Length)
{
sb.Append(s.Substring(0, endCol));
}
else
{
sb.Append(s);
sb.Append("\n");
}
return sb.ToString();
}
public override int Pos
{
get { return cPos; }
set
{
cPos = value;
findIndex(cPos, out cLine, out curLineStart);
// cLine should be the *next* line after curLine.
curLine = (cLine < numLines ? line[cLine++] : "");
curLineEnd = curLineStart + curLine.Length;
}
}
public override string ToString() { return "LineBuffer"; }
}
#if (!NOFILES)
// ==============================================================
// ===== class BuildBuff : for unicode text files ========
// ==============================================================
class BuildBuffer : ScanBuff
{
// Double buffer for char stream.
class BufferElement
{
StringBuilder bldr = new StringBuilder();
StringBuilder next = new StringBuilder();
int minIx;
int maxIx;
int brkIx;
bool appendToNext;
internal BufferElement() { }
internal int MaxIndex { get { return maxIx; } }
// internal int MinIndex { get { return minIx; } }
internal char this[int index]
{
get
{
if (index < minIx || index >= maxIx)
throw new BufferException("Index was outside data buffer");
else if (index < brkIx)
return bldr[index - minIx];
else
return next[index - brkIx];
}
}
internal void Append(char[] block, int count)
{
maxIx += count;
if (appendToNext)
this.next.Append(block, 0, count);
else
{
this.bldr.Append(block, 0, count);
brkIx = maxIx;
appendToNext = true;
}
}
internal string GetString(int start, int limit)
{
if (limit <= start)
return "";
if (start >= minIx && limit <= maxIx)
if (limit < brkIx) // String entirely in bldr builder
return bldr.ToString(start - minIx, limit - start);
else if (start >= brkIx) // String entirely in next builder
return next.ToString(start - brkIx, limit - start);
else // Must do a string-concatenation
return
bldr.ToString(start - minIx, brkIx - start) +
next.ToString(0, limit - brkIx);
else
throw new BufferException("String was outside data buffer");
}
internal void Mark(int limit)
{
if (limit > brkIx + 16) // Rotate blocks
{
StringBuilder temp = bldr;
bldr = next;
next = temp;
next.Length = 0;
minIx = brkIx;
brkIx = maxIx;
}
}
}
BufferElement data = new BufferElement();
int bPos; // Postion index in the StringBuilder
BlockReader NextBlk; // Delegate that serves char-arrays;
private string EncodingName
{
get
{
StreamReader rdr = NextBlk.Target as StreamReader;
return (rdr == null ? "raw-bytes" : rdr.CurrentEncoding.BodyName);
}
}
public BuildBuffer(Stream stream)
{
FileStream fStrm = (stream as FileStream);
if (fStrm != null) FileName = fStrm.Name;
NextBlk = BlockReaderFactory.Raw(stream);
}
#if (!BYTEMODE)
public BuildBuffer(Stream stream, int fallbackCodePage)
{
FileStream fStrm = (stream as FileStream);
if (fStrm != null) FileName = fStrm.Name;
NextBlk = BlockReaderFactory.Get(stream, fallbackCodePage);
}
#endif
/// <summary>
/// Marks a conservative lower bound for the buffer,
/// allowing space to be reclaimed. If an application
/// needs to call GetString at arbitrary past locations
/// in the input stream, Mark() is not called.
/// </summary>
public override void Mark() { data.Mark(bPos - 2); }
public override int Pos
{
get { return bPos; }
set { bPos = value; }
}
/// <summary>
/// Read returns the ordinal number of the next char, or
/// EOF (-1) for an end of stream. Note that the next
/// code point may require *two* calls of Read().
/// </summary>
/// <returns></returns>
public override int Read()
{
//
// Characters at positions
// [data.offset, data.offset + data.bldr.Length)
// are available in data.bldr.
//
if (bPos < data.MaxIndex)
{
// ch0 cannot be EOF
return (int)data[bPos++];
}
else // Read from underlying stream
{
// Experimental code, blocks of page size
char[] chrs = new char[4096];
int count = NextBlk(chrs, 0, 4096);
if (count == 0)
return EndOfFile;
else
{
data.Append(chrs, count);
return (int)data[bPos++];
}
}
}
public override string GetString(int begin, int limit)
{
return data.GetString(begin, limit);
}
public override string ToString()
{
return "StringBuilder buffer, encoding: " + this.EncodingName;
}
}
// =============== End ScanBuff-derived classes ==================
internal delegate int BlockReader(char[] block, int index, int number);
// A delegate factory, serving up a delegate that
// reads a block of characters from the underlying
// encoded stream, via a StreamReader object.
//
internal static class BlockReaderFactory
{
public static BlockReader Raw(Stream stream)
{
return delegate(char[] block, int index, int number)
{
byte[] b = new byte[number];
int count = stream.Read(b, 0, number);
int i = 0;
int j = index;
for (; i < count; i++, j++)
block[j] = (char)b[i];
return count;
};
}
#if (!BYTEMODE)
public static BlockReader Get(Stream stream, int fallbackCodePage)
{
Encoding encoding;
int preamble = Preamble(stream);
if (preamble != 0) // There is a valid BOM here!
encoding = Encoding.GetEncoding(preamble);
else if (fallbackCodePage == -1) // Fallback is "raw" bytes
return Raw(stream);
else if (fallbackCodePage != -2) // Anything but "guess"
encoding = Encoding.GetEncoding(fallbackCodePage);
else // This is the "guess" option
{
int guess = new Guesser(stream).GuessCodePage();
stream.Seek(0, SeekOrigin.Begin);
if (guess == -1) // ==> this is a 7-bit file
encoding = Encoding.ASCII;
else if (guess == 65001)
encoding = Encoding.UTF8;
else // ==> use the machine default
encoding = Encoding.Default;
}
StreamReader reader = new StreamReader(stream, encoding);
return reader.Read;
}
static int Preamble(Stream stream)
{
int b0 = stream.ReadByte();
int b1 = stream.ReadByte();
if (b0 == 0xfe && b1 == 0xff)
return 1201; // UTF16BE
if (b0 == 0xff && b1 == 0xfe)
return 1200; // UTF16LE
int b2 = stream.ReadByte();
if (b0 == 0xef && b1 == 0xbb && b2 == 0xbf)
return 65001; // UTF8
//
// There is no unicode preamble, so we
// return denoter for the machine default.
//
stream.Seek(0, SeekOrigin.Begin);
return 0;
}
#endif // !BYTEMODE
}
#endif // !NOFILES
#endregion Buffer classes
// ==============================================================
// ============ class CodePageHandling =============
// ==============================================================
#if (!NOFILES)
public static class CodePageHandling
{
public static int GetCodePage(string option)
{
string command = option.ToUpperInvariant();
if (command.StartsWith("CodePage:", StringComparison.OrdinalIgnoreCase))
command = command.Substring(9);
try
{
if (command.Equals("RAW"))
return -1;
else if (command.Equals("GUESS"))
return -2;
else if (command.Equals("DEFAULT"))
return 0;
else if (char.IsDigit(command[0]))
return int.Parse(command, CultureInfo.InvariantCulture);
else
{
Encoding enc = Encoding.GetEncoding(command);
return enc.CodePage;
}
}
catch (FormatException)
{
Console.Error.WriteLine(
"Invalid format \"{0}\", using machine default", option);
}
catch (ArgumentException)
{
Console.Error.WriteLine(
"Unknown code page \"{0}\", using machine default", option);
}
return 0;
}
}
#region guesser
#if (!BYTEMODE)
// ==============================================================
// ============ Encoding Guesser =============
// ==============================================================
/// <summary>
/// This class provides a simple finite state automaton that
/// scans the file looking for (1) valid UTF-8 byte patterns,
/// (2) bytes >= 0x80 which are not part of a UTF-8 sequence.
/// The method then guesses whether it is UTF-8 or maybe some
/// local machine default encoding. This works well for the
/// various Latin encodings.
/// </summary>
internal class Guesser
{
ScanBuff buffer;
public int GuessCodePage() { return Scan(); }
const int maxAccept = 10;
const int initial = 0;
const int eofNum = 0;
const int goStart = -1;
const int INITIAL = 0;
const int EndToken = 0;
#region user code
/*
* Reads the bytes of a file to determine if it is
* UTF-8 or a single-byte code page file.
*/
public long utfX;
public long uppr;
#endregion user code
int state;
int currentStart = startState[0];
int code;
#region ScannerTables
static int[] startState = new int[] { 11, 0 };
#region CharacterMap
static sbyte[] map = new sbyte[256] {
/* '\0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '\x10' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '\x20' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '@' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 'P' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '`' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 'p' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* '\x80' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\x90' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\xA0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\xB0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* '\xC0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* '\xD0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* '\xE0' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
/* '\xF0' */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5 };
#endregion
static sbyte[][] nextState = new sbyte[][] {
new sbyte[] {0, 0, 0, 0, 0, 0},
new sbyte[] {-1, -1, 10, -1, -1, -1},
new sbyte[] {-1, -1, -1, -1, -1, -1},
new sbyte[] {-1, -1, 8, -1, -1, -1},
new sbyte[] {-1, -1, 5, -1, -1, -1},
new sbyte[] {-1, -1, 6, -1, -1, -1},
new sbyte[] {-1, -1, 7, -1, -1, -1},
null,
new sbyte[] {-1, -1, 9, -1, -1, -1},
null,
null,
new sbyte[] {-1, 1, 2, 3, 4, 2}
};
[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
// Reason for suppression: cannot have self-reference in array initializer.
static Guesser()
{
nextState[7] = nextState[2];
nextState[9] = nextState[2];
nextState[10] = nextState[2];
}
int NextState()
{
if (code == ScanBuff.EndOfFile)
return eofNum;
else
return nextState[state][map[code]];
}
#endregion
public Guesser(System.IO.Stream file) { SetSource(file); }
public void SetSource(System.IO.Stream source)
{
this.buffer = new BuildBuffer(source);
code = buffer.Read();
}
int Scan()
{
for (; ; )
{
int next;
state = currentStart;
while ((next = NextState()) == goStart)
code = buffer.Read();
state = next;
code = buffer.Read();
while ((next = NextState()) > eofNum)
{
state = next;
code = buffer.Read();
}
if (state <= maxAccept)
{
#region ActionSwitch
#pragma warning disable 162
switch (state)
{
case eofNum:
switch (currentStart)
{
case 11:
if (utfX == 0 && uppr == 0) return -1; /* raw ascii */
else if (uppr * 10 > utfX) return 0; /* default code page */
else return 65001; /* UTF-8 encoding */
break;
}
return EndToken;
case 1: // Recognized '{Upper128}', Shortest string "\xC0"
case 2: // Recognized '{Upper128}', Shortest string "\x80"
case 3: // Recognized '{Upper128}', Shortest string "\xE0"
case 4: // Recognized '{Upper128}', Shortest string "\xF0"
uppr++;
break;
case 5: // Recognized '{Utf8pfx4}{Utf8cont}', Shortest string "\xF0\x80"
uppr += 2;
break;
case 6: // Recognized '{Utf8pfx4}{Utf8cont}{2}', Shortest string "\xF0\x80\x80"
uppr += 3;
break;
case 7: // Recognized '{Utf8pfx4}{Utf8cont}{3}', Shortest string "\xF0\x80\x80\x80"
utfX += 3;
break;
case 8: // Recognized '{Utf8pfx3}{Utf8cont}', Shortest string "\xE0\x80"
uppr += 2;
break;
case 9: // Recognized '{Utf8pfx3}{Utf8cont}{2}', Shortest string "\xE0\x80\x80"
utfX += 2;
break;
case 10: // Recognized '{Utf8pfx2}{Utf8cont}', Shortest string "\xC0\x80"
utfX++;
break;
default:
break;
}
#pragma warning restore 162
#endregion
}
}
}
} // end class Guesser
#endif // !BYTEMODE
#endregion
#endif // !NOFILES
// End of code copied from embedded resource
}
@@ -0,0 +1,884 @@
// ==============================================================
// <auto-generated>
// This code automatically produced from an embedded resource.
// Do not edit this file, or it will become incompatible with
// the specification from which it was generated.
// </auto-generated>
// ==============================================================
// Gardens Point Parser Generator
// Copyright (c) Wayne Kelly, QUT 2005-2010
// (see accompanying GPPGcopyright.rtf)
using System;
using System.Text;
using System.Globalization;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Diagnostics.CodeAnalysis;
namespace QUT.Gppg {
/// <summary>
/// Abstract class for GPPG shift-reduce parsers.
/// Parsers generated by GPPG derive from this base
/// class, overriding the abstract Initialize() and
/// DoAction() methods.
/// </summary>
/// <typeparam name="TValue">Semantic value type</typeparam>
/// <typeparam name="TSpan">Location type</typeparam>
#if EXPORT_GPPG
public abstract class ShiftReduceParser<TValue, TSpan>
#else
internal abstract class ShiftReduceParser<TValue, TSpan>
#endif
where TSpan : IMerge<TSpan>, new() {
private AbstractScanner<TValue, TSpan> scanner;
/// <summary>
/// The abstract scanner for this parser.
/// </summary>
protected AbstractScanner<TValue, TSpan> Scanner {
get { return scanner; }
set { scanner = value; }
}
/// <summary>
/// Constructor for base class
/// </summary>
/// <param name="scanner">Scanner instance for this parser</param>
protected ShiftReduceParser( AbstractScanner<TValue, TSpan> scanner ) {
this.scanner = scanner;
}
// ==============================================================
// TECHNICAL EXPLANATION.
// Why the next two fields are not exposed via properties.
// ==============================================================
// These fields are of the generic parameter types, and are
// frequently instantiated as struct types in derived classes.
// Semantic actions are defined in the derived classes and refer
// to instance fields of these structs. In such cases the code
// "get_CurrentSemanticValue().myField = blah;" will fail since
// the getter pushes the value of the field, not the reference.
// So, in the presence of properties, gppg would need to encode
// such field accesses as ...
// "tmp = get_CurrentSemanticValue(); // Fetch value
// tmp.myField = blah; // update
// set_CurrentSemanticValue(tmp); " // Write update back.
// There is no issue if TValue is restricted to be a ref type.
// The same explanation applies to scanner.yylval.
// ==============================================================
/// <summary>
/// The current value of the "$$" symbolic variable in the parser
/// </summary>
[SuppressMessage( "Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields" )]
protected TValue CurrentSemanticValue;
/// <summary>
/// The current value of the "@$" symbolic variable in the parser
/// </summary>
[SuppressMessage( "Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields" )]
protected TSpan CurrentLocationSpan;
protected int NextToken;
private TSpan LastSpan;
private State FsaState;
private bool recovering;
private int tokensSinceLastError;
private PushdownPrefixState<State> StateStack = new PushdownPrefixState<State>();
private PushdownPrefixState<TValue> valueStack = new PushdownPrefixState<TValue>();
private PushdownPrefixState<TSpan> locationStack = new PushdownPrefixState<TSpan>();
/// <summary>
/// The stack of semantic value (YYSTYPE) values.
/// </summary>
protected PushdownPrefixState<TValue> ValueStack { get { return valueStack; } }
/// <summary>
/// The stack of location value (YYLTYPE) varlues.
/// </summary>
protected PushdownPrefixState<TSpan> LocationStack { get { return locationStack; } }
private int errorToken;
private int endOfFileToken;
private string[] nonTerminals;
private State[] states;
private Rule[] rules;
/// <summary>
/// Initialization method to allow derived classes
/// to insert the rule list into this base class.
/// </summary>
/// <param name="rules">The array of Rule objects</param>
protected void InitRules( Rule[] rules ) { this.rules = rules; }
/// <summary>
/// Initialization method to allow derived classes to
/// insert the states table into this base class.
/// </summary>
/// <param name="states">The pre-initialized states table</param>
protected void InitStates( State[] states ) { this.states = states; }
/// <summary>
/// OBSOLETE FOR VERSION 1.4.0
/// </summary>
/// <param name="size"></param>
protected void InitStateTable( int size ) { states = new State[size]; }
/// <summary>
/// Initialization method to allow derived classes
/// to insert the special value for the error and EOF tokens.
/// </summary>
/// <param name="err">The error state ordinal</param>
/// <param name="end">The EOF stat ordinal</param>
protected void InitSpecialTokens( int err, int end ) {
errorToken = err;
endOfFileToken = end;
}
/// <summary>
/// Initialization method to allow derived classes to
/// insert the non-terminal symbol names into this base class.
/// </summary>
/// <param name="names">Non-terminal symbol names</param>
protected void InitNonTerminals( string[] names ) { nonTerminals = names; }
#region YYAbort, YYAccept etcetera.
[Serializable]
[SuppressMessage( "Microsoft.Design", "CA1064:ExceptionsShouldBePublic" )]
// Reason for FxCop message suppression -
// This exception cannot escape from the local context
private class AcceptException : Exception {
internal AcceptException() { }
protected AcceptException( SerializationInfo i, StreamingContext c ) : base( i, c ) { }
}
[Serializable]
[SuppressMessage( "Microsoft.Design", "CA1064:ExceptionsShouldBePublic" )]
// Reason for FxCop message suppression -
// This exception cannot escape from the local context
private class AbortException : Exception {
internal AbortException() { }
protected AbortException( SerializationInfo i, StreamingContext c ) : base( i, c ) { }
}
[Serializable]
[SuppressMessage( "Microsoft.Design", "CA1064:ExceptionsShouldBePublic" )]
// Reason for FxCop message suppression -
// This exception cannot escape from the local context
private class ErrorException : Exception {
internal ErrorException() { }
protected ErrorException( SerializationInfo i, StreamingContext c ) : base( i, c ) { }
}
// The following methods are only called from within
// a semantic action. The thrown exceptions can never
// propagate outside the ShiftReduceParser class in
// which they are nested.
/// <summary>
/// Force parser to terminate, returning "true"
/// </summary>
protected static void YYAccept() { throw new AcceptException(); }
/// <summary>
/// Force parser to terminate, returning "false"
/// </summary>
protected static void YYAbort() { throw new AbortException(); }
/// <summary>
/// Force parser to terminate, returning
/// "false" if error recovery fails.
/// </summary>
protected static void YYError() { throw new ErrorException(); }
/// <summary>
/// Check if parser in error recovery state.
/// </summary>
protected bool YYRecovering { get { return recovering; } }
#endregion
/// <summary>
/// Abstract base method. ShiftReduceParser calls this
/// to initialize the base class data structures. Concrete
/// parser classes must override this method.
/// </summary>
protected abstract void Initialize();
/// <summary>
/// Main entry point of the Shift-Reduce Parser.
/// </summary>
/// <returns>True if parse succeeds, else false for
/// unrecoverable errors</returns>
public bool Parse() {
Initialize(); // allow derived classes to instantiate rules, states and nonTerminals
NextToken = 0;
FsaState = states[0];
StateStack.Push( FsaState );
valueStack.Push( CurrentSemanticValue );
LocationStack.Push( CurrentLocationSpan );
while (true) {
#if TRACE_ACTIONS
Console.Error.WriteLine("Entering state {0} ", FsaState.number);
DisplayStack();
#endif
int action = FsaState.defaultAction;
if (FsaState.ParserTable != null) {
if (NextToken == 0) {
// We save the last token span, so that the location span
// of production right hand sides that begin or end with a
// nullable production will be correct.
LastSpan = scanner.yylloc;
NextToken = scanner.yylex();
#if TRACE_ACTIONS
Console.Error.WriteLine( "Reading: Next token is {0}", TerminalToString( NextToken ) );
#endif
}
#if TRACE_ACTIONS
else
Console.Error.WriteLine( "Next token is still {0}", TerminalToString( NextToken ) );
#endif
if (FsaState.ParserTable.ContainsKey( NextToken ))
action = FsaState.ParserTable[NextToken];
}
if (action > 0) // shift
{
Shift( action );
}
else if (action < 0) // reduce
{
try {
Reduce( -action );
if (action == -1) // accept
return true;
}
catch (AbortException) {
return false;
}
catch (AcceptException) {
return true;
}
catch (ErrorException) {
if (!ErrorRecovery())
return false;
else
throw; // Rethrow x, preserving information.
}
}
else if (action == 0 && !ErrorRecovery()) // error
return false;
}
}
private void Shift( int stateIndex ) {
#if TRACE_ACTIONS
Console.Error.Write("Shifting token {0}, ", TerminalToString(NextToken));
#endif
FsaState = states[stateIndex];
valueStack.Push( scanner.yylval );
StateStack.Push( FsaState );
LocationStack.Push( scanner.yylloc );
if (recovering) {
if (NextToken != errorToken)
tokensSinceLastError++;
if (tokensSinceLastError > 5)
recovering = false;
}
if (NextToken != endOfFileToken)
NextToken = 0;
}
private void Reduce( int ruleNumber ) {
#if TRACE_ACTIONS
DisplayRule(ruleNumber);
#endif
Rule rule = rules[ruleNumber];
int rhLen = rule.RightHandSide.Length;
//
// Default actions for unit productions.
//
if (rhLen == 1) {
CurrentSemanticValue = valueStack.TopElement(); // Default action: $$ = $1;
CurrentLocationSpan = LocationStack.TopElement(); // Default action "@$ = @1;
}
else if (rhLen == 0) {
// Create a new blank value.
// Explicit semantic action may mutate this value
CurrentSemanticValue = default( TValue );
// The location span for an empty production will start with the
// beginning of the next lexeme, and end with the finish of the
// previous lexeme. This gives the correct behaviour when this
// nonsense value is used in later Merge operations.
CurrentLocationSpan = (scanner.yylloc != null && LastSpan != null ?
scanner.yylloc.Merge( LastSpan ) :
default( TSpan ));
}
else {
// Default action: $$ = $1;
CurrentSemanticValue = valueStack[LocationStack.Depth - rhLen];
// Default action "@$ = @1.Merge(@N)" for location info.
TSpan at1 = LocationStack[LocationStack.Depth - rhLen];
TSpan atN = LocationStack[LocationStack.Depth - 1];
CurrentLocationSpan =
((at1 != null && atN != null) ? at1.Merge( atN ) : default( TSpan ));
}
DoAction( ruleNumber );
for (int i = 0; i < rule.RightHandSide.Length; i++) {
StateStack.Pop();
valueStack.Pop();
LocationStack.Pop();
}
FsaState = StateStack.TopElement();
if (FsaState.Goto.ContainsKey( rule.LeftHandSide ))
FsaState = states[FsaState.Goto[rule.LeftHandSide]];
StateStack.Push( FsaState );
valueStack.Push( CurrentSemanticValue );
LocationStack.Push( CurrentLocationSpan );
}
/// <summary>
/// Execute the selected action from array.
/// Must be overriden in derived classes.
/// </summary>
/// <param name="actionNumber">Index of the action to perform</param>
protected abstract void DoAction( int actionNumber );
private bool ErrorRecovery() {
bool discard;
if (!recovering) // if not recovering from previous error
ReportError();
if (!FindErrorRecoveryState())
return false;
//
// The interim fix for the "looping in error recovery"
// artifact involved moving the setting of the recovering
// bool until after invalid tokens have been discarded.
//
ShiftErrorToken();
discard = DiscardInvalidTokens();
recovering = true;
tokensSinceLastError = 0;
return discard;
}
private void ReportError() {
StringBuilder errorMsg = new StringBuilder();
errorMsg.AppendFormat( "Syntax error, unexpected {0}", TerminalToString( NextToken ) );
if (FsaState.ParserTable.Count < 7) {
bool first = true;
foreach (int terminal in FsaState.ParserTable.Keys) {
if (first)
errorMsg.Append( ", expecting " );
else
errorMsg.Append( ", or " );
errorMsg.Append( TerminalToString( terminal ) );
first = false;
}
}
scanner.yyerror( errorMsg.ToString() );
}
private void ShiftErrorToken() {
int old_next = NextToken;
NextToken = errorToken;
Shift( FsaState.ParserTable[NextToken] );
#if TRACE_ACTIONS
Console.Error.WriteLine("Entering state {0} ", FsaState.number);
#endif
NextToken = old_next;
}
private bool FindErrorRecoveryState() {
while (true) // pop states until one found that accepts error token
{
if (FsaState.ParserTable != null &&
FsaState.ParserTable.ContainsKey( errorToken ) &&
FsaState.ParserTable[errorToken] > 0) // shift
return true;
#if TRACE_ACTIONS
Console.Error.WriteLine("Error: popping state {0}", StateStack.TopElement().number);
#endif
StateStack.Pop();
valueStack.Pop();
LocationStack.Pop();
#if TRACE_ACTIONS
DisplayStack();
#endif
if (StateStack.IsEmpty()) {
#if TRACE_ACTIONS
Console.Error.WriteLine("Aborting: didn't find a state that accepts error token");
#endif
return false;
}
else
FsaState = StateStack.TopElement();
}
}
private bool DiscardInvalidTokens() {
int action = FsaState.defaultAction;
if (FsaState.ParserTable != null) {
// Discard tokens until find one that works ...
while (true) {
if (NextToken == 0) {
#if TRACE_ACTIONS
Console.Error.Write("Reading a token: ");
#endif
NextToken = scanner.yylex();
}
#if TRACE_ACTIONS
Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken));
#endif
if (NextToken == endOfFileToken)
return false;
if (FsaState.ParserTable.ContainsKey( NextToken ))
action = FsaState.ParserTable[NextToken];
if (action != 0)
return true;
else {
#if TRACE_ACTIONS
Console.Error.WriteLine("Error: Discarding {0}", TerminalToString(NextToken));
#endif
NextToken = 0;
}
}
}
else if (recovering && tokensSinceLastError == 0) {
//
// Boolean recovering is not set until after the first
// error token has been shifted. Thus if we get back
// here with recovering set and no tokens read we are
// looping on the same error recovery action. This
// happens if current_state.ParserTable is null because
// the state has an LR(0) reduction, but not all
// lookahead tokens are valid. This only occurs for
// error productions that *end* on "error".
//
// This action discards tokens one at a time until
// the looping stops. Another attack would be to always
// use the LALR(1) table if a production ends on "error"
//
#if TRACE_ACTIONS
Console.Error.WriteLine("Error: panic discard of {0}", TerminalToString(NextToken));
#endif
if (NextToken == endOfFileToken)
return false;
NextToken = 0;
return true;
}
else
return true;
}
/// <summary>
/// Traditional YACC method. Discards the next input token.
/// </summary>
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyclearin" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyclearin" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
protected void yyclearin() { NextToken = 0; }
/// <summary>
/// Tradional YACC method. Clear the "recovering" flag.
/// </summary>
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerrok" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerrok" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
protected void yyerrok() { recovering = false; }
/// <summary>
/// OBSOLETE FOR VERSION 1.4.0
/// Method used by derived types to insert new
/// state instances in the "states" array.
/// </summary>
/// <param name="stateNumber">index of the state</param>
/// <param name="state">data for the state</param>
protected void AddState( int stateNumber, State state ) {
states[stateNumber] = state;
state.number = stateNumber;
}
private void DisplayStack() {
Console.Error.Write( "State stack is now:" );
for (int i = 0; i < StateStack.Depth; i++)
Console.Error.Write( " {0}", StateStack[i].number );
Console.Error.WriteLine();
}
private void DisplayRule( int ruleNumber ) {
Console.Error.Write( "Reducing stack by rule {0}, ", ruleNumber );
DisplayProduction( rules[ruleNumber] );
}
private void DisplayProduction( Rule rule ) {
if (rule.RightHandSide.Length == 0)
Console.Error.Write( "/* empty */ " );
else
foreach (int symbol in rule.RightHandSide)
Console.Error.Write( "{0} ", SymbolToString( symbol ) );
Console.Error.WriteLine( "-> {0}", SymbolToString( rule.LeftHandSide ) );
}
/// <summary>
/// Abstract state class naming terminal symbols.
/// This is overridden by derived classes with the
/// name (or alias) to be used in error messages.
/// </summary>
/// <param name="terminal">The terminal ordinal</param>
/// <returns></returns>
protected abstract string TerminalToString( int terminal );
private string SymbolToString( int symbol ) {
if (symbol < 0)
return nonTerminals[-symbol - 1];
else
return TerminalToString( symbol );
}
/// <summary>
/// Return text representation of argument character
/// </summary>
/// <param name="input">The character to convert</param>
/// <returns>String representation of the character</returns>
protected static string CharToString( char input ) {
switch (input) {
case '\a': return @"'\a'";
case '\b': return @"'\b'";
case '\f': return @"'\f'";
case '\n': return @"'\n'";
case '\r': return @"'\r'";
case '\t': return @"'\t'";
case '\v': return @"'\v'";
case '\0': return @"'\0'";
default: return string.Format( CultureInfo.InvariantCulture, "'{0}'", input );
}
}
}
/// <summary>
/// Classes implementing this interface must supply a
/// method that merges two location objects to return
/// a new object of the same type.
/// GPPG-generated parsers have the default location
/// action equivalent to "@$ = @1.Merge(@N);" where N
/// is the right-hand-side length of the production.
/// </summary>
/// <typeparam name="TSpan">The Location type</typeparam>
#if EXPORT_GPPG
public interface IMerge<TSpan>
#else
internal interface IMerge<TSpan>
#endif
{
/// <summary>
/// Interface method that creates a location object from
/// the current and last object. Typically used to create
/// a location object extending from the start of the @1
/// object to the end of the @N object.
/// </summary>
/// <param name="last">The lexically last object to merge</param>
/// <returns>The merged location object</returns>
TSpan Merge( TSpan last );
}
/// <summary>
/// This is the default class that carries location
/// information from the scanner to the parser.
/// If you don't declare "%YYLTYPE Foo" the parser
/// will expect to deal with this type.
/// </summary>
#if EXPORT_GPPG
public class LexLocation : IMerge<LexLocation>
#else
[SuppressMessage( "Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses" )]
internal class LexLocation : IMerge<LexLocation>
#endif
{
private int startLine; // start line
private int startColumn; // start column
private int endLine; // end line
private int endColumn; // end column
/// <summary>
/// The line at which the text span starts.
/// </summary>
public int StartLine { get { return startLine; } }
/// <summary>
/// The column at which the text span starts.
/// </summary>
public int StartColumn { get { return startColumn; } }
/// <summary>
/// The line on which the text span ends.
/// </summary>
public int EndLine { get { return endLine; } }
/// <summary>
/// The column of the first character
/// beyond the end of the text span.
/// </summary>
public int EndColumn { get { return endColumn; } }
/// <summary>
/// Default no-arg constructor.
/// </summary>
public LexLocation() { }
/// <summary>
/// Constructor for text-span with given start and end.
/// </summary>
/// <param name="sl">start line</param>
/// <param name="sc">start column</param>
/// <param name="el">end line </param>
/// <param name="ec">end column</param>
public LexLocation( int sl, int sc, int el, int ec ) { startLine = sl; startColumn = sc; endLine = el; endColumn = ec; }
/// <summary>
/// Create a text location which spans from the
/// start of "this" to the end of the argument "last"
/// </summary>
/// <param name="last">The last location in the result span</param>
/// <returns>The merged span</returns>
public LexLocation Merge( LexLocation last ) { return new LexLocation( this.startLine, this.startColumn, last.endLine, last.endColumn ); }
}
/// <summary>
/// Abstract scanner class that GPPG expects its scanners to
/// extend.
/// </summary>
/// <typeparam name="TValue">Semantic value type YYSTYPE</typeparam>
/// <typeparam name="TSpan">Source location type YYLTYPE</typeparam>
#if EXPORT_GPPG
public abstract class AbstractScanner<TValue, TSpan>
#else
internal abstract class AbstractScanner<TValue, TSpan>
#endif
where TSpan : IMerge<TSpan> {
/// <summary>
/// Lexical value optionally set by the scanner. The value
/// is of the %YYSTYPE type declared in the parser spec.
/// </summary>
[SuppressMessage( "Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields" )]
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylval" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylval" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
// A field must be declared for this value of parametric type,
// since it may be instantiated by a value struct. If it were
// implemented as a property, machine generated code in derived
// types would not be able to select on the returned value.
#pragma warning disable 649
public TValue yylval; // Lexical value: set by scanner
#pragma warning restore 649
/// <summary>
/// Current scanner location property. The value is of the
/// type declared by %YYLTYPE in the parser specification.
/// </summary>
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylloc" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylloc" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
public virtual TSpan yylloc {
get { return default( TSpan ); } // Empty implementation allowing
set { /* skip */ } // yylloc to be ignored entirely.
}
/// <summary>
/// Main call point for LEX-like scanners. Returns an int
/// corresponding to the token recognized by the scanner.
/// </summary>
/// <returns>An int corresponding to the token</returns>
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
public abstract int yylex();
/// <summary>
/// Traditional error reporting provided by LEX-like scanners
/// to their YACC-like clients.
/// </summary>
/// <param name="format">Message format string</param>
/// <param name="args">Optional array of args</param>
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerror" )]
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerror" )]
// Reason for FxCop message suppression -
// This is a traditional name for YACC-like functionality
public virtual void yyerror( string format, params object[] args ) { }
}
/// <summary>
/// Encapsulated state for the parser.
/// Opaque to users, visible to the tool-generated code.
/// </summary>
#if EXPORT_GPPG
public class State
{
/// <summary>
/// The number of states in the automaton.
/// </summary>
public int number;
#else
internal class State {
/// <summary>
/// The index of this state in the states array.
/// </summary>
internal int number;
#endif
internal Dictionary<int, int> ParserTable; // Terminal -> ParseAction
internal Dictionary<int, int> Goto; // NonTerminal -> State;
internal int defaultAction; // = 0; // ParseAction
/// <summary>
/// State transition data for this state. Pairs of elements of the
/// goto array associate symbol ordinals with next state indices.
/// The actions array is passed to another constructor.
/// </summary>
/// <param name="actions">The action list</param>c
/// <param name="goToList">Next state data</param>
public State( int[] actions, int[] goToList )
: this( actions ) {
Goto = new Dictionary<int, int>();
for (int i = 0; i < goToList.Length; i += 2)
Goto.Add( goToList[i], goToList[i + 1] );
}
/// <summary>
/// Action data for this state. Pairs of elements of the
/// action array associate action ordinals with each of
/// those symbols that have actions in the current state.
/// </summary>
/// <param name="actions">The action array</param>
public State( int[] actions ) {
ParserTable = new Dictionary<int, int>();
for (int i = 0; i < actions.Length; i += 2)
ParserTable.Add( actions[i], actions[i + 1] );
}
/// <summary>
/// Set the default action for this state.
/// </summary>
/// <param name="defaultAction">Ordinal of the default action</param>
public State( int defaultAction ) {
this.defaultAction = defaultAction;
}
/// <summary>
/// Set the default action and the state transition table.
/// </summary>
/// <param name="defaultAction">The default action</param>
/// <param name="goToList">Transitions from this state</param>
public State( int defaultAction, int[] goToList )
: this( defaultAction ) {
Goto = new Dictionary<int, int>();
for (int i = 0; i < goToList.Length; i += 2)
Goto.Add( goToList[i], goToList[i + 1] );
}
}
/// <summary>
/// Rule representation at runtime.
/// </summary>
#if EXPORT_GPPG
public class Rule
#else
internal class Rule
#endif
{
internal int LeftHandSide; // symbol
internal int[] RightHandSide; // symbols
/// <summary>
/// Rule constructor. This holds the ordinal of
/// the left hand side symbol, and the list of
/// right hand side symbols, in lexical order.
/// </summary>
/// <param name="left">The LHS non-terminal</param>
/// <param name="right">The RHS symbols, in lexical order</param>
public Rule( int left, int[] right ) {
this.LeftHandSide = left;
this.RightHandSide = right;
}
}
/// <summary>
/// Stack utility for the shift-reduce parser.
/// GPPG parsers have three instances:
/// (1) The parser state stack, T = QUT.Gppg.State,
/// (2) The semantic value stack, T = TValue,
/// (3) The location stack, T = TSpan.
/// </summary>
/// <typeparam name="T"></typeparam>
#if EXPORT_GPPG
public class PushdownPrefixState<T>
#else
internal class PushdownPrefixState<T>
#endif
{
// Note that we cannot use the BCL Stack<T> class
// here as derived types need to index into stacks.
//
private T[] array = new T[8];
private int tos = 0;
/// <summary>
/// Indexer for values of the stack below the top.
/// </summary>
/// <param name="index">index of the element, starting from the bottom</param>
/// <returns>the selected element</returns>
public T this[int index] { get { return array[index]; } }
/// <summary>
/// The current depth of the stack.
/// </summary>
public int Depth { get { return tos; } }
internal void Push( T value ) {
if (tos >= array.Length) {
T[] newarray = new T[array.Length * 2];
System.Array.Copy( array, newarray, tos );
array = newarray;
}
array[tos++] = value;
}
internal T Pop() {
T rslt = array[--tos];
array[tos] = default( T );
return rslt;
}
internal T TopElement() { return array[tos - 1]; }
internal bool IsEmpty() { return tos == 0; }
}
}
@@ -0,0 +1,4 @@
global using System;
global using System.Linq;
global using System.Collections.Generic;
global using System.Collections.Immutable;
@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
<PackageReference Include="YaccLexTools" Version="1.2.0" />
<PackageReference Include="YaccLexTools" Version="1.2.2" />
</ItemGroup>
<ItemGroup>
@@ -0,0 +1,49 @@
using System;
namespace BCG {
[DataStreamUserRespresentation("count")]
public class CountStream : ViewStream {
private DataPacket myLastFiredDataPacket;
private IBlueTableSchema mySchema = new BlueTableSchema("count",
new ColumnInfo("id", 0, typeof(int)),
new ColumnInfo("count", 1, typeof(int)));
private int myId = 0;
private ViewStream myVS;
public CountStream(ViewStream vs) {
myVS = vs;
}
public CountStream(string tableName)
: this(new TableStream(tableName)) { }
protected override void myOnFirstSubscriber() {
myVS.onChange += new ChangeDelegate(myHandleChanges);
}
protected override void myOnLastSubscriber() {
myVS.onChange -= new ChangeDelegate(myHandleChanges);
}
private void myHandleChanges(object newValue) {
myFireEvent(
myLastFiredDataPacket =
myLastFiredDataPacket == null ?
new DataPacket(myGetRows(newValue, ++myId), myGetRows(newValue, myId),
new BlueTable(mySchema))
:
new DataPacket(myGetRows(newValue, ++myId), myGetRows(newValue, myId),
myLastFiredDataPacket.newRows)
);
}
private IBlueRowCollection myGetRows(object dp, int id) {
BlueTable retVal = new BlueTable(mySchema);
retVal.addRow
(new BlueRow(mySchema, id, (dp as DataPacket).newRows.Count));
return retVal;
}
}
}
@@ -0,0 +1,38 @@
namespace bts.BlueOrb {
using bts;
using BCG;
using System;
[DataStreamUserRespresentation("DateTimeExpanderStream")]
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_of_week");
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}_minute");
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_of_week", 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}_minute", dt.Minute);
rv.setValue($"{inp_col}_seconds_of_day", (dt - dt.Date).TotalSeconds);
return rv;
});
mySetRealSource(rs);
}
}
}
@@ -0,0 +1,158 @@
namespace bts.BlueOrb {
using BCG;
using System;
using System.Text.RegularExpressions;
public class RegExpFilter : IStreamFilter {
private Regex[] myRegExps;
private string[] myCols;
public RegExpFilter(string col, string regExp)
: this(new string[] { col }, new string[] { regExp }) { }
public RegExpFilter(string[] cols, string[] regExps) {
myCols = cols;
myRegExps = new Regex[regExps.Length];
for (int i = 0; i < regExps.Length; i++)
myRegExps[i] = new Regex(regExps[i]);
}
#region IStreamFilter Members
public bool filter(IBlueRow dr) {
bool rv = true;
for (int i = 0; i < myCols.Length; i++) {
rv &= myRegExps[i].IsMatch(dr[myCols[i]] is DBNull ? "" : dr[myCols[i]].ToString());
if (!rv)
return rv;
}
return rv;
}
#endregion
}
//[DataStreamUserReprsentation("FilterStream")]
public class FilterStream : ViewStream {
private BlueTable myLastFiredRows;
private IBlueRowCollection myLastReceivedRows;
private IStreamFilter myFilter;
private ViewStream myParentStream;
private string myFilterString;
private bool myUseNewFilter = false;// Configuration.get<DataStreamConfig>().UseNewFilter;
#region constructors
public delegate bool OnFilter(IBlueRow r);
private class OnFilterWrapper : IStreamFilter {
public OnFilterWrapper(OnFilter f) { this.f = f; }
public bool filter(IBlueRow dr) { return f(dr); }
private OnFilter f;
}
public FilterStream(ViewStream vs, OnFilter f)
: this(vs, new OnFilterWrapper(f)) { }
public FilterStream(ViewStream vs, IStreamFilter filter) {
{
myParentStream = vs;
myFilter = filter;
myFilterString = filter.ToString();
if (filter is IDynamicStreamFilter)
(filter as IDynamicStreamFilter).onFilterChange += new FilterChangeDelegate(myHandleFilterChange);
}
}
public FilterStream(ViewStream vs, string filterExpression)
: this(vs, new BooleanExpressionFilter(filterExpression)) {
myFilterString = filterExpression;
}
public FilterStream(ViewStream vs, string col, string regExp)
: this(vs, new RegExpFilter(col, regExp)) {
myFilterString = col + " , " + regExp;
}
public FilterStream(ViewStream vs)
: this(vs, new BinaryFilter(true)) {
myFilterString = true.ToString();
}
#endregion
#region overridden methods
protected override void myOnFirstSubscriber() { myParentStream.onChange += new ChangeDelegate(myHandleCallbacks); }
protected override void myOnLastSubscriber() {
myLastFiredRows = null;
myParentStream.onChange -= new ChangeDelegate(myHandleCallbacks);
}
protected override void myFireEvent(object o) {
DataPacket dp = o as DataPacket;
if (myLastValue == null || dp.addedRows.Count + dp.deletedRows.Count > 0)
base.myFireEvent(o);
}
#endregion
private void myHandleCallbacks(object newValue) {
DataPacket retVal;
DataPacket arrivedPacket = newValue as DataPacket;
myLastReceivedRows = arrivedPacket.newRows;
if (myLastFiredRows != null) {
retVal = new DataPacket(myLastFiredRows, new BlueTable(myLastFiredRows.schema),
new BlueTable(myLastFiredRows.schema));
foreach (IBlueRow r in arrivedPacket.deletedRows)
if (myLastFiredRows.containsID((int)r["id"])) {
myLastFiredRows.deleteRow(r);
(retVal.deletedRows as BlueTable).addRow(r);
}
foreach (IBlueRow r in arrivedPacket.addedRows)
if (myFilter.filter(r)) {
myLastFiredRows.addRow(r);
(retVal.addedRows as BlueTable).addRow(r);
}
} else {
myLastFiredRows = new BlueTable(arrivedPacket.schema);
retVal = new DataPacket(myLastFiredRows, myLastFiredRows, new BlueTable(myLastFiredRows.schema));
foreach (IBlueRow r in arrivedPacket.newRows)
if (myFilter.filter(r))
myLastFiredRows.addRow(r);
}
myFireEvent(retVal);
}
public IStreamFilter filter {
set {
{
myFilter = value;
if (numberOfSubscribers > 0) {
if (myLastReceivedRows != null) {
BlueTable nRows = new BlueTable(myLastReceivedRows.schema);
foreach (IBlueRow r in myLastReceivedRows)
if (myFilter.filter(r))
nRows.addRow(r);
IBlueRowCollection dRows = new BlueTable(nRows.schema),
aRows = new BlueTable(nRows.schema);
BlueDataUtility.computeDifferences(nRows, myLastFiredRows, out dRows, out aRows);
myLastFiredRows = nRows;
myFireEvent(new DataPacket(nRows, aRows, dRows));
}
}
}
}
get {
return myFilter;
}
}
//public string filterString { set { filter = new BooleanExpressionFilter(value); } }
public override string ToString() {
return GetType().ToString() + " " + myFilterString;
}
private void myHandleFilterChange() {
filter = myFilter;
}
}
}
@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.Json;
using bts;
//using bts.SilverPine;
using BCG;
namespace bts.BlueOrb {
[DataStreamUserRespresentation("GroupByStream")]
public class GroupByStream : ViewStream {
public interface INonIncGroupByEvaluator {
// grouped_rows
IBlueRowCollection evaluate(IDictionary<int, List<IBlueRow>> grouped_rows);
string[] get_group_by_cols();
}
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();
}
}
private ViewStream _main_stream;
private INonIncGroupByEvaluator _groupby_func;
private BlueRowHasher _row_hasher;
private string[] _groupby_cols;
private Stopwatch _timer = new();
private int _n_total_fires = 0, _n_expensive_fires = 0;
public GroupByStream(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);
}
public GroupByStream(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 GroupByStream(ViewStream parent_str, string groupby_col, string standard_group_by_text)
: this(parent_str, groupby_col, standard_group_by_text, String.Empty) { }
// this is the main constructor that does everything
public GroupByStream(ViewStream parent_str, string groupby_col, string standard_group_by_ops, string optional_sort_col) {
MultiRowOpHelper std_group_by = MultiRowOpHelper.parse_ops(standard_group_by_ops);
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));
// this si where the group by aggregation happens
IBlueRow rv = MultiRowOpHelper.group_by_compute(group_rows, std_group_by);
return new IBlueRow[] { rv }.ToList();
};
ViewStream rs = new GroupByStream(parent_str, groupby_cols_func, evaluate_func);
mySetRealSource(rs);
}
public GroupByStream(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) {
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);
_timer.Stop();
var groupElapsedMs = _timer.ElapsedMilliseconds;
if (groupElapsedMs >= 50) {
Log.DataFlow.info($"Time to group {dp.newRows.Count} rows into {grouped_rows.Count} groups: {_timer.ElapsedMilliseconds}ms");
}
// Log.log(bts.Log.Level.Info, bts.log.Subsystem.gen, String.Format("Time to group {0} rows into {1} groups = {2}", dp.newRows.Count, grouped_rows.Count, _timer.lastIntervalTime));
/// reducing
_timer.Restart();
IBlueRowCollection total_state = _groupby_func.evaluate(grouped_rows);
_timer.Stop();
var applyElapsedMs = _timer.ElapsedMilliseconds;
_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));
}
}
}
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BCG;
namespace bts.BlueOrb {
public interface INonIncJoinInlineMapper
{
IBlueTableSchema get_output_schema(IBlueTableSchema schema);
IBlueRowCollection map_rows(IBlueRowCollection rows);
event MapperChangeDelegate onMapperChange;
}
}
@@ -0,0 +1,152 @@
using bts;
using bts.collections;
using mbts;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
using BCG;
namespace bts.BlueOrb {
internal class NonIncJoinBookkeeper : IDisposable {
public Action on_new_data;
private readonly NonIncJoinSpec _join_spec;
private readonly int _join_position;
private readonly int _start_index_in_output;
private readonly BlueRowHasher _row_hasher;
private readonly bool _is_left_most;
private readonly bool _is_tag_along;
private int _n_total_fires = 0, _n_expensive_fires = 0;
private IBlueTableSchema _schema = null;
private IDictionary<int, IBlueRow> _row_map = new Dictionary<int, IBlueRow>();
private List<Pair<int, IBlueRow>> _row_list = new List<Pair<int, IBlueRow>>();
private IBlueRow _solitary_row = null;
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) {
_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}");
var timer = Stopwatch.StartNew();
DataPacket dp = (DataPacket)dp_obj;
_fill_missing_data(dp);
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) {
_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 {
if (_is_tag_along)
_solitary_row = BlueDataUtility.extractRow(dp.newRows, 0);
else {
_row_map.Clear();
foreach (IBlueRow r in dp.newRows)
_row_map[_row_hasher.get_hash(r, _join_col_indices)] = r;
}
}
timer.Stop();
_n_total_fires++;
if (timer.ElapsedMilliseconds >= 50) {
_n_expensive_fires++;
Log.Gen.info($"NonIncJoinBookkeepingData._on_stream_cb {dp.newRows.Count} rows {_join_col_indices.Length} "
+ $"key cols {_join_position} join pos time {timer.Elapsed} ratio {_n_expensive_fires}/{_n_total_fires}");
}
if (on_new_data != null)
on_new_data();
}
public bool is_ready { get { return _schema != null; } }
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) {
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) {
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 {
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);
else
copy_dbnull_to_output_row(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;
}
#region IDisposable
public void Dispose() { _join_spec.stream.onChange -= _on_stream_cb; }
#endregion
}
}
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BCG;
using mbts;
namespace bts.BlueOrb {
// this a collection of spec, theres no joining logic in here
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) { }
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) {
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(' ');
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) {
string[] toks = s.Split(':');
if (toks.Length == 1) {
data_col_names.Add(toks[0]);
mapped_col_names.Add(toks[0]);
} 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()));
}
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;
}
}
}
@@ -0,0 +1,165 @@
using bts;
using mbts;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using BCG;
namespace bts.BlueOrb {
[DataStreamUserRespresentation("JoinStream")]
public class NonIncJoinStream : ViewStream, BCG.Utilities.General.IWorker {
private readonly NonIncJoinSpec[] _join_specs;
private readonly INonIncJoinInlineMapper _output_mapper;
private readonly BlueRowHasher _row_hasher;
private readonly TimeSpan _throttle_period;
private readonly ViewStreamDatabase _vsd;
private List<NonIncJoinBookkeeper> _book_keeping_data = new List<NonIncJoinBookkeeper>();
private IBlueTableSchema _output_schema = null;
private DateTime _last_fire_time = DateTime.MinValue;
private bool _is_dirty = false;
public NonIncJoinStream(ViewStream left, string left_join_cols, string left_proj,
ViewStream right, string right_join_cols, string right_proj)
: this(new Triplet<ViewStream, string, string>[]
{
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) { }
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) {
}
public NonIncJoinStream(NonIncJoinSpec[] join_specs, INonIncJoinInlineMapper output_mapper, int throttles_ms = 0)
: this(ViewStreamDatabase.instance, join_specs, output_mapper, throttles_ms) { }
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);
_throttle_period = throttles_ms == 0 ? TimeSpan.Zero : new TimeSpan(0, 0, 0, 0, throttles_ms);
_vsd = vsd;
}
protected override void myOnFirstSubscriber() {
int data_col_no = 1;
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);
}
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() {
foreach (NonIncJoinBookkeeper d in _book_keeping_data)
d.Dispose();
if (_output_mapper != null)
_output_mapper.onMapperChange -= _on_mapper_change;
_vsd.removeWorker(this);
}
private void _stream_callback() {
//Log.Gen.info("NonIncJoinStream._stream_callback received callback");
_is_dirty = true;
doWork();
}
private void _on_mapper_change() {
_is_dirty = true;
doWork();
}
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) {
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);
_output_schema = new BlueTableSchema("NonIncJoinStream", cis.ToArray());
}
}
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()) {
_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++) {
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++) {
NonIncJoinBookkeeper bk_data = _book_keeping_data[ji];
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
bk_data.copy_matching_row_to_output_row(left_row_list[i].first, output_rows[i]);
}
}
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, true);
myFireEvent(dp_out);
//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) {
IBlueRowCollection output_rows;
var timer = Stopwatch.StartNew();
output_rows = _output_mapper.map_rows(unmapped_rows);
timer.Stop();
if (timer.ElapsedMilliseconds >= 50) {
Log.Gen.info($"Time to map {unmapped_rows.Count} rows into {output_rows.Count} rows {timer.Elapsed}");
}
return output_rows;
} 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) {
_is_dirty = false;
_last_fire_time = DateTime.Now;
_form_and_fire();
}
}
}
}
@@ -0,0 +1,28 @@
//namespace bts.Blueorb {
// using BCG;
// public class JsonSaverStream : ViewStream {
// private ViewStream _stream;
// private string _file_name;
// public JsonSaverStream(ViewStream vs, string file_name) {
// _stream = vs;
// _file_name = file_name;
// }
// protected override void myOnFirstSubscriber() {
// _stream.onChange += _on_data;
// }
// private void _on_data(object dp_obj) {
// if (dp_obj == null) {
// return;
// }
// DataPacket dp = dp_obj as DataPacket;
// dp.newRows.write_to_json_file(dp.newRows, _file_name);
// }
// protected override void myOnLastSubscriber() {
// _stream.onChange -= _on_data;
// }
// }
//}
@@ -0,0 +1,91 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Amazon.Runtime.Internal.Util;
using BCG;
using BCG.Utilities;
using bts;
namespace bts.BlueOrb{
public class LiteralStream : ViewStream {
public static List<Tuple<ColumnInfo, object>> parse_columns(string key_value_pairs) {
List<Tuple<ColumnInfo, object>> rv = new List<Tuple<ColumnInfo, object>>();
string[] pairs = key_value_pairs.Split(' ');
foreach (string p in pairs) {
string[] kvp = p.Split(':');
string col_name = kvp[0];
string val = kvp[1];
var tup = BlueDataUtility.guess_type(val);
var ci = new ColumnInfo(col_name, rv.Count, tup.Item1);
rv.Add(Tuple.Create(ci, tup.Item2));
}
return rv;
}
//literal("table1", "x:123, y:1.001, z:abc;x:123, y:1.001, z:abc")
// col_name: col_value ... ; col_name: col_value
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(' ');
ColumnInfo[] ci = new ColumnInfo[columns.Length + 1];
ci[0] = new ColumnInfo("id", 0, typeof(int));
int n = 1;
foreach (string c in columns) {
string[] columnAndType = c.Split('/');
if (columnAndType.Length == 1)
ci[n] = new ColumnInfo(c, n, typeof(double));
else
ci[n] = new ColumnInfo(columnAndType[0], n, Type.GetType("System." + columnAndType[1], true));
n++;
}
BlueTable t = new BlueTable(new BlueTableSchema(tableName, ci));
string[] rows = value.Split(';');
n = 0;
foreach (string r in rows)
try {
if (r == string.Empty)
continue;
t.addRow(
BlueDataUtility.createRowFromCSVFileRow(r, t.schema, ++n));
} catch (Exception e) {
throw (new Exception("Error occured at line: " + n.ToString() + " " + e.Message));
}
mySetRealSource(new BlueRowCollectionStaticStream(t));
}
}
}
@@ -0,0 +1,89 @@
using System;
using BCG.Utilities.General;
using BCG;
using bts;
namespace bts.BlueOrb {
[DataStreamUserRespresentation("MillisecondStream")]
public class MillisecondStream : ViewStream, IWorker {
private DateTime _last_fire_time = DateTime.MinValue;
private readonly TimeSpan _period;
private readonly int _size;
private readonly ViewStreamDatabase _vsd;
private IBlueTableSchema _schema;
private bts.CircularBufferTable _table;
public MillisecondStream(int interval_msecs, int size)
: this(ViewStreamDatabase.instance, interval_msecs, size) {
}
public MillisecondStream(ViewStreamDatabase vsd, int interval_msecs, int size) {
_vsd = vsd;
_period = TimeSpan.FromMilliseconds(interval_msecs);
_size = size;
_schema = BlueDataUtility.form_schema("Milliseconds",
Tuple.Create("id", TypeCode.Int32),
Tuple.Create("time", TypeCode.DateTime),
Tuple.Create("display_time", TypeCode.String));
_table = new CircularBufferTable(_schema, _size);
}
protected override void myOnFirstSubscriber() {
_vsd.addWorker(this);
}
protected override void myOnLastSubscriber() {
_vsd.removeWorker(this);
}
private int _id = 0;
public void doWork() {
if (DateTime.Now - _last_fire_time >= _period) {
_last_fire_time = DateTime.Now;
IBlueRow nr = new BlueRow(_schema, _id++, _last_fire_time,
_last_fire_time.ToString("yyyy-MM-dd HH:mm:ss.fff"));
_table.add_row(nr);
var dp = BlueDataUtility.build_dp_inc(_table, myLastValue as DataPacket);
myFireEvent(dp);
}
}
}
public class MSecondStream : TimeUnitStream {
public MSecondStream(int intervalInms, int size)
: base(DateTime.Now, new TimeSpan(0, 0, 0, 0, intervalInms), size, ViewStreamDatabase.instance) { }
protected override DateTime myRoundTime(DateTime dt) { return dt; }
}
public class DisplayableMillisecondStream : ViewStream, IStreamMapper {
private IBlueTableSchema mySchema = new BlueTableSchema("ms",
new ColumnInfo("id", 0, typeof(int)),
new ColumnInfo("time", 1, typeof(string)));
public DisplayableMillisecondStream(int intervalInMs, int sz) {
mySetRealSource(new MapStream(new MSecondStream(intervalInMs, sz), this));
}
#region IStreamMapper Members
public IBlueTableSchema getOutputSchema(IBlueTableSchema inputSchema) {
return mySchema;
}
#endregion
#region IDynamicStreamMapper Members
public IBlueRow map(IBlueRow row) {
DateTime time = row.get_datetime("time");
var time_txt = time.ToString("yyyy-MM-dd HH:mm:ss.fff");
return new BlueRow(mySchema, row["id"], time_txt);
}
#endregion
private string myToString(DateTime dt) {
string sep = ":";
return dt.Hour + sep + dt.Minute + sep + dt.Second + sep + dt.Millisecond;
}
}
}
@@ -0,0 +1,127 @@
namespace bts.BlueOrb {
using BCG;
using System;
using System.Collections.Generic;
using System.Linq;
//using MathNet.Numerics.Statistics;
public enum MultiRowOp {
Mean,
Median,
Mode,
Range,
StdDev,
Max,
Min,
First,
Last,
Sum,
EdgeDiff,
EdgeDiffPercentage,
//IsEdgeDiff,
}
public class MultiRowOpHelper {
public readonly List<Tuple<string, MultiRowOp>> operations;
public static MultiRowOpHelper parse_ops(string text) {
// text is inp_col: op, inp_col: op, inp_col:op
List<Tuple<string, MultiRowOp>> rv = new List<Tuple<string, MultiRowOp>>();
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();
MultiRowOp op = Enum.Parse<MultiRowOp>(op_txt, true);
rv.Add(Tuple.Create(inp_col, op));
}
return new MultiRowOpHelper(rv);
}
public MultiRowOpHelper(List<Tuple<string, MultiRowOp>> operations_) {
operations = operations_;
}
// aggregates multiple rows into one - ie does group_by compute
public static IBlueRow group_by_compute(List<IBlueRow> rows, MultiRowOpHelper 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, MultiRowOp>> out_col_map =
new Dictionary<string, Tuple<string, MultiRowOp>>();
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;
MultiRowOp 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;
}
// rolling_rows are the rolling window of rows. the 0th row is the one thats gettin
// calculated. rows 1 - n-1 are its window rows. the schema is based on the operations.
public IBlueRow rolling_calc(List<IBlueRow> rolling_rows) {
if (rolling_rows.Count() == 0) {
return null;
}
IBlueRow ir = rolling_rows.ElementAt(0);
IBlueTableSchema in_schema = ir.schema;
IBlueTableSchema out_schema = in_schema;
IDictionary<string, Tuple<string, MultiRowOp>> out_col_map =
new Dictionary<string, Tuple<string, MultiRowOp>>();
foreach (var t in 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;
MultiRowOp op = kv.Value.Item2;
IEnumerable<double> col_vals = BlueDataUtility.get_colvalues<double>(rolling_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, MultiRowOp op) {
switch (op) {
case MultiRowOp.Max:
return col_vals.Max<double>();
case MultiRowOp.Min:
return col_vals.Min<double>();
case MultiRowOp.Mean:
return col_vals.Sum() / col_vals.Count();
case MultiRowOp.Sum:
return col_vals.Sum();
case MultiRowOp.First:
return col_vals.First();
case MultiRowOp.Last:
return col_vals.Last();
case MultiRowOp.StdDev:
return MathNet.Numerics.Statistics.Statistics.StandardDeviation(col_vals);
default:
// TODO
Log.assert(false);
return Double.NaN;
}
}
}
}
@@ -0,0 +1,207 @@
namespace bts.BlueOrb {
using BCG;
using ProtoBuf;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
#region mappings
internal class ProjectData {
// schema from the base stream
public readonly IBlueTableSchema in_schema;
// this is the projected schema
public readonly IBlueTableSchema out_schema;
// projected cols to the input cols, for cols who's names are changed
public readonly IDictionary<string, string> mapped_to_orig_col_map = new Dictionary<string, string>();
public ProjectData(IBlueTableSchema in_schema_, IBlueTableSchema out_schema_,
IDictionary<string, string> mapped_to_orig_col_map_) {
in_schema = in_schema_;
out_schema = out_schema_;
mapped_to_orig_col_map = mapped_to_orig_col_map_;
}
}
#endregion
#region Row with mapipings build in
internal class NewProjectRow : IBlueRow {
#region IBlueRow members
private ProjectData _project_data;
private IBlueRow _row;
public NewProjectRow(ProjectData project_data, IBlueRow row) {
_project_data = project_data;
_row = row;
}
public IBlueTableSchema schema { get { return _project_data.out_schema; } }
#endregion
#region ICollection members
public int Count { get { return schema.columnNames.Length; } }
public bool IsSynchronized { get { return false; } }
public object SyncRoot { get { return this; } }
public void CopyTo(Array array, int index) {
int i = index;
foreach (object o in this as IEnumerable)
array.SetValue(o, i++);
}
#endregion
#region IDictionary members
public bool IsFixedSize { get { return true; } }
public bool IsReadOnly { get { return true; } }
public object this[object key] {
get {
if (key is string)
return this[(string)key];
return this[(int)key];
}
set { throw new NotSupportedException("The IBlueRow is readonly"); }
}
public object this[int index] {
get {
return this[schema.columnInfo[index].colName];
}
}
public object this[string col_name] {
get {
string mapped_to_col = null;
if (_project_data.mapped_to_orig_col_map.TryGetValue(col_name, out mapped_to_col)) {
return _row[mapped_to_col];
}
return _row[col_name];
}
}
public ICollection Keys { get { return schema.columnNames; } }
public ICollection Values {
get {
object[] retVal = new object[schema.columnNames.Length];
CopyTo(retVal, 0);
return retVal;
}
}
public void Add(object key, object value) { throw new NotSupportedException("The IBlueRow is readonly"); }
public void Clear() { throw new NotSupportedException("The IBlueRow is readonly"); }
public bool Contains(object key) { return schema[(string)key] != null; }
/// <summary>
/// Note, the default enumerator is the IDictionary's enumerator, so if user needs to
/// iterate through the values, typecast this into an IEnumerable
/// </summary>
/// <returns></returns>
public IDictionaryEnumerator GetEnumerator() { return new BlueRowDictionaryEnumerator(this); }
IEnumerator IEnumerable.GetEnumerator() { return new BlueRowEnumerator(this); }
public void Remove(object key) { throw new NotSupportedException("The IBlueRow is readonly"); }
#endregion
}
#endregion
[DataStreamUserRespresentation("ProjectStream")]
public class NewProjectStream : ViewStream, IStreamMapper {
private ViewStream _stream;
private string _project_expression;
private ProjectData _project_data = null;
//public ProjectData
public NewProjectStream(ViewStream vs, string project_expression) {
_stream = vs;
_project_expression = project_expression;
_stream = new MapStream(vs, this);
mySetRealSource(_stream);
}
public IBlueTableSchema getOutputSchema(IBlueTableSchema input_schema) {
_project_data = _create_project_data(input_schema, _project_expression);
return _project_data.out_schema;
}
public IBlueRow map(IBlueRow row) {
return new NewProjectRow(_project_data, row);
}
private static ProjectData _create_project_data(IBlueTableSchema input_schema,
string project_expression) {
project_expression = project_expression.Trim();
string[] project_toks = project_expression.Split(' ');
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 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);
}
} else if (p_tok.Contains(":")) {
string[] map_toks = p_tok.Split(":");
string orig_col = map_toks[0];
string mapped_col = map_toks[1];
mapped_to_orig_map.Add(mapped_col, orig_col);
orig_to_mapped.Add(orig_col, mapped_col);
} else {
if (input_schema.columnNames.Contains(p_tok)) {
string orig_col = p_tok;
string mapped_col = orig_col;
orig_to_mapped.Add(orig_col, mapped_col);
}
}
}
// make the new schema
List<ColumnInfo> new_cols = new List<ColumnInfo>();
foreach (ColumnInfo ci in input_schema.columnInfo) {
if (ci.colName == "id") {
ColumnInfo nc = new ColumnInfo(ci.colName, new_cols.Count, ci.colType);
new_cols.Add(nc);
continue;
}
if (removed_cols.Contains(ci.colName)) {
continue;
} else if (orig_to_mapped.ContainsKey(ci.colName)) {
string mapped_name = orig_to_mapped[ci.colName];
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);
//}
}
}
IBlueTableSchema new_schema = new BlueTableSchema(input_schema.tableName, new_cols.ToArray());
return new ProjectData(input_schema, new_schema, mapped_to_orig_map);
}
}
}
@@ -0,0 +1,30 @@
using BCG;
namespace bts.BlueOrb {
public class SchemaGuesserStream : ViewStream {
private IBlueRowCollection _rows = null;
private ViewStream _vs;
public SchemaGuesserStream(ViewStream vs) {
_vs = vs;
}
protected override void myOnFirstSubscriber() {
_vs.onChange += _on_data;
}
protected override void myOnLastSubscriber() {
_vs.onChange -= _on_data;
}
private void _on_data(object obj) {
DataPacket dp = obj as DataPacket;
if (_rows == null) {
_rows = BlueDataUtility.get_typed_table(dp.newRows);
}
var dp_out = BlueDataUtility.build_dp_inc(_rows, myLastValue as DataPacket);
myFireEvent(dp_out);
}
}
}
@@ -0,0 +1,67 @@
using Bts.ArithmeticExpressions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BCG;
namespace bts.BlueOrb {
[DataStreamUserRespresentation("SingleRowMathStream")]
public class MathStream : ViewStream, IStreamMapper {
private IArithmeticProgram myExp;
private BooleanExpressionFilter _bool;
List<string> myExtraColumns = new List<string>();
BlueTableSchema mySchema;
public MathStream(ViewStream vs, string mathExpression)
: this(vs, mathExpression, string.Empty) {
}
public MathStream(ViewStream vs, string mathExpression, string boolean_expression) {
myExp = ArithmeticProgramParser.Parse(mathExpression) ??
throw new Exception($"Failed to parse ArithmeticExpression '{mathExpression}'");
myExtraColumns = myExp.OutputIdentifiers.ToList();
if (!string.IsNullOrEmpty(boolean_expression))
_bool = new BooleanExpressionFilter(boolean_expression);
mySetRealSource(new MapStream(vs, this));
}
#region IStreamMapper Members
public IBlueTableSchema getOutputSchema(IBlueTableSchema inputSchema) {
if (mySchema == null) {
Dictionary<string, ColumnInfo> colIdx = new Dictionary<string, ColumnInfo>();
foreach (ColumnInfo ci in inputSchema.columnInfo)
colIdx[ci.colName] = ci;
foreach (string ncn in myExtraColumns) {
ColumnInfo newC;
if (colIdx.ContainsKey(ncn))
newC = new ColumnInfo(colIdx[ncn].colName, colIdx[ncn].colNo, typeof(double));
else
newC = new ColumnInfo(ncn, colIdx.Count, typeof(double));
colIdx[ncn] = newC;
}
mySchema = new BlueTableSchema(colIdx.Values.ToArray(), "math(" + inputSchema.tableName + ")");
}
return mySchema;
}
#endregion
#region IDynamicStreamMapper Members
public IBlueRow map(IBlueRow row) {
MutableBlueRow result = new MutableBlueRow(mySchema, row);
if (_bool == null || _bool.filter(row)) {
myExp.Evaluate(result.AsDictionary());
}
return result;
}
#endregion
}
}
@@ -0,0 +1,11 @@
namespace bts.BlueOrb {
using BCG;
[DataStreamUserRespresentation("TopStream")]
public class TopStream : ViewStream {
public TopStream(ViewStream vs, int n_rows, string sort_col) {
ViewStream rs = new BCG.TopStream (vs, n_rows, sort_col);
mySetRealSource(rs);
}
}
}
@@ -0,0 +1,261 @@
using System;
using System.Collections.Generic;
using mbts;
using BCG;
namespace bts.BlueOrb {
internal class MutableAppendTable : IBlueRowCollection {
private class MyRow : IBlueRow {
private IBlueRow myRow;
private int myID;
public MyRow(IBlueRow r, int id) {
myRow = r;
myID = id;
}
#region IBlueRow Members
public IBlueTableSchema schema { get { return myRow.schema; } }
public object this[int index] {
get {
if (myRow.schema[index].colName == "id")
return myID;
else
return myRow[index];
}
}
public object this[string colName] { get { return colName == "id" ? (object)myID : myRow[colName]; } }
#endregion
#region IDictionary Members
public void Add(object key, object value) { throw new Exception("Row is read only."); }
public void Clear() { throw new Exception("Row is read only."); }
public bool Contains(object key) { return myRow.Contains(key); }
public System.Collections.IDictionaryEnumerator GetEnumerator() { return new BlueRowDictionaryEnumerator(this); }
public bool IsFixedSize { get { return true; } }
public bool IsReadOnly { get { return true; } }
public System.Collections.ICollection Keys { get { return myRow.Keys; } }
public void Remove(object key) { throw new Exception("The method or operation is not implemented."); }
public System.Collections.ICollection Values {
get {
object[] vals = new object[myRow.Count];
CopyTo(vals, 0);
return vals;
}
}
public object this[object key] {
get { return key is string ? this[key as string] : this[(int)key]; }
set { throw new Exception("The method or operation is not implemented."); }
}
#endregion
#region ICollection Members
public void CopyTo(Array array, int index) {
myRow.CopyTo(array, index);
array.SetValue(myID, index + myRow.schema["id"].colNo);
}
public int Count { get { return myRow.Count; } }
public bool IsSynchronized { get { return myRow.IsSynchronized; } }
public object SyncRoot { get { return myRow.SyncRoot; } }
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new BlueRowEnumerator(this); }
#endregion
}
private BlueTable myRows;
private int myID = 0;
/// <summary>
/// maps the table no to a dictionary containing the
/// local IDs to a row in the final big table
/// </summary>
private Dictionary<int, Dictionary<int, IBlueRow>> myIDMap = new Dictionary<int, Dictionary<int, IBlueRow>>();
public MutableAppendTable(IBlueTableSchema schema) { myRows = new BlueTable(schema); }
public IBlueRow addRow(IBlueRow r, int tableNo) {
if (!myIDMap.ContainsKey(tableNo))
myIDMap.Add(tableNo, new Dictionary<int, IBlueRow>());
IBlueRow nr = new MyRow(r, myID++); // BlueDataUtility.getNewReplacedRow(r, myID++, "id");
myRows.addRow(nr);
myIDMap[tableNo].Add((int)r["id"], nr);
return nr;
}
public IBlueRow removeRow(IBlueRow r, int tableNo) {
IBlueRow dr = myIDMap[tableNo][(int)r["id"]];
myRows.deleteRow(dr);
myIDMap[tableNo].Remove((int)r["id"]);
return dr;
}
public IBlueRowCollection removeTable(int tableNo) {
if (!myIDMap.ContainsKey(tableNo))
return null;
else {
BlueTable rv = new BlueTable(myRows.schema);
foreach (IBlueRow r in myIDMap[tableNo].Values)
rv.addRow(r);
myRows.deleteRows(rv);
myIDMap.Remove(tableNo);
return rv;
}
}
public void clear() {
myRows.clear();
myIDMap.Clear();
}
#region IBlueRowCollection Members
public IBlueRow this[int id] { get { return myRows[id]; } }
public IBlueTableSchema schema { get { return myRows.schema; } }
public bool containsID(int id) { return myRows.containsID(id); }
#endregion
#region ICollection Members
public void CopyTo(Array array, int index) { myRows.CopyTo(array, index); }
public int Count { get { return myRows.Count; } }
public bool IsSynchronized { get { return myRows.IsSynchronized; } }
public object SyncRoot { get { return myRows.SyncRoot; } }
#endregion
#region IEnumerable Members
public System.Collections.IEnumerator GetEnumerator() { return myRows.GetEnumerator(); }
#endregion
}
/// <summary>
/// MutableStream can append multiple streams
/// as well as give the user the flexibility
/// to append (or remove) more streams at
/// runtime
/// </summary>
}
namespace bts.BlueOrb {
[DataStreamUserRespresentation("UnionStream")]
public class MutableAppendStream : ViewStream {
private bool mySubscriptionActive = false;
private MutableAppendTable myTable;
private int myMovingIndex;
private Dictionary<int, Pair<ViewStream, ViewStream>> myStreamIndex = new Dictionary<int, Pair<ViewStream, ViewStream>>();
private bool _allign_col_orders = true;
public MutableAppendStream(params ViewStream[] streams)
: this(new List<ViewStream>(streams)) { }
public MutableAppendStream(bool allign_col_order, params ViewStream[] streams)
: this(allign_col_order, new List<ViewStream>(streams)) { }
public MutableAppendStream(ICollection<ViewStream> streams)
: this(true, streams) { }
public MutableAppendStream(bool allign_col_orders, ICollection<ViewStream> streams) {
_allign_col_orders = allign_col_orders;
foreach (ViewStream vs in streams) {
myMovingIndex++;
ViewStream pj = new ChangeTableNameStream(vs, myMovingIndex.ToString());
if (_allign_col_orders)
pj = new ProjectStream(pj, "!");
myStreamIndex.Add(myMovingIndex, new Pair<ViewStream, ViewStream>(vs, pj));
}
}
public void addStream(ViewStream vs) {
myMovingIndex++;
///the change name is done to identify the callbacks, and the project to
///make all the schemas col orders the same
ViewStream pj = new ChangeTableNameStream(vs, myMovingIndex.ToString());
if (_allign_col_orders)
pj = new ProjectStream(pj, "!");
myStreamIndex.Add(myMovingIndex, new Pair<ViewStream, ViewStream>(vs, pj));
if (mySubscriptionActive)
pj.onChange += new ChangeDelegate(myHandleStreamChanges);
}
public void removeStream(ViewStream vs) {
int index = -1;
foreach (KeyValuePair<int, Pair<ViewStream, ViewStream>> p in myStreamIndex) {
if (p.Value.first == vs) {
index = p.Key;
if (mySubscriptionActive) {
p.Value.second.onChange -= new ChangeDelegate(myHandleStreamChanges);
if (myTable != null) {
IBlueRowCollection delRows = myTable.removeTable(p.Key);
if (delRows != null)
myFireEvent(new DataPacket(myTable, new BlueTable(myTable.schema), delRows));
}
}
break;
}
if (index > 0)
myStreamIndex.Remove(index);
}
}
protected override void myOnFirstSubscriber() {
mySubscriptionActive = true;
foreach (KeyValuePair<int, Pair<ViewStream, ViewStream>> p in myStreamIndex)
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 -= new ChangeDelegate(myHandleStreamChanges);
if (myTable != null)
myTable.clear();
}
private void myHandleStreamChanges(object newValue) {
DataPacket dp = newValue as DataPacket;
myTable = myTable ?? new MutableAppendTable(new BlueTableSchema("MutableAppend", dp.schema.columnInfo));
BlueTable adds = new BlueTable(myTable.schema),
dels = new BlueTable(myTable.schema);
int index = Int32.Parse(dp.schema.tableName);
foreach (IBlueRow r in dp.deletedRows) {
IBlueRow dr = myTable.removeRow(r, index);
dels.addRow(dr);
}
foreach (IBlueRow r in dp.addedRows) {
IBlueRow nr = myTable.addRow(r, index);
adds.addRow(nr);
}
myFireEvent(new DataPacket(myTable, adds, dels));
}
}
}
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
@@ -9,14 +9,22 @@
<ProjectReference Include="..\ArithmeticExpressions\ArithmeticExpressions.csproj" />
<ProjectReference Include="..\BaseUtilities\BaseUtilities.csproj" />
<ProjectReference Include="..\BooleanExpressions\BooleanExpressions.csproj" />
<ProjectReference Include="..\Bts.ColumnExpressions\Bts.ColumnExpressions.csproj" />
<ProjectReference Include="..\Bts.ColumnSortExpressions\Bts.ColumnSortExpressions.csproj" />
<ProjectReference Include="..\DataStreamCore\DataStreamCore.csproj" />
<ProjectReference Include="..\DataStreamExpressions\DataStreamExpressions.csproj" />
<ProjectReference Include="..\..\client\spark_core\spark_core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.57" />
<PackageReference Include="IronPython" Version="3.4.2" />
<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" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,26 @@
namespace Bts.DataStream;
using BCG;
using Spark.Core.Disposables;
using System;
using System.Reactive.Linq;
public static class DataStreamExtensions {
public static ViewStream AsViewStream(this IObservable<DataPacket> source) =>
source as ViewStream ?? new ObservableViewStream(source);
public static IObservable<DataPacket> AsObservable(this ViewStream source) {
return source as IObservable<DataPacket> ?? Observable.Create<DataPacket>(Subscribe);
IDisposable Subscribe(IObserver<DataPacket> observer) {
source.onChange += OnChange;
return Disposable.Create(() => source.onChange -= OnChange);
void OnChange(object? newValue) =>
observer.OnNext(newValue as DataPacket ?? throw new ArgumentException(
$"Expected DataPacket, got {newValue?.GetType()}", nameof(newValue)));
}
}
}
@@ -0,0 +1,32 @@
namespace bts.SilverPine {
using System;
using BCG;
using System.Collections.Generic;
using Bts.DataStreamExpressions;
// 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) {
Log.Gen.info($"DSLStream.cons dsl: {dsl}");
_dsl = dsl;
ViewStream rs = build_stream(dsl);
rs = rs ?? new LiteralStream("error", $"msg:invalid dsl \"{dsl}\"");
mySetRealSource(rs);
}
static ViewStream? build_stream(string stream_expression) {
try {
var exp = DataStreamExpressionsInterpreter.Evaluate(stream_expression);
var rv = exp.getView(new Dictionary<string, StatementExpression>(0));
return rv;
} catch (Exception ex) {
Log.Gen.error($"Could not build stream: {stream_expression} ex: {ex}");
return null;
}
}
}
}
@@ -0,0 +1,29 @@
namespace Bts.DataStream;
using BCG;
using bts;
using System;
using System.IO;
public class PandasScriptStream : ViewStream {
public PandasScriptStream(ViewStream vs, string file)
: this(vs, file, null) { }
public PandasScriptStream(ViewStream vs, string file, string? pythonExe)
: this(vs, file, pythonExe, ViewStreamDatabase.instance) { }
public PandasScriptStream(ViewStream vs, string file, string? pythonExe, ViewStreamDatabase vsd) {
mySetRealSource(new PandasStream(vs, readFile(), pythonExe, vsd));
string readFile() {
try {
return File.ReadAllText(file);
} catch (Exception ex) {
Log.Gen.error($"PandasScriptStream error reading file: {ex}");
throw;
}
}
}
}
@@ -0,0 +1,130 @@
namespace Bts.DataStream;
using BCG;
using BCG.Extensions;
using BCG.Utilities.General;
using bts;
using bts.collections;
using Bts.DataStreamCore;
using Spark.Core.Disposables;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
public class PandasStream : ViewStream, IWorker {
readonly string inputFile = $"PandasStream_{Guid.NewGuid()}.csv";
readonly string outputFile = $"PandasStream_{Guid.NewGuid()}.csv";
readonly string pythonExe;
readonly ViewStreamDatabase vsd;
readonly CSVSaverStream inputCsvStream;
readonly Lazy<string> pythonCode;
IDictionary<int, IBlueRow>? lastRowMap = null;
int inputVersion = 0;
int outputVersion = 0;
DateTime lastFireTime = DateTime.MinValue;
TimeSpan fireThrottle = TimeSpan.FromSeconds(3);
IDisposable? dispose;
public PandasStream(ViewStream vs, string dataFrameExpression)
: this(vs, dataFrameExpression, null, ViewStreamDatabase.instance) { }
public PandasStream(ViewStream vs, string dataFrameExpression, string? pythonExe, ViewStreamDatabase vsd) {
pythonExe ??= Environment.GetEnvironmentVariable("PYTHON_EXE") ?? @"C:\Users\johnc\GoogleDrive\Repos\bts\spark\.venv\Scripts\python.exe";
this.pythonExe = pythonExe;
this.vsd = vsd;
// This should fire an update when it writes to the output file
inputCsvStream = new CSVSaverStream(vs, inputFile, true, int.MaxValue, true);
pythonCode = new(getPythonCode);
string getPythonCode() {
var imports =
@"import numpy as np
import pandas as pd
import sys
";
var bd = new StringBuilder(imports);
bd.AppendLine($"df=pd.read_csv('{inputFile}')");
bd.AppendLine(dataFrameExpression);
bd.AppendLine($"df.to_csv('{outputFile}', index=False)");
return bd.ToString();
}
}
protected override void myOnFirstSubscriber() {
vsd.addWorker(this);
inputCsvStream.onChange += onInputChanged;
this.dispose = Disposable.Create(dispose);
void onInputChanged(object newValue) =>
inputVersion++;
void dispose() {
inputCsvStream.onChange -= onInputChanged;
vsd.removeWorker(this);
deleteFile(inputFile);
deleteFile(outputFile);
}
void deleteFile(string file, [CallerArgumentExpression(nameof(file))] string name = "") {
if (!File.Exists(file)) {
return;
}
try {
File.Delete(file);
} catch (Exception ex) {
Log.Gen.error($"PandasStream. Error deleting {name} file '{file}': {ex}");
}
}
}
protected override void myOnLastSubscriber() =>
Disposable.dispose(ref dispose);
static void executePythonCode(string pythonCode, string? pythonExe = null) {
pythonExe ??= "python";
var start = new ProcessStartInfo {
FileName = pythonExe,
Arguments = "-c \"" + pythonCode.Replace("\"", "\\\"") + "\"",
UseShellExecute = false,
RedirectStandardOutput = true
};
using var process = Process.Start(start)
?? throw new InvalidOperationException("Failed to launch python");
process.WaitForExit();
}
void IWorker.doWork() {
if (outputVersion == inputVersion) {
return;
}
var now = DateTime.Now;
var elapsedSinceLastFire = now - lastFireTime;
if (elapsedSinceLastFire < fireThrottle) {
return;
}
outputVersion = inputVersion;
executePythonCode(pythonCode.Value, pythonExe);
var rows = BlueDataUtility.createRowsFromCSVFileWithoutTypes(outputFile, out var schema);
var rowMap = rows as IDictionary<int, IBlueRow> ?? rows.Cast<IBlueRow>().ToDictionary(r => r.Id());
var comp = BlueRowEqualityComparer.Instance;
var deletedRows = new BlueTable(schema);
var addedRows = new BlueTable(schema);
if (lastRowMap is not null) {
deletedRows.SetItems(lastRowMap.Where(oldRow =>
!(rowMap.TryGetValue(oldRow.Key, out var newRow) && comp.Equals(newRow, oldRow.Value))));
addedRows.SetItems(rowMap.Where(newRow =>
!(lastRowMap.TryGetValue(newRow.Key, out var oldRow) && comp.Equals(oldRow, newRow.Value))));
}
lastRowMap = rowMap;
lastFireTime = DateTime.Now;
myFireEvent(new DataPacket(rows, addedRows, deletedRows));
}
}
@@ -0,0 +1,79 @@
using BCG.Utilities.General;
using System;
namespace BCG {
public class TCPConnectionTestStream : ViewStream, IWorker, ITCPConnectionHandler, ITCPMessageHandler {
class State {
public int n_sends = 0;
public int n_recvs = 0;
}
private readonly string _ip;
private readonly int _port;
private readonly ViewStreamDatabase _vsd;
State _state = new State();
private readonly int _msg_size;
private IBlueTableSchema _schema;
private TimeSpan _send_period;
private ITCPConnection _connection = null;
private byte[] _buff;
public TCPConnectionTestStream(string ip, int port, int msg_size, int send_period_seconds) :
this(ip, port, msg_size, send_period_seconds, ViewStreamDatabase.instance) { }
public TCPConnectionTestStream(string ip, int port, int msg_size, int send_period_seconds, ViewStreamDatabase vsd) {
_ip = ip;
_port = port;
_msg_size = msg_size;
_vsd = vsd;
_schema = BlueDataUtility.form_schema("TCPClient",
Tuple.Create("id", TypeCode.Int32),
Tuple.Create("n_sends", TypeCode.UInt32),
Tuple.Create("n_recvs", TypeCode.UInt32));
_send_period = TimeSpan.FromSeconds(send_period_seconds);
_buff = new byte[msg_size];
for (int i = 0; i < _buff.Length; i++) {
_buff[i] = (byte)i;
}
}
protected override void myOnFirstSubscriber() {
MasterWorker.getInstance(false).addWorker(this, _send_period);
var server_rci = new RemoteConnectionInfo(_ip, _port);
bts.AsyncTCPConnector_APM.connect_to(server_rci, this);
}
protected override void myOnLastSubscriber() {
MasterWorker.getInstance(false).removeWorker(this);
}
public void doWork() {
if (_connection != null) {
_connection.send(_buff);
_state.n_sends++;
}
IBlueRow r = new BlueRow(_schema, 0, _state.n_sends, _state.n_recvs);
BlueTable rows = new BlueTable(r.schema);
rows.addRow(r);
var dp = BlueDataUtility.build_dp_inc(rows, myLastValue as DataPacket, true);
myFireEvent(dp);
}
public void onConnection(ITCPConnection connection) {
_connection = connection;
_connection.register(this);
}
public bool isDisposed { get; }
public void onData(RemoteMessage msg) {
bts.Log.Gen.info($"TCPConnectionTestStream received msg: {msg}");
_state.n_recvs++;
}
public void Dispose() {
}
}
}
@@ -0,0 +1,3 @@
file_path = r"C:\Temp\test2.txt" # r prefix for raw string to avoid escape characters
with open(file_path, "w") as f:
f.write("Hello, world!\n")
@@ -0,0 +1,37 @@
namespace Bts.DataStream;
using BCG;
using bts;
using System;
public class ObservableViewStream : ViewStream, IObservable<DataPacket>, IDisposable {
readonly IObservable<DataPacket> source;
IDisposable? subscription;
public ObservableViewStream(IObservable<DataPacket> source) =>
this.source = source;
public void Dispose() {
GC.SuppressFinalize(this);
if (subscription is not null) {
subscription.Dispose();
subscription = null;
}
}
protected override void myOnFirstSubscriber() {
Log.isnull(subscription);
subscription = source.Subscribe(myFireEvent);
}
protected override void myOnLastSubscriber() {
Log.notnull(subscription);
subscription.Dispose();
subscription = null;
}
IDisposable IObservable<DataPacket>.Subscribe(IObserver<DataPacket> observer) =>
source.Subscribe(observer);
}
@@ -1,32 +0,0 @@
using BCG;
namespace BCG
{
// this is a stream so we can run it from the DSQA (since dsqa can only load streams)
[DataStreamUserRespresentation("add_to_cloud")]
public class AddToCloudStream : ViewStream
{
private readonly string _name, _stream_exp;
private StreamOffloadRequestor _requestor = new StreamOffloadRequestor();
public AddToCloudStream(string name, params string[] lines)
: this(name, 0, lines)
{
}
public AddToCloudStream(string name, int persist, params string[] lines)
{
_name = name;
_stream_exp = getExpression(lines);
_requestor.add_to_cloud(_name, _stream_exp, persist == 1);
mySetRealSource(new TableStream("cloud_streams"));
}
static string getExpression(params string[] lines) {
for (int i = 0; i < lines.Length; i++) {
// unescape quotes
lines[i] = lines[i].Replace("\\\"", "\"");
}
return string.Join("\n", lines);
}
}
}
@@ -1,31 +1,22 @@
using BCG;
using System;
using System.Collections.Generic;
using mbts.config;
using bts.utils;
using System.Threading.Tasks;
using Bts.DataStreamExpressions;
using System.Collections.Generic;
using BCG.Utilities.General;
using bts;
namespace BCG
{
namespace BCG {
// listens to the requests posted on "cloud_streams" request table, and
// if unfulfilled starts a ViewPubsliher
public class CloudStreamManager : IWorker
{
public class StreamPubUnit
{
public class RemoteQueryManager : IWorker {
public class StreamPubUnit {
public string name;
public string stream_expression;
public ViewStream stream;
public bool persist;
public ViewPublisher view_publisher;
public StreamPubUnit(string name_, string stream_expression_, ViewStream stream_, bool persist_, ViewPublisher view_publisher_)
{
public StreamPubUnit(string name_, string stream_expression_, ViewStream stream_, bool persist_, ViewPublisher view_publisher_) {
name = name_;
stream_expression = stream_expression_;
stream = stream_;
@@ -33,7 +24,7 @@ namespace BCG
view_publisher = view_publisher_;
}
}
static ViewStream build_stream(string stream_expression)
static ViewStream? build_stream(string stream_expression)
{
try
{
@@ -41,9 +32,7 @@ namespace BCG
var rv = exp.getView(new Dictionary<string, StatementExpression>(0));
return rv;
}
catch (Exception ex)
{
} catch (Exception ex) {
bts.Log.assert(false, $"Could not build stream: {stream_expression} ex: {ex}");
return null;
}
@@ -52,34 +41,37 @@ namespace BCG
_stream_pub_map = new Dictionary<string, StreamPubUnit>();
private ViewStream _stream = new TableStream("cloud_streams");
private PubTableBroker _broker = new PubTableBroker();
private ManagedSubscriber _sub = ManagedSubscriber.instance;
public CloudStreamManager()
{
public RemoteQueryManager() {
_stream.onChange += _on_str;
_sub.subscribe("RemoteRequest", (string tag, byte[] data) => {
RemoteRequest req = RemoteRequest.construct_from_bytes(data);
_spawn_remote_stream(req.published_table_name, req.stream_expression, false);
});
}
private void _on_str(object obj)
{
DataPacket dp = obj as DataPacket;
if (obj is not DataPacket dp) {
return;
}
foreach (IBlueRow r in dp.newRows)
{
string name = r.get<string>("name");
bool persist = r.get<bool>("persist");
string stream_exp = r.get<string>("stream_exp");
if (!_stream_pub_map.ContainsKey(name))
{
_assign(name, stream_exp, persist);
if (!_stream_pub_map.ContainsKey(name)) {
_spawn_remote_stream(name, stream_exp, persist);
}
}
}
private void _assign(string name, string stream_expression, bool persist)
{
private void _spawn_remote_stream(string name, string stream_expression, bool persist) {
bts.Log.Gen.info($"CloudStreamManager.assign name: {name} stream_expression: {stream_expression}");
ViewStream stream = build_stream(stream_expression);
_expose_to_ws(name, stream);
if (persist)
{
if (persist) {
stream = new PersistorStream(stream, name, "C:\\Temp\\", 1000000); // 10MBs
}
ViewPublisher view_pub = new ViewPublisher(name, _broker, stream);
@@ -87,14 +79,12 @@ namespace BCG
_stream_pub_map.Add(name, u);
}
private void _expose_to_ws(string name, ViewStream stream)
{
private void _expose_to_ws(string name, ViewStream stream) {
// TODO: john
}
public void doWork()
{
public void doWork() {
}
}
}
}
@@ -0,0 +1,48 @@
using BCG;
using bts;
using System;
namespace BCG {
// this is a stream so we can run it from the DSQA (since dsqa can only load streams)
[DataStreamUserRespresentation("remoteQuery")]
public class RemoteQueryStream : ViewStream {
private readonly string _name, _stream_exp;
private PublisherCore _publisher_core = new PublisherCore();
private ViewStream _source_str;
public RemoteQueryStream(params string[] lines) {
_stream_exp = get_expression(lines);
_name = Guid.NewGuid().ToString();
_name = $"remotereq_{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString()}";
//_name.Replace("-", "_");
}
protected override void myOnFirstSubscriber() {
RemoteRequest rem_req = new RemoteRequest(_stream_exp, _name);
byte[] rem_req_bytes = rem_req.serialize();
_publisher_core.publish("System", "RemoteRequest", rem_req_bytes);
_source_str = new TableStream(_name);
_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 -= new ChangeDelegate(_handle_data);
}
static string get_expression(params string[] lines) {
for (int i = 0; i < lines.Length; i++) {
// unescape quotes
lines[i] = lines[i].Replace("\\\"", "\"");
}
return string.Join("\n", lines);
}
private void _handle_data(object o) {
myFireEvent(o);
}
}
}
@@ -0,0 +1,31 @@
namespace bts {
using System.IO;
using BCG;
using System.IO;
using System.Threading.Tasks.Dataflow;
public class RemoteRequest {
public readonly string stream_expression;
public readonly string published_table_name;
public RemoteRequest(string stream_expression_, string published_table_name_) {
stream_expression = stream_expression_;
published_table_name = published_table_name_;
}
public byte[] serialize() {
var str = new MemoryStream();
var bw = new BinaryWriter(str);
bw.write_string_cpp(stream_expression);
bw.write_string_cpp(published_table_name);
return str.ToArray();
}
public static RemoteRequest construct_from_bytes(byte[] ser_bytes) {
BinaryReader br = new BinaryReader(new MemoryStream(ser_bytes));
string stream_expression_ = br.read_string_cpp();
string published_table_name_ = br.read_string_cpp();
return new RemoteRequest(stream_expression_, published_table_name_);
}
}
}
@@ -1,59 +1,54 @@
using BCG;
// using BCG;
using System.Linq;
// using bts;
namespace BCG
{
public class StreamOffloadRequestor
{
public class OffloadOp
{
string name;
string stream_exp;
}
private IBlueTableSchema _schema;
private IBlueRowCollection _rows;
private PubTableBroker _broker = new PubTableBroker();
ViewStream _existing_offloads_vs = new TableStream("cloud_streams");
public StreamOffloadRequestor()
{
_schema = new BlueTableSchema("cloud_streams",
new ColumnInfo("id", 0, typeof(int)),
new ColumnInfo("name", 1, typeof(string)),
new ColumnInfo("persist", 2, typeof(bool)),
new ColumnInfo("stream_exp", 3, typeof(string)));
_existing_offloads_vs.onChange += _on_str;
}
private void _on_str(object obj)
{
DataPacket dp = obj as DataPacket;
_rows = dp.newRows;
// this is needed so the broker knows the state of the table
_broker.createTable(_rows);
}
public void add_to_cloud(string name, string stream_exp, bool persist)
{
// check if it exists
if (_rows == null)
{
BlueTable table = new BlueTable(_schema);
IBlueRow nr = new BlueRow(_schema, 0, name, persist, stream_exp);
table.addRow(nr);
_broker.createTable(table);
// create table
}
else
{
if (exists(name))
return;
IBlueRow nr = new BlueRow(_schema, _rows.Count, name, persist, stream_exp);
_broker.addRow(nr);
}
}
// using System.Linq;
bool exists(string name)
{
return _rows.to_ienum().Where(r => name == r.get<string>("name")).Count() > 0;
}
}
}
// namespace BCG {
// // used on the client
// public class StreamOffloadRequestor {
// public class OffloadOp {
// string name;
// string stream_exp;
// }
// private IBlueTableSchema _schema;
// private IBlueRowCollection _rows;
// private PubTableBroker _broker = new PubTableBroker();
// ViewStream _existing_offloads_vs = new TableStream("cloud_streams");
// public StreamOffloadRequestor() {
// _schema = new BlueTableSchema("cloud_streams",
// new ColumnInfo("id", 0, typeof(int)),
// new ColumnInfo("name", 1, typeof(string)),
// new ColumnInfo("persist", 2, typeof(bool)),
// new ColumnInfo("stream_exp", 3, typeof(string)));
// _existing_offloads_vs.onChange += _on_str;
// }
// private void _on_str(object obj) {
// DataPacket dp = obj as DataPacket;
// _rows = dp.newRows;
// // this is needed so the broker knows the state of the table
// _broker.create_table(_rows);
// }
// public void add_to_cloud(string name, string stream_exp, bool persist) {
// // check if it exists
// if (_rows == null) {
// BlueTable table = new BlueTable(_schema);
// IBlueRow nr = new BlueRow(_schema, 0, name, persist, stream_exp);
// table.addRow(nr);
// _broker.create_table(table);
// // create table
// } else {
// if (exists(name))
// return;
// IBlueRow nr = new BlueRow(_schema, _rows.Count, name, persist, stream_exp);
// // TODO: use make_batch_changes instead
// Log.assert(false, "Fix addRow");
// //_broker.addRow(nr);
// }
// }
// bool exists(string name) {
// return _rows.to_ienum().Where(r => name == r.get<string>("name")).Count() > 0;
// }
// }
// }
@@ -1,17 +1,14 @@
using System;
using System.Collections;
namespace BCG
{
internal class AddColumnsRow : IBlueRow
{
namespace BCG {
internal class AddColumnsRow : IBlueRow {
private IBlueTableSchema mySchema;
private IBlueRow myRow;
//private object[] myCachedValues;
#region Constructors
public AddColumnsRow (IBlueTableSchema schema, IBlueRow row)
{
public AddColumnsRow(IBlueTableSchema schema, IBlueRow row) {
mySchema = schema;
myRow = row;
//myCachedValues = new object[schema.columnNames.Length];
@@ -19,85 +16,78 @@ namespace BCG
#endregion
#region IBlueRow members
public IBlueTableSchema schema{get{return mySchema;}}
public IBlueTableSchema schema { get { return mySchema; } }
#endregion
#region ICollection members
public int Count {get{return mySchema.columnNames.Length;}}
public int Count { get { return mySchema.columnNames.Length; } }
public bool IsSynchronized {get{return false;}}
public bool IsSynchronized { get { return false; } }
public object SyncRoot {get{return this;}}
public object SyncRoot { get { return this; } }
public void CopyTo (Array array, int index)
{
public void CopyTo(Array array, int index) {
int i = index;
foreach (object o in this as IEnumerable)
array.SetValue (o, i++);
array.SetValue(o, i++);
}
#endregion
#region IDictionary members
public bool IsFixedSize {get{return true;}}
public bool IsFixedSize { get { return true; } }
public bool IsReadOnly {get{return true;}}
public bool IsReadOnly { get { return true; } }
/// <summary>
/// The key can either be the string corrsponding to the column name or
/// the order of the column
/// </summary>
public object this [object key]
{
get
{
public object this[object key] {
get {
if (key is string)
return this[(string)key];
return this[(int)key];
}
set {throw new NotSupportedException ("The IBlueRow is readonly");}
set { throw new NotSupportedException("The IBlueRow is readonly"); }
}
public object this[int index]
{
get
{
public object this[int index] {
get {
//if (myCachedValues[index] == null)
// myCachedValues[index] = mySchema[index].isConstant ? mySchema[index].colValue : myRow[index];
//return myCachedValues[index];
return mySchema[index].isConstant ? mySchema[index].colValue : myRow[index];
return mySchema[index].isConstant ? DBNull.Value : myRow[index];
}
}
public object this[string colName] {get{return this[mySchema[colName].colNo];}}
public object this[string colName] { get { return this[mySchema[colName].colNo]; } }
public ICollection Keys{get{return mySchema.columnNames;}}
public ICollection Keys { get { return mySchema.columnNames; } }
public ICollection Values
{
get
{
public ICollection Values {
get {
object[] retVal = new object[mySchema.columnNames.Length];
CopyTo (retVal, 0);
CopyTo(retVal, 0);
return retVal;
}
}
public void Add (object key, object value) {throw new NotSupportedException ("The IBlueRow is readonly");}
public void Add(object key, object value) { throw new NotSupportedException("The IBlueRow is readonly"); }
public void Clear () {throw new NotSupportedException ("The IBlueRow is readonly");}
public void Clear() { throw new NotSupportedException("The IBlueRow is readonly"); }
public bool Contains (object key){return mySchema[(string)key] != null;}
public bool Contains(object key) { return mySchema[(string)key] != null; }
/// <summary>
/// Note, the default enumerator is the IDictionary's enumerator, so if user needs to
/// iterate through the values, typecast this into an IEnumerable
/// </summary>
/// <returns></returns>
public IDictionaryEnumerator GetEnumerator() {return new BlueRowDictionaryEnumerator(this);}
IEnumerator IEnumerable.GetEnumerator () {return new BlueRowEnumerator(this);}
public IDictionaryEnumerator GetEnumerator() { return new BlueRowDictionaryEnumerator(this); }
public void Remove (object key) {throw new NotSupportedException ("The IBlueRow is readonly");}
IEnumerator IEnumerable.GetEnumerator() { return new BlueRowEnumerator(this); }
public void Remove(object key) { throw new NotSupportedException("The IBlueRow is readonly"); }
#endregion
}
@@ -1,11 +1,34 @@
// using System;
// using System.Data;
// using System.Collections;
// using BCG.Utilities;
// using BCG.Utilities.General;
// namespace BCG {
using System;
// public class AddColumnsStream : MapStream {
// public AddColumnsStream(ViewStream vs, string columnDef) : base(vs, new ColumnAdder(columnDef)) { }
// }
// }
namespace BCG {
public class AddColumnsStream : ViewStream {
public static Tuple<string, Type, object> parse_exp(string exp) {
string[] toks = exp.Split(':');
string col_name = toks[0];
string col_value = toks[1];
Tuple<Type, object> tup = BlueDataUtility.guess_type(col_value);
return Tuple.Create(col_name, tup.Item1, tup.Item2);
}
private Tuple<string, Type, object> _new_col;
private IBlueTableSchema _out_schema;
public AddColumnsStream(ViewStream vs, string col_def) {
_new_col = parse_exp(col_def);
ViewStream rs = new MapStream(vs, (IBlueTableSchema s) => _get_schema(s), (IBlueRow r) => _map(r));
mySetRealSource(rs);
}
private IBlueTableSchema _get_schema(IBlueTableSchema input_schema) {
if (_out_schema == null)
_out_schema = BlueDataUtility.add_column(input_schema, _new_col.Item1, _new_col.Item2);
return _out_schema;
}
private IBlueRow _map(IBlueRow r) {
MutableBlueRow rv = new MutableBlueRow(_get_schema(r.schema), r);
rv.setValue(_new_col.Item1, _new_col.Item3);
return rv;
}
}
}
@@ -0,0 +1,12 @@
namespace bts {
using BCG;
using System;
using System.Collections;
public class AddConstantColumnRow {
AddConstantColumnRow(IBlueRow r, Tuple<string, Type, object>[] constant_cols) {
}
}
}
@@ -1,63 +1,52 @@
// using System;
// using System.Collections;
// using BCG.Utilities;
// using BCG.Evaluator.AddColumnsExpression;
// namespace BCG {
// /// <summary>
// /// Provides methods to add columns to the schema
// /// </summary>
// public class ColumnAdder : IStreamMapper {
// protected IDictionary myNewColumns;
// protected IBlueTableSchema mySchema;
// static syntax myParser =
// new syntax();
// /// <summary>
// /// string represting the columns to be added to the output table.
// /// </summary>
// /// <param name="colAddExpression"></param>
// public ColumnAdder(string columnDef) {
// AddColumnsExpression ace;
// if (DataStreamLoadFileConfig.instance.useStaticParser) {
// lock (myParser) {
// ace =
// (AddColumnsExpression)myParser.Parse(columnDef);
// }
// } else {
// syntax parser = new syntax();
// ace =
// (AddColumnsExpression)parser.Parse(columnDef);
// }
// if (ace == null)
// throw new Exception("Invalid columnn expression: " + columnDef);
// myNewColumns = ace.columns;
// }
// public virtual IBlueRow map(IBlueRow row) {
// if (mySchema == null)
// myConstructSchema(row.schema);
// return new AddColumnsRow(mySchema, row);
// }
// public IBlueTableSchema getOutputSchema(IBlueTableSchema inputSchema) {
// myConstructSchema(inputSchema);
// return mySchema;
// }
// private void myConstructSchema(IBlueTableSchema schema) {
// ColumnInfo[] cis = new ColumnInfo[schema.columnNames.Length + myNewColumns.Count];
// int ciIndex = 0;
// foreach (ColumnInfo ci in schema.columnInfo)
// cis[ciIndex++] = ci;
// foreach (DictionaryEntry de in myNewColumns)
// cis[ciIndex] = new ColumnInfo((string)de.Key, ciIndex++,
// ((AddColumnsExpression.ConstantInfo)de.Value).t, ((AddColumnsExpression.ConstantInfo)de.Value).v);
// mySchema = new BlueTableSchema(cis, schema.tableName);
// }
// }
// }
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Bts.ColumnExpressions;
namespace BCG;
/// <summary>
/// Provides methods to add columns to the schema
/// </summary>
/// <param name="columnsExpression">
/// String represting the columns to add to the output table
/// </param>
public class ColumnAdder : IStreamMapper {
// Store tuples of (column, index) to preserve order
protected readonly IDictionary<string, (ColumnExpression column, int index)> myNewColumns;
protected IBlueTableSchema? mySchema;
public ColumnAdder(string columnsExpression) =>
myNewColumns = (ColumnExpressionInterpreter.Evaluate(columnsExpression) ??
throw new Exception("Invalid columnn expression: " + columnsExpression))
.Select((c, i) => (c, i))
.ToDictionary(c => c.c.Name, c => (c.c, c.i));
[MemberNotNull(nameof(mySchema))]
public virtual IBlueRow map(IBlueRow row) {
// Only rebuild schema if necessary (i.e., if it's null)
mySchema ??= buildSchema(row.schema, myNewColumns);
return new AddColumnsRow(mySchema, row);
}
[MemberNotNull(nameof(mySchema))]
public IBlueTableSchema getOutputSchema(IBlueTableSchema inputSchema) =>
// Always rebuild schema (even if it's already non-null)
mySchema = buildSchema(inputSchema, myNewColumns);
[MemberNotNull(nameof(mySchema))]
static BlueTableSchema buildSchema(
IBlueTableSchema schema,
IDictionary<string, (ColumnExpression column, int index)> newColumns
) {
ColumnInfo[] cis = new ColumnInfo[schema.columnNames.Length + newColumns.Count];
schema.columnInfo.CopyTo(cis, 0);
foreach (var (col, index) in newColumns.Values) {
var schemaIdx = schema.columnInfo.Length + index;
cis[schemaIdx] = new ColumnInfo(col.Name, schemaIdx, col.Type, col.Value);
}
return new BlueTableSchema(cis, schema.tableName);
}
}
@@ -1,52 +1,47 @@
using System;
namespace BCG
{
[DataStreamUserRespresentation ("count")]
public class CountStream : ViewStream
{
namespace bts.BlueOrb {
using BCG;
[DataStreamUserRespresentation("CountStream")]
public class CountStream : ViewStream {
private DataPacket myLastFiredDataPacket;
private IBlueTableSchema mySchema = new BlueTableSchema ("count",
new ColumnInfo ("id", 0, typeof(int)),
new ColumnInfo ("count", 1, typeof(int)));
private IBlueTableSchema mySchema = new BlueTableSchema("count",
new ColumnInfo("id", 0, typeof(int)),
new ColumnInfo("count", 1, typeof(int)));
private int myId = 0;
private ViewStream myVS;
public CountStream (ViewStream vs)
{
public CountStream(ViewStream vs) {
myVS = vs;
}
public CountStream (string tableName)
: this (new TableStream (tableName))
{}
public CountStream(string tableName)
: this(new TableStream(tableName)) { }
protected override void myOnFirstSubscriber () {
protected override void myOnFirstSubscriber() {
myVS.onChange += new ChangeDelegate(myHandleChanges);
}
protected override void myOnLastSubscriber () {
protected override void myOnLastSubscriber() {
myVS.onChange -= new ChangeDelegate(myHandleChanges);
}
private void myHandleChanges(object newValue)
{
myFireEvent (
private void myHandleChanges(object newValue) {
myFireEvent(
myLastFiredDataPacket =
myLastFiredDataPacket == null ?
new DataPacket (myGetRows (newValue, ++myId), myGetRows (newValue, myId),
new BlueTable (mySchema))
new DataPacket(myGetRows(newValue, ++myId), myGetRows(newValue, myId),
new BlueTable(mySchema))
:
new DataPacket (myGetRows (newValue, ++myId), myGetRows (newValue, myId),
new DataPacket(myGetRows(newValue, ++myId), myGetRows(newValue, myId),
myLastFiredDataPacket.newRows)
);
}
private IBlueRowCollection myGetRows (object dp, int id)
{
BlueTable retVal = new BlueTable (mySchema);
private IBlueRowCollection myGetRows(object dp, int id) {
BlueTable retVal = new BlueTable(mySchema);
retVal.addRow
(new BlueRow (mySchema, id, (dp as DataPacket).newRows.Count));
(new BlueRow(mySchema, id, (dp as DataPacket).newRows.Count));
return retVal;
}
@@ -1,23 +1,24 @@
using bts;
using System;
using System.Collections;
namespace BCG
{
namespace BCG {
/// <summary>
/// Provides a stream that with distinct rows with respect to the columns
/// the user specifies in the argument
/// </summary>
[DataStreamUserRespresentation ("distinct")]
public class DistinctRowStream : ViewStream
{
public DistinctRowStream (ViewStream stream, params string[] cols)
{
ArrayList groupByCols = new ArrayList ();
foreach (string col in cols)
foreach (string c in col.Split (' '))
groupByCols.Add (c);
mySetRealSource (new GroupByStream (stream,
new DistinctRowEvaluator (groupByCols.ToArray (typeof(string)) as string[]), false));
[DataStreamUserRespresentation("distinct")]
public class DistinctRowStream : ViewStream {
public DistinctRowStream(ViewStream stream, params string[] cols) {
var g_by_eval = new DistinctRowEvaluator(cols);
ViewStream r = new GroupByStream(stream, g_by_eval);
var proj_exp = String.Empty;
foreach (var c in cols)
proj_exp += $"{c} ";
proj_exp = proj_exp.Trim();
r = new NewProjectStream(r, proj_exp);
mySetRealSource(r);
}
}
}
@@ -1,49 +0,0 @@
// using System;
// using System.Collections.Generic;
// using System.Text;
// using System.IO;
// using System.Runtime.Serialization.Formatters.Binary;
// namespace BCG
// {
// public class DumpLoaderStream : ViewStream, ISideEffectStream
// {
// //wtf
// //public class Exception : System.Exception
// //{public Exception(string msg) : base(msg) { }}
// public DumpLoaderStream(string fileName, int secondsBetweenPolls)
// {
// mySetRealSource(
// new PollStream(() => new LoaderStream(fileName).rows, secondsBetweenPolls,
// ViewStreamDatabase.instance));
// }
// public DumpLoaderStream(string fileName)
// {
// if (fileName == null)
// throw new LoaderStream.Exception("File name cannot be null");
// for (int i = 0; i < 5; i++)
// try
// {
// using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
// {
// IClientDeserializer deser = new ClientUniversalDeserializer();
// byte[] the_ops;
// Array the_rows;
// deser.deserialize(new Stream[] { fs }, out the_ops, out the_rows);
// mySetRealSource(new BlueRowCollectionStaticStream((IBlueRowCollection)the_rows.GetValue(0)));
// }
// break;
// }
// catch (IOException)
// {
// System.Threading.Thread.Sleep(50);
// }
// }
// }
// }
@@ -1,48 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using BCG;
using System.Runtime.Serialization.Formatters.Binary;
namespace BCG
{
namespace bts {
// This is the other side of the SaverStream, its "loads" the stream and fires once
[DataStreamUserRespresentation("loader")]
public class LoaderStream : ViewStream, ISideEffectStream
{
public class Exception : System.Exception
{public Exception(string msg) : base(msg) { }}
public class LoaderStream : ViewStream {
public LoaderStream(string fileName, int secondsBetweenPolls)
{
mySetRealSource(
new PollStream(() => new LoaderStream(fileName).rows, secondsBetweenPolls,
ViewStreamDatabase.instance));
private string _filename;
private IStreamMsgDeserilizer _deser = new StreamIODeserializationController();
public LoaderStream(string filename) {
_filename = filename;
}
public LoaderStream(string fileName)
{
if (fileName == null)
throw new LoaderStream.Exception("File name cannot be null");
for (int i = 0; i < 5; i++)
try
{
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
BinaryFormatter bf = new BinaryFormatter();
#pragma warning disable SYSLIB0011
BlueTable bt = (BlueTable)bf.Deserialize(fs);
#pragma warning restore SYSLIB0011
mySetRealSource(new BlueRowCollectionStaticStream(bt));
}
break;
}
catch (IOException)
{
System.Threading.Thread.Sleep(50);
}
protected override void myOnFirstSubscriber() {
byte[] ser_msg = StreamSerializationUtils.read_from_file(_filename);
StreamIOMessage msg = _deser.deserialize(ser_msg);
Log.assert(msg.op == StreamIOMessage.StreamOp.CREATE);
IBlueRowCollection rows = msg.create_message.rows;
DataPacket dp = BlueDataUtility.build_dp_inc(rows, myLastValue as DataPacket);
myFireEvent(dp);
}
}
}
@@ -5,9 +5,11 @@ using System.Text;
using System.IO;
using Google.Protobuf;
using System.Globalization;
using BCG;
namespace BCG {
// Writes all the udpates to a stream in a file.
namespace bts {
// Writes all the udpates to a stream in a file or multiples files dependong on the rollover size (as opposed to Saver
// which just writes one update, as a create)
// File naming:
// token_epoch_yyyyMMdd_HHmmss
// File location: directory(passed)\token\
@@ -15,11 +17,16 @@ namespace BCG {
// data:
// epochtime, size, serialized data
[DataStreamUserRespresentation("pers")]
// Saves each udpate of a stream into a file. The token is the the unique logical name of the stream,
// which maps the name of the directory where the streams are saved. The directory (3rd arg) is the
// parent directory where the token folder is stored. Each file goes up to rolloevr_size after which a new
// file is created. The file names are token_epoch_datetime
// the first entry in a file is the complete state
public class PersistorStream : ViewStream {
private ViewStream _source_stream;
private string _token;
private FileStream _out_fs;
private IBlueDataSerializer _serializer;
private IStreamIOMsgSerializer _serializer;// = new UniversalStreamIOSerializer();
private string _file_name = String.Empty;
private long _rollover_size;
private readonly string _directory_path;
@@ -88,20 +95,19 @@ namespace BCG {
void _on_change(object new_value) {
DataPacket dp = new_value as DataPacket;
byte[] serialized_update = null;
bool _write_create = _serializer == null || _n_updates_in_current_file == 0;
_serializer = _serializer ?? new UniversalSerializer(dp.schema);
if (_write_create) {
// new files always starts with create
_serializer.serialize(StreamOpCode.create, new IBlueRowCollection[] { dp.newRows }, out serialized_update);
bool first_write = _serializer == null || _n_updates_in_current_file == 0;
_serializer = _serializer ?? new UniversalStreamIOSerializer();
if (first_write) {
// first file always starts with create
serialized_update = _serializer.serialize(new bts.StreamIOMessage(new bts.StreamIOMessage.CreateMessage(dp.newRows)));
} else
_serializer.serialize(StreamOpCode.multipleRemoveAdd, new IBlueRowCollection[] { dp.deletedRows, dp.addedRows }, out serialized_update);
serialized_update = _serializer.serialize(new bts.StreamIOMessage(new bts.StreamIOMessage.MultipleRemoveAddMessage(dp.deletedRows, dp.addedRows)));
BinaryWriter bw = new BinaryWriter(_out_fs);
long utc_epoch = epoch_now();
//time, length of data, data
bw.Write(utc_epoch);
bw.Write(serialized_update.Length);
//bw.Write(utc_epoch);
//bw.Write(serialized_update.Length);
bw.Write(serialized_update);
_out_fs.Flush();
myFireEvent(dp);
@@ -1,190 +0,0 @@
// using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Text;
// using System.IO;
// using System.Runtime.Serialization.Formatters.Binary;
// using BCG.Utilities.General;
// using bts.collections;
// using System.Reflection.Metadata;
// namespace BCG {
// public class PlaybackStream : ViewStream, IWorker {
// private readonly PlaybackType _type;
// private BlueTable _current_table;
// private IClientDeserializer _deserilializer = new ClientUniversalDeserializer();
// // these are the packets already downloaded from the current file
// private List<PlaybackPacket> _packets = new List<PlaybackPacket>();
// //private IEnumerable<FileStream> _file_streams = new List<FileStream>();
// private IEnumerable<string> _file_names;
// private Tuple<int, FileStream> _current_fs = new Tuple<int, FileStream>(-1, null);
// private DateTime _playback_t0, _playback_t1;
// private bool _all_files_read = false;
// SnapshotData _snapshot_data = null; // only initialized when in snapshot mode
// public PlaybackStream(string datetime_start, string datetime_end, string directory_name, string token) {
// _type = PlaybackType.Streaming;
// _playback_t0 = PersistorStream.parse_datetime(datetime_start);
// _playback_t1 = PersistorStream.parse_datetime(datetime_end);
// string token_directory_name = $"{directory_name}\\{token}";
// bts.Log.Gen.info($"PlaybackStream t0: {_playback_t0} t1: {_playback_t1} dir: {token_directory_name}");
// List<string> files_in_range = new List<string>();
// if (Directory.Exists(token_directory_name)) {
// _file_names =
// Directory.GetFiles(token_directory_name).Where(f => {
// DateTime file_time = PersistorStream.parse_datetime_from_filename(f);
// return file_time > _playback_t0 && file_time < _playback_t1;
// });
// }
// }
// protected override void myOnFirstSubscriber() {
// FileStream fs = new FileStream(_snapshot_data.snapshot_file, FileMode.Open, FileAccess.Read);
// _snapshot_data.packets = StreamPersistorUtils.load_packets_from_file(fs);
// PlaybackPacket snapshot_packet = StreamPersistorUtils.find_packet_at_time(_snapshot_data.packets, _snapshot_data.snapshot_time);
// if (snapshot_packet != null) {
// foreach (PlaybackPacket p in _snapshot_data.packets) {
// byte[] ops;
// Array row_array;
// _deserilializer.deserialize(new Stream[] { new MemoryStream(p.data) }, out ops, out row_array);
// for (int i = 0; i < ops.Length; i++) {
// IBlueRowCollection[] rows_args = row_array.GetValue(i) as IBlueRowCollection[];
// byte op = ops[i];
// if (op == StreamOpCode.create) {
// IBlueRowCollection full_table = rows_args[0];
// _current_table = new BlueTable(full_table);
// } else if (op == StreamOpCode.multipleRemoveAdd) {
// //IBlueRowCollection[] del_added = rows_args.GetValue(0) as IBlueRowCollection[];
// IBlueRowCollection dels = rows_args.GetValue(0) as IBlueRowCollection;
// IBlueRowCollection adds = rows_args.GetValue(1) as IBlueRowCollection;
// BlueDataUtility.absorbChanges(_current_table, dels, adds);
// } else {
// bts.Log.assert(false, $"Oprator: {op} is not expected");
// }
// if (p.idx == snapshot_packet.idx) {
// myFireEvent(new DataPacket(_current_table, _current_table, new BlueTable(_current_table.schema)));
// break;
// }
// }
// }
// }
// }
// private void _load_packets_from_current_file() {
// int curr_idx = _current_fs.Item1;
// FileStream curr_fs = _current_fs.Item2;
// _packets = new List<PlaybackPacket>();
// _packets.AddRange(StreamPersistorUtils.load_packets_from_file(curr_fs));
// }
// private bool current_file_all_replayed {
// get {
// bool rv = true;
// _packets.ForEach(p => rv = rv && p.replayed);
// return rv;
// }
// }
// protected override void myOnLastSubscriber() {
// var fs = _current_fs.Item2;
// if (fs != null) {
// fs.Close();
// }
// ViewStreamDatabase.instance.removeWorker(this);
// }
// // public event PlaybackStreamProgress onProgress;
// // public event Action onFileExhausted;
// private PlaybackPacket _locate_packet_to_replay() {
// foreach (var p in _packets) {
// // returns the first non replayed packet
// if (!p.replayed)
// return p;
// }
// //else
// {
// double secondsElapsed = new BinaryReader(myFileReader).ReadDouble();
// myNextPacketTime = myPlaybackStart + new TimeSpan(0, 0, 0, 0, (int)(1000 * secondsElapsed / myPlaybackSpeed));
// if (onProgress != null)
// onProgress(myFileReader.Position, myFileReader.Length);
// }
// }
// #region IWorker Members
// public void doWork() {
// if (_all_files_read)
// return;
// if (current_file_all_replayed) {
// _load_next_file();
// }
// PlaybackPacket curr_packet = _locate_packet_to_replay();
// if (curr_packet.idx == 0) { // first packet in the file, fire it rightaway
// byte[] ops;
// Array row_array;
// // what a stupid interface!
// _deserilializer.deserialize(new Stream[] { new MemoryStream(curr_packet.data) }, out ops, out row_array);
// _fire_packet(ops, row_array);
// curr_packet.replay_timestamp = PersistorStream.epoch_now();
// } else {
// PlaybackPacket prev_packet = _get_previous_packet(curr_packet);
// // this is the time we need to fire (replay) this packet
// long time_to_fire = prev_packet.replay_timestamp + curr_packet.offset_from_previous;
// long now_epoch = PersistorStream.epoch_now();
// // fire when we are past the
// if (now_epoch >= time_to_fire) {
// byte[] ops;
// Array row_array;
// _deserilializer.deserialize(new Stream[] { new MemoryStream(curr_packet.data) }, out ops, out row_array);
// _fire_packet(ops, row_array);
// curr_packet.replay_timestamp = PersistorStream.epoch_now();
// }
// }
// }
// private void _fire_packet(byte[] ops, Array row_array) {
// for (int i = 0; i < ops.Length; i++) {
// IBlueRowCollection[] rows_args = row_array.GetValue(i) as IBlueRowCollection[];
// byte op = ops[i];
// if (op == StreamOpCode.create) {
// IBlueRowCollection full_table = rows_args[0];
// _current_table = new BlueTable(full_table);
// //_current_table.addRows(full_table);
// myFireEvent(new DataPacket(full_table, full_table, myLastValue == null ? new BlueTable(full_table.schema) :
// (myLastValue as DataPacket).newRows));
// } else if (op == StreamOpCode.multipleRemoveAdd) {
// //IBlueRowCollection[] del_added = rows_args.GetValue(0) as IBlueRowCollection[];
// IBlueRowCollection dels = rows_args.GetValue(0) as IBlueRowCollection;
// IBlueRowCollection adds = rows_args.GetValue(1) as IBlueRowCollection;
// BlueDataUtility.absorbChanges(_current_table, dels, adds);
// myFireEvent(new DataPacket(_current_table, adds, dels));
// } else {
// bts.Log.assert(false, $"Oprator: {op} is not expected");
// }
// }
// }
// private void _load_next_file() {
// var new_idx = _current_fs.Item1 + 1;
// if (new_idx >= _file_names.Count()) {
// _all_files_read = true;
// bts.Log.Gen.info("All files read");
// return;
// }
// var prev_fs = _current_fs.Item2;
// if (prev_fs != null)
// prev_fs.Close();
// var new_filename = _file_names.ElementAt(new_idx);
// bts.Log.Gen.info("PlaybackStream_load_next_file new_filename=: {new_filename}");
// var new_fs = new FileStream(new_filename, FileMode.Open, FileAccess.Read);
// _current_fs = new Tuple<int, FileStream>(new_idx, new_fs);
// _load_packets_from_current_file();
// }
// #endregion
// }
// }
@@ -1,68 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace BCG
{
public class RecorderStream : ViewStream
{
private ViewStream mySource;
private DateTime myStartTime;
private FileStream myOutFile;
private string myFileName;
private IBlueDataSerializer mySerializer;
public RecorderStream(ViewStream src, string recordFile)
{
mySource = src;
myFileName = recordFile;
myFileName = myFileName.Replace("%DATE%", DateTime.Now.ToString("yyyyMMdd_HHmmss"));
}
protected override void myOnFirstSubscriber()
{
myStartTime = DateTime.Now;
mySource.onChange += new ChangeDelegate(mySource_onChange);
myOutFile = new FileStream(myFileName, FileMode.OpenOrCreate);
}
protected override void myOnLastSubscriber()
{
mySource.onChange -= mySource_onChange;
myOutFile.Close();
}
void mySource_onChange(object newValue)
{
DataPacket dp = (DataPacket)newValue;
BlueTable toWrite = new BlueTable(dp.schema);
if (mySerializer == null)
{
mySerializer = new UniversalSerializer(dp.schema);
}
foreach (IBlueRow r in dp.newRows)
toWrite.addRow(r);
byte[] result;
if (myLastValue == null)
mySerializer.serialize(StreamOpCode.create, new IBlueRowCollection[] { dp.newRows }, out result);
else
mySerializer.serialize(StreamOpCode.multipleRemoveAdd, new IBlueRowCollection[] { dp.deletedRows, dp.addedRows }, out result);
BinaryWriter bw = new BinaryWriter(myOutFile);
//write down what time this happened
bw.Write((DateTime.Now - myStartTime).TotalSeconds);
bw.Write(result.Length);
bw.Write(result);
myOutFile.Flush();
myFireEvent(dp);
}
}
}
@@ -1,64 +1,37 @@
// using System;
// using System.Collections.Generic;
// using System.Text;
// using System.IO;
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using BCG;
// using System.Runtime.Serialization.Formatters.Binary;
namespace bts {
// this saves the updates as a Create on the same file, each update calls -save, which
// reqrites the whole data to the packet. The other side of this stream is the Loader
[DataStreamUserRespresentation("saver")]
public class SaverStream : ViewStream {
private ViewStream _stream;
private string _filename;
private IStreamIOMsgSerializer _serializer = new StreamIOSerializationController();
// namespace BCG
// {
// [DataStreamUserRespresentation("saver")]
// public class SaverStream : ViewStream, ISideEffectStream
// {
// private ViewStream myStream;
// private string myFileName;
public SaverStream(ViewStream vs, string filename) {
_stream = vs;
_filename = filename;
}
// public class Exception : System.Exception
// {
// public Exception(string msg) : base(msg) { }
// }
protected override void myOnFirstSubscriber() { _stream.onChange += new ChangeDelegate(_handle_changes); }
// public SaverStream(ViewStream vs, string fileName)
// {
// if (fileName == null)
// throw new SaverStream.Exception("File name cannot be null");
// myStream = vs;
// myFileName = fileName;
void _handle_changes(object dp_obj) {
DataPacket dp = dp_obj as DataPacket;
_save(dp);
myFireEvent(dp_obj);
}
// }
protected override void myOnLastSubscriber() { _stream.onChange -= new ChangeDelegate(_handle_changes); }
// protected override void myOnFirstSubscriber()
// { myStream.onChange += new ChangeDelegate(myHandleChanges); }
// void myHandleChanges(object newValue)
// {
// DataPacket dp = newValue as DataPacket;
// mySave(dp);
// myFireEvent(newValue);
// }
// protected override void myOnLastSubscriber()
// { myStream.onChange -= new ChangeDelegate(myHandleChanges); }
// protected void mySave(DataPacket dp)
// {
// for (int i = 0; i < 5 ; i++)
// try
// {
// using (FileStream fs = new FileStream(myFileName, FileMode.Create, FileAccess.Write))
// {
// BinaryFormatter bf = new BinaryFormatter();
// BlueTable t = new BlueTable(dp.schema);
// foreach (IBlueRow r in dp.newRows) // to guarantee table is serializable
// t.addRow(new BlueRow(r));
// bf.Serialize(fs, t);
// }
// break;
// }
// catch (IOException)
// {
// System.Threading.Thread.Sleep(5);
// }
// }
// }
// }
protected void _save(DataPacket dp) {
StreamIOMessage.CreateMessage cr_msg = new StreamIOMessage.CreateMessage(dp.newRows);
byte[] str_bytes = _serializer.serialize(new StreamIOMessage(cr_msg));
StreamSerializationUtils.write_to_file(str_bytes, _filename);
}
}
}
@@ -1,115 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using BCG.Utilities.General;
using bts.collections;
using System.Reflection.Metadata;
// using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Text;
// using System.IO;
// using System.Runtime.Serialization.Formatters.Binary;
// using BCG.Utilities.General;
// using bts.collections;
// using System.Reflection.Metadata;
namespace BCG {
public class SnapshotStream : ViewStream {
public enum SpecificSnapshot {
FirstOfDay,
LastOfDay
};
// private BlueTable _current_table;
// private IClientDeserializer _deserilializer = new ClientUniversalDeserializer();
// public DateTime _snapshot_time;
// public string _snapshot_file;
// public IEnumerable<PlaybackPacket> _packets;
// public SnapshotStream(string snapshot_date, string specific_snapshot, string directory_name, string token) {
// DateTime dt;
// var parsed = DateTime.TryParse(snapshot_date, out dt);
// dt = dt.Date;
// bts.Log.assert(parsed);
// SpecificSnapshot specific_snapshot_enum;
// parsed = Enum.TryParse<SpecificSnapshot>(specific_snapshot, out specific_snapshot_enum);
// bts.Log.assert(parsed);
// string snapshot_dt = StreamPersistorUtils.find_snapshot_file($"{directory_name}\\{token}", dt, specific_snapshot_enum);
// ViewStream rs = new SnapshotStream(snapshot_dt, directory_name, token);
// mySetRealSource(rs);
// }
private BlueTable _current_table;
private IClientDeserializer _deserilializer = new ClientUniversalDeserializer();
public DateTime _snapshot_time;
public string _snapshot_file;
public IEnumerable<PlaybackPacket> _packets;
// public SnapshotStream(string snapshot_dt, string directory_name, string token) {
// _snapshot_time = PersistorStream.parse_datetime(snapshot_dt);
// string token_directory_name = $"{directory_name}\\{token}";
// _snapshot_file = StreamPersistorUtils.find_snapshot_file(token_directory_name, _snapshot_time);
// }
// protected override void myOnFirstSubscriber() {
// FileStream fs = new FileStream(_snapshot_file, FileMode.Open, FileAccess.Read);
// _packets = StreamPersistorUtils.load_packets_from_file(fs);
// PlaybackPacket snapshot_packet = StreamPersistorUtils.find_packet_at_time(_packets, _snapshot_time);
// if (snapshot_packet != null) {
// foreach (PlaybackPacket p in _packets) {
// byte[] ops;
// Array row_array;
// _deserilializer.deserialize(new Stream[] { new MemoryStream(p.data) }, out ops, out row_array);
// for (int i = 0; i < ops.Length; i++) {
// IBlueRowCollection[] rows_args = row_array.GetValue(i) as IBlueRowCollection[];
// byte op = ops[i];
// if (op == StreamOpCode.create) {
// IBlueRowCollection full_table = rows_args[0];
// _current_table = new BlueTable(full_table);
// } else if (op == StreamOpCode.multipleRemoveAdd) {
// //IBlueRowCollection[] del_added = rows_args.GetValue(0) as IBlueRowCollection[];
// IBlueRowCollection dels = rows_args.GetValue(0) as IBlueRowCollection;
// IBlueRowCollection adds = rows_args.GetValue(1) as IBlueRowCollection;
// BlueDataUtility.absorbChanges(_current_table, dels, adds);
// } else {
// bts.Log.assert(false, $"Oprator: {op} is not expected");
// }
// if (p.idx == snapshot_packet.idx) {
// myFireEvent(new DataPacket(_current_table, _current_table, new BlueTable(_current_table.schema)));
// break;
// }
// }
// }
// }
// }
public SnapshotStream(string snapshot_dt, string directory_name, string token) {
_snapshot_time = PersistorStream.parse_datetime(snapshot_dt);
string token_directory_name = $"{directory_name}\\{token}";
_snapshot_file = StreamPersistorUtils.find_snapshot_file(token_directory_name, _snapshot_time);
}
// private void _absorb_packet(byte[] ops, Array row_array) {
// for (int i = 0; i < ops.Length; i++) {
// IBlueRowCollection[] rows_args = row_array.GetValue(i) as IBlueRowCollection[];
// byte op = ops[i];
// if (op == StreamOpCode.create) {
// IBlueRowCollection full_table = rows_args[0];
// _current_table = new BlueTable(full_table);
// } else if (op == StreamOpCode.multipleRemoveAdd) {
// //IBlueRowCollection[] del_added = rows_args.GetValue(0) as IBlueRowCollection[];
// IBlueRowCollection dels = rows_args.GetValue(0) as IBlueRowCollection;
// IBlueRowCollection adds = rows_args.GetValue(1) as IBlueRowCollection;
// BlueDataUtility.absorbChanges(_current_table, dels, adds);
// } else {
// bts.Log.assert(false, $"Operator: {op} is not expected");
// }
// }
// }
protected override void myOnFirstSubscriber() {
FileStream fs = new FileStream(_snapshot_file, FileMode.Open, FileAccess.Read);
_packets = StreamPersistorUtils.load_packets_from_file(fs);
PlaybackPacket snapshot_packet = StreamPersistorUtils.find_packet_at_time(_packets, _snapshot_time);
if (snapshot_packet != null) {
foreach (PlaybackPacket p in _packets) {
byte[] ops;
Array row_array;
_deserilializer.deserialize(new Stream[] { new MemoryStream(p.data) }, out ops, out row_array);
for (int i = 0; i < ops.Length; i++) {
IBlueRowCollection[] rows_args = row_array.GetValue(i) as IBlueRowCollection[];
byte op = ops[i];
if (op == StreamOpCode.create) {
IBlueRowCollection full_table = rows_args[0];
_current_table = new BlueTable(full_table);
} else if (op == StreamOpCode.multipleRemoveAdd) {
//IBlueRowCollection[] del_added = rows_args.GetValue(0) as IBlueRowCollection[];
IBlueRowCollection dels = rows_args.GetValue(0) as IBlueRowCollection;
IBlueRowCollection adds = rows_args.GetValue(1) as IBlueRowCollection;
BlueDataUtility.absorbChanges(_current_table, dels, adds);
} else {
bts.Log.assert(false, $"Oprator: {op} is not expected");
}
if (p.idx == snapshot_packet.idx) {
myFireEvent(new DataPacket(_current_table, _current_table, new BlueTable(_current_table.schema)));
break;
}
}
}
}
}
// protected override void myOnLastSubscriber() {
// }
private void _absorb_packet(byte[] ops, Array row_array) {
for (int i = 0; i < ops.Length; i++) {
IBlueRowCollection[] rows_args = row_array.GetValue(i) as IBlueRowCollection[];
byte op = ops[i];
if (op == StreamOpCode.create) {
IBlueRowCollection full_table = rows_args[0];
_current_table = new BlueTable(full_table);
} else if (op == StreamOpCode.multipleRemoveAdd) {
//IBlueRowCollection[] del_added = rows_args.GetValue(0) as IBlueRowCollection[];
IBlueRowCollection dels = rows_args.GetValue(0) as IBlueRowCollection;
IBlueRowCollection adds = rows_args.GetValue(1) as IBlueRowCollection;
BlueDataUtility.absorbChanges(_current_table, dels, adds);
} else {
bts.Log.assert(false, $"Operator: {op} is not expected");
}
}
}
// // public event SnapshotStream.Progress onProgress;
// // public event Action onFileExhausted;
// private PlaybackPacket _locate_packet_to_replay() {
// foreach (var p in _packets) {
// // returns the first non replayed packet
// if (!p.replayed)
// return p;
// }
// return null;
// }
protected override void myOnLastSubscriber() {
}
// private void _fire_packet(byte[] ops, Array row_array) {
// for (int i = 0; i < ops.Length; i++) {
// IBlueRowCollection[] rows_args = row_array.GetValue(i) as IBlueRowCollection[];
// byte op = ops[i];
// if (op == StreamOpCode.create) {
// IBlueRowCollection full_table = rows_args[0];
// _current_table = new BlueTable(full_table);
// //_current_table.addRows(full_table);
// myFireEvent(new DataPacket(full_table, full_table, myLastValue == null ? new BlueTable(full_table.schema) :
// (myLastValue as DataPacket).newRows));
// } else if (op == StreamOpCode.multipleRemoveAdd) {
// //IBlueRowCollection[] del_added = rows_args.GetValue(0) as IBlueRowCollection[];
// IBlueRowCollection dels = rows_args.GetValue(0) as IBlueRowCollection;
// IBlueRowCollection adds = rows_args.GetValue(1) as IBlueRowCollection;
// BlueDataUtility.absorbChanges(_current_table, dels, adds);
// myFireEvent(new DataPacket(_current_table, adds, dels));
// } else {
// bts.Log.assert(false, $"Oprator: {op} is not expected");
// }
// public event SnapshotStream.Progress onProgress;
// public event Action onFileExhausted;
private PlaybackPacket _locate_packet_to_replay() {
foreach (var p in _packets) {
// returns the first non replayed packet
if (!p.replayed)
return p;
}
return null;
}
private void _fire_packet(byte[] ops, Array row_array) {
for (int i = 0; i < ops.Length; i++) {
IBlueRowCollection[] rows_args = row_array.GetValue(i) as IBlueRowCollection[];
byte op = ops[i];
if (op == StreamOpCode.create) {
IBlueRowCollection full_table = rows_args[0];
_current_table = new BlueTable(full_table);
//_current_table.addRows(full_table);
myFireEvent(new DataPacket(full_table, full_table, myLastValue == null ? new BlueTable(full_table.schema) :
(myLastValue as DataPacket).newRows));
} else if (op == StreamOpCode.multipleRemoveAdd) {
//IBlueRowCollection[] del_added = rows_args.GetValue(0) as IBlueRowCollection[];
IBlueRowCollection dels = rows_args.GetValue(0) as IBlueRowCollection;
IBlueRowCollection adds = rows_args.GetValue(1) as IBlueRowCollection;
BlueDataUtility.absorbChanges(_current_table, dels, adds);
myFireEvent(new DataPacket(_current_table, adds, dels));
} else {
bts.Log.assert(false, $"Oprator: {op} is not expected");
}
}
}
// }
// }
}
}
}
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.IO;
using bts;
namespace BCG {
@@ -37,6 +38,20 @@ namespace BCG {
public IEnumerable<PlaybackPacket> packets = new List<PlaybackPacket>();
}
public static class StreamPersistorUtils {
public static string find_snapshot_file(string directory_name, DateTime snapshot_date, SnapshotStream.SpecificSnapshot specific_snapshot) {
DateTime max_dt = DateTime.MinValue;
string rv = String.Empty;
string[] file_names = Directory.GetFiles(directory_name);
for (int i = 0; i < file_names.Count() - 1; i++) {
string fn = file_names[i];
var dt = parse_datetime_from_filename(fn);
if (dt > max_dt) {
max_dt = dt;
rv = fn;
}
}
return rv;
}
public static string find_snapshot_file(string directory_name, DateTime snapshot_time) {
string[] file_names = Directory.GetFiles(directory_name);
for (int i = 0; i < file_names.Count() - 1; i++) {
Loaded 100 of 1668 files, more files were not shown because too many files have changed in this diff. Show more