Compare commits
247
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5ada70d49 | ||
|
|
f93319cce4 | ||
|
|
d111143a3f | ||
|
|
d4e9b8b49d | ||
|
|
2bc8cf6db5 | ||
|
|
881651e3d6 | ||
|
|
64b3d0d092 | ||
|
|
7b40f56498 | ||
|
|
f4b010f3f0 | ||
|
|
edd0c2b2b7 | ||
|
|
74b2860414 | ||
|
|
65ac7a03ad | ||
|
|
5a5649e440 | ||
|
|
98d98cb899 | ||
|
|
1f2f483e21 | ||
|
|
0d93cce697 | ||
|
|
fe53fd0f2b | ||
|
|
0b2a0266c1 | ||
|
|
670ed49534 | ||
|
|
3d59e2d049 | ||
|
|
c8a7cd0961 | ||
|
|
7598d9a237 | ||
|
|
f4fbb304b8 | ||
|
|
7c0d2bf046 | ||
|
|
79aa309141 | ||
|
|
27e834dee6 | ||
|
|
032d53de5b | ||
|
|
b0a7f28070 | ||
|
|
0d6359904c | ||
|
|
e74fb56431 | ||
|
|
cf7c0830d3 | ||
|
|
255c76cf3b | ||
|
|
873f9568b6 | ||
|
|
17acf3424f | ||
|
|
3a36ffcb16 | ||
|
|
0883b4af48 | ||
|
|
8c3a12cda6 | ||
|
|
b8799622d5 | ||
|
|
8b80c9821f | ||
|
|
23d2c2d6c2 | ||
|
|
60a34785a0 | ||
|
|
b8c4f772cc | ||
|
|
d343f35fff | ||
|
|
ef7892e14e | ||
|
|
08e8255b5a | ||
|
|
4d1e0008d5 | ||
|
|
cd2e7a5795 | ||
|
|
e4a099cf6d | ||
|
|
d2bbd43ecb | ||
|
|
86eb53cc29 | ||
|
|
95fda4f268 | ||
|
|
f7fba0b638 | ||
|
|
08598d2b78 | ||
|
|
5ecef5f34d | ||
|
|
ec9fabb26e | ||
|
|
c11f0157c5 | ||
|
|
f1ace62773 | ||
|
|
5b40ea03a6 | ||
|
|
bf8dccf5eb | ||
|
|
bdcb71ec7f | ||
|
|
a6b387afec | ||
|
|
603f810465 | ||
|
|
304c6fd4d1 | ||
|
|
30ee2cab3d | ||
|
|
aa95fb3a35 | ||
|
|
af1bc96e01 | ||
|
|
d41fa8a5fb | ||
|
|
1da52e9a5a | ||
|
|
53739e3919 | ||
|
|
18ea0ec425 | ||
|
|
0b3a3d8833 | ||
|
|
b8d35cc0f9 | ||
|
|
eb81da9863 | ||
|
|
9ea79c0bc9 | ||
|
|
621cdb90a4 | ||
|
|
3ded2653ad | ||
|
|
e92a91b450 | ||
|
|
9d66f268ec | ||
|
|
a81f176de6 | ||
|
|
3ff3f62be3 | ||
|
|
09b28704e6 | ||
|
|
586fdefc45 | ||
|
|
99f13b5ba5 | ||
|
|
5c9624380e | ||
|
|
ca6429e483 | ||
|
|
9f1e4d8b3e | ||
|
|
7e79430aeb | ||
|
|
031b0ac521 | ||
|
|
9ec5bf4ea5 | ||
|
|
5507743201 | ||
|
|
e0e4bf9764 | ||
|
|
95ba1bb0bd | ||
|
|
a524943f47 | ||
|
|
19804866ad | ||
|
|
ef5835a83c | ||
|
|
86b9c67c54 | ||
|
|
0a6d960522 | ||
|
|
eb8be7a98f | ||
|
|
8c05bcf4f7 | ||
|
|
b788505646 | ||
|
|
fcf5707ef1 | ||
|
|
38dcfeae79 | ||
|
|
be4556a6b2 | ||
|
|
939b783583 | ||
|
|
466d3eb432 | ||
|
|
d3f069439d | ||
|
|
bc9102b7b5 | ||
|
|
b0bc68997b | ||
|
|
ad1e9b1fe2 | ||
|
|
1efbca9a49 | ||
|
|
00f825802d | ||
|
|
4dc95e1979 | ||
|
|
fd0f95a884 | ||
|
|
00f866d3f5 | ||
|
|
17b2d56391 | ||
|
|
0d9699b79c | ||
|
|
87c3471c9c | ||
|
|
2bb6458c44 | ||
|
|
768ec3ca34 | ||
|
|
b10135aded | ||
|
|
00dbbfa230 | ||
|
|
f4570b2083 | ||
|
|
5e79a58253 | ||
|
|
61ddefa862 | ||
|
|
490e425fc3 | ||
|
|
0382d5de3b | ||
|
|
0ae1d61ce1 | ||
|
|
3c1d849989 | ||
|
|
1b26f4b114 | ||
|
|
8a2dea53e6 | ||
|
|
e396ebb181 | ||
|
|
7f9be44cc2 | ||
|
|
0f88a15c57 | ||
|
|
b84dfce39d | ||
|
|
86bddb7fd6 | ||
|
|
3b4e424dd3 | ||
|
|
96dee6ac0e | ||
|
|
e0ea6418bd | ||
|
|
fd34c0f5e7 | ||
|
|
0e50994c2d | ||
|
|
8612f6c073 | ||
|
|
39bc561834 | ||
|
|
2f88cbd7e8 | ||
|
|
1e625c58cf | ||
|
|
c792e1897e | ||
|
|
71032cdefc | ||
|
|
6709ccc2fe | ||
|
|
807675a0ab | ||
|
|
f7f1ea2c0c | ||
|
|
443aac540a | ||
|
|
7c803d18f9 | ||
|
|
2c813da889 | ||
|
|
6e0dbe56a3 | ||
|
|
7550e81aa7 | ||
|
|
d3ce9a7a9a | ||
|
|
4ffc0cf38e | ||
|
|
5607e92ea9 | ||
|
|
77b9a2fbbb | ||
|
|
7e1136a092 | ||
|
|
f5b71bda18 | ||
|
|
e4d6bc604b | ||
|
|
148a1bd5d4 | ||
|
|
b4eaba8af4 | ||
|
|
7801ac9300 | ||
|
|
4f6614c080 | ||
|
|
f9084e24dd | ||
|
|
32c8589478 | ||
|
|
7e25b904b4 | ||
|
|
a25afb9c64 | ||
|
|
f672d2221a | ||
|
|
36f1596288 | ||
|
|
d0f0ef12f5 | ||
|
|
ca326690a5 | ||
|
|
d84fb40454 | ||
|
|
263a051dd7 | ||
|
|
36f9e29520 | ||
|
|
ae8dd16e36 | ||
|
|
26625e317e | ||
|
|
b966352d79 | ||
|
|
38a3eebb13 | ||
|
|
940a34cd8a | ||
|
|
e4ed09d96e | ||
|
|
6edb8b89f0 | ||
|
|
b870e49d01 | ||
|
|
f2e5ed35fb | ||
|
|
368ffce5cf | ||
|
|
46b4313f2a | ||
|
|
2dd6c3d6a6 | ||
|
|
547d3cd755 | ||
|
|
280c141f5b | ||
|
|
865e001888 | ||
|
|
b621a6b240 | ||
|
|
979eb50268 | ||
|
|
3960403d5a | ||
|
|
ff66151fc1 | ||
|
|
76dcc331e4 | ||
|
|
037ce4a2b8 | ||
|
|
96f0cfec1c | ||
|
|
6d013abe7a | ||
|
|
97691cceb3 | ||
|
|
7a612502e9 | ||
|
|
964f9a0b06 | ||
|
|
5085e872cb | ||
|
|
c0fd30ab92 | ||
|
|
40dfbd90d5 | ||
|
|
9411e8ed21 | ||
|
|
b6291d89e3 | ||
|
|
4fb8b26812 | ||
|
|
583932ea91 | ||
|
|
8f0a758f1a | ||
|
|
1d76c0c0ed | ||
|
|
89cb2b04bf | ||
|
|
55f7a86500 | ||
|
|
86d01e73c4 | ||
|
|
142aca7dc5 | ||
|
|
7b57a07a31 | ||
|
|
d6983ab359 | ||
|
|
dfa47bd88e | ||
|
|
9fcf23c0d7 | ||
|
|
5a51d6e7f6 | ||
|
|
fac11fdfe2 | ||
|
|
4932388338 | ||
|
|
cccfbc7bd2 | ||
|
|
4d2cac7216 | ||
|
|
1c30546c24 | ||
|
|
c79ee0217a | ||
|
|
a8b8e4215e | ||
|
|
79f3431e77 | ||
|
|
9469906d4d | ||
|
|
de62ac6e82 | ||
|
|
4340910285 | ||
|
|
3b5e8d6e7e | ||
|
|
2fab790ebf | ||
|
|
06352bd6e9 | ||
|
|
ea4c91116f | ||
|
|
f7c2fc52ce | ||
|
|
7882c5ca77 | ||
|
|
91b9d2a37b | ||
|
|
48419e8d3c | ||
|
|
66511d69bb | ||
|
|
68a6e716f7 | ||
|
|
5d28d0e455 | ||
|
|
8db44cc7f5 | ||
|
|
91220a0296 | ||
|
|
9709112307 | ||
|
|
82128be9ca | ||
|
|
fd59682b28 |
No files matched your search
@@ -9,7 +9,7 @@
|
||||
]
|
||||
},
|
||||
"fable": {
|
||||
"version": "4.24.0",
|
||||
"version": "4.0.6",
|
||||
"commands": [
|
||||
"fable"
|
||||
]
|
||||
@@ -25,12 +25,6 @@
|
||||
"commands": [
|
||||
"fake"
|
||||
]
|
||||
},
|
||||
"dotnet-t4": {
|
||||
"version": "3.0.0",
|
||||
"commands": [
|
||||
"t4"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ RUN \
|
||||
&& apt-get install -y cmake
|
||||
|
||||
# Dotnet
|
||||
RUN apt-get update && apt-get install -y dotnet8
|
||||
RUN apt-get update && apt-get install -y dotnet7
|
||||
|
||||
# Node
|
||||
ARG node_major=18
|
||||
@@ -129,3 +129,5 @@ RUN \
|
||||
-G sudo \
|
||||
--password "$(openssl passwd -1 "$docker_pass")" \
|
||||
"$docker_user"
|
||||
|
||||
RUN usermod -aG docker "$docker_user"
|
||||
@@ -1,10 +1,15 @@
|
||||
{
|
||||
"dockerFile": "Dockerfile",
|
||||
// Creates local dir to mount to HOME in docker
|
||||
"initializeCommand": "mkdir -p ${localEnv:HOME}/.bts/devcontainer-mounts/${devcontainerId}",
|
||||
"hostRequirements": {
|
||||
"memory": "8gb",
|
||||
"storage": "10gb"
|
||||
"memory": "4gb",
|
||||
"storage": "6gb"
|
||||
},
|
||||
"postCreateCommand": "/home/bts/spark/docker/sparkd/dev/devcontainer_post_create.sh",
|
||||
"containerUser": "bts",
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/home/bts/spark,type=bind",
|
||||
"workspaceFolder": "/home/bts/spark",
|
||||
"updateRemoteUserUID": true,
|
||||
"shutdownAction": "none",
|
||||
// Note: If running multiple containers on the same host, each must use a
|
||||
@@ -12,20 +17,26 @@
|
||||
// example, if 8000-8003 is taken, go with 9000-9003, then 10000-10003, etc.
|
||||
"runArgs": [
|
||||
"--shm-size",
|
||||
"8gb"
|
||||
"2gb",
|
||||
"--network",
|
||||
"host"
|
||||
],
|
||||
"mounts": [
|
||||
"source=${localEnv:HOME}/.bts/devcontainer-mounts/${devcontainerId},target=/home/bts,type=bind",
|
||||
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"clangd.arguments": [
|
||||
"--compile-commands-dir=${workspaceFolder}/build/clang/debug"
|
||||
]
|
||||
},
|
||||
"extensions": [
|
||||
"eamodio.gitlens",
|
||||
"llvm-vs-code-extensions.vscode-clangd",
|
||||
"ms-python.python",
|
||||
"ms-vscode.cmake-tools",
|
||||
"ms-vscode.cpptools",
|
||||
"xaver.clang-format"
|
||||
"ms-vscode.cpptools"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
# This file defines the global default configuration for docker deployments.
|
||||
# It is tracked in source control. For temporary modifications, please create
|
||||
# a separate file called ".env.local" (it's in .gitignore, so won't be tracked).
|
||||
# If a variable is defined in both files, the value in .env.local will be used.
|
||||
#
|
||||
# About the deployment procedure:
|
||||
# We use Docker Compose to build images and launch containers for various services
|
||||
# that make up our software suite:
|
||||
# - sparkd
|
||||
# - 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/app_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
|
||||
SPARKD__PYTHON_REQUIREMENTS=requirements.txt
|
||||
|
||||
# TODO: add config for other services (pubsub, md-publisher, webapp, api-server, etc.)
|
||||
@@ -1,3 +1,4 @@
|
||||
*.cmd text=auto eol=crlf
|
||||
*.cs text=auto eol=crlf
|
||||
*.sh text=auto eol=lf
|
||||
*.py text=auto eol=lf
|
||||
@@ -11,7 +11,6 @@ cmake-build-debug/
|
||||
**.vscode/*
|
||||
!.vscode/launch.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/*.env
|
||||
.vs
|
||||
obj/
|
||||
*.csproj.user
|
||||
@@ -55,12 +54,8 @@ trace_data/
|
||||
.cache/
|
||||
/src/Spark.Admin.WebApp/tsconfig.*.g.json
|
||||
/src/Spark.Admin.WebApp/src/bin/
|
||||
/src/client/**/*appsettings.Local.json
|
||||
/src/DataStreamSuite/**/*appsettings.Local.json
|
||||
**/CMakeDeps.cmake
|
||||
**/CMakeDeps_win.cmake
|
||||
.devcontainer/
|
||||
*.Generated.cs
|
||||
*.lst
|
||||
.env.local
|
||||
.secrets
|
||||
Vendored
+23
-152
@@ -1,14 +1,6 @@
|
||||
{
|
||||
"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",
|
||||
@@ -27,7 +19,7 @@
|
||||
"--sparkd",
|
||||
"http://127.0.0.1:8000/config"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"cwd": "build/Debug/bin/net7.0",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
@@ -44,7 +36,7 @@
|
||||
"--sparkd",
|
||||
"http://127.0.0.1:8000/config"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"cwd": "build/Debug/bin/net7.0",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
@@ -54,8 +46,8 @@
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "Build DataStream WebApp (Debug)",
|
||||
"program": "${workspaceFolder}/build/Debug/bin/net8.0/Bts.DataStreamWebApp.Server.dll",
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"program": "${workspaceFolder}/build/Debug/bin/net7.0/Bts.DataStreamWebApp.Server.dll",
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0",
|
||||
"env": {
|
||||
"ASPNETCORE_HTTP_PORT": "8080",
|
||||
"ASPNETCORE_HTTPS_PORT": "8443",
|
||||
@@ -67,8 +59,8 @@
|
||||
"name": "Bts.DataStreamWebApp.Server (Skip Build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/Debug/bin/net8.0/Bts.DataStreamWebApp.Server.dll",
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"program": "${workspaceFolder}/build/Debug/bin/net7.0/Bts.DataStreamWebApp.Server.dll",
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0",
|
||||
"env": {
|
||||
"ASPNETCORE_HTTP_PORT": "8080",
|
||||
"ASPNETCORE_HTTPS_PORT": "8443",
|
||||
@@ -88,10 +80,10 @@
|
||||
"windows": {
|
||||
"program": "DataStreamPublisher.exe",
|
||||
},
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0",
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
@@ -106,10 +98,10 @@
|
||||
"windows": {
|
||||
"program": "DataStreamPublisher.exe",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0",
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
@@ -118,39 +110,7 @@
|
||||
"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]"
|
||||
],
|
||||
"args": ["run"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/sparkd-debug-clang/server",
|
||||
"environment": [],
|
||||
@@ -165,25 +125,12 @@
|
||||
"program": "",
|
||||
"windows": {
|
||||
"program": "DataStreamQueryAnalyzer.exe",
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net7.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamQueryAnalyzerEnvironment}",
|
||||
"PYTHON_EXE": "${workspaceFolder}/.venv/Scripts/python.exe"
|
||||
},
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal",
|
||||
},
|
||||
{
|
||||
"name": "DataStreamQueryAnalyzer (Skip Build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"windows": {
|
||||
"program": "DataStreamQueryAnalyzer.exe",
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamQueryAnalyzerEnvironment}",
|
||||
"PYTHON_EXE": "${workspaceFolder}/.venv/Scripts/python.exe"
|
||||
},
|
||||
},
|
||||
@@ -202,7 +149,7 @@
|
||||
"windows": {
|
||||
"program": "PubSubServer.exe",
|
||||
},
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"cwd": "build/Debug/bin/net7.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
@@ -220,7 +167,7 @@
|
||||
"windows": {
|
||||
"program": "PubSubServer.exe",
|
||||
},
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"cwd": "build/Debug/bin/net7.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
@@ -235,25 +182,11 @@
|
||||
"windows": {
|
||||
"preLaunchTask": "Build Spark (Debug)",
|
||||
"program": "Spark.exe",
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:sparkEnvironment}",
|
||||
}
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Spark (Skip Build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"windows": {
|
||||
"program": "Spark.exe",
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:sparkEnvironment}",
|
||||
}
|
||||
"args": [
|
||||
"--sparkd",
|
||||
"http://127.0.0.1:8000/config"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net7.0-windows",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
@@ -270,40 +203,7 @@
|
||||
"--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}"
|
||||
]
|
||||
"cwd": "build/Debug/bin/net7.0-windows",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
@@ -312,6 +212,7 @@
|
||||
"name": "Sparkd",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "Build Sparkd (Debug | Clang)",
|
||||
"program": "",
|
||||
"linux": {
|
||||
"program": "${workspaceFolder}/build/sparkd-debug-clang/src/app_sparkd/sparkd",
|
||||
@@ -403,42 +304,12 @@
|
||||
"Staging",
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dataStreamQueryAnalyzerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "DataStreamQueryAnalyzer Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"Local",
|
||||
],
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "sparkEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "Spark Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"Local",
|
||||
],
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"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",
|
||||
},
|
||||
{
|
||||
"id": "isSparkApiEnabled",
|
||||
"type": "pickString",
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
PYTHONPATH=/workspaces/spark/build/sparkd-debug-clang/src/lib_python_interop;/workspaces/spark/src/lib_python_interop/python_interop_plugins
|
||||
Vendored
+61
-169
@@ -485,12 +485,12 @@
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "DataStreamQueryAnalyzer.exe",
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamQueryAnalyzerEnvironment}",
|
||||
"PYTHON_EXE": "${workspaceFolder}/.venv/Scripts/python.exe"
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -510,7 +510,7 @@
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -530,7 +530,7 @@
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -549,11 +549,12 @@
|
||||
"windows": {
|
||||
"command": "DataStreamPublisher.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -571,11 +572,12 @@
|
||||
"windows": {
|
||||
"command": "DataStreamPublisher.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -593,11 +595,12 @@
|
||||
"windows": {
|
||||
"command": "DataStreamPublisher.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -698,11 +701,12 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -720,11 +724,12 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -741,11 +746,12 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -763,11 +769,12 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -784,11 +791,12 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -803,7 +811,7 @@
|
||||
"windows": {
|
||||
"command": "Spark.exe",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -819,7 +827,7 @@
|
||||
"windows": {
|
||||
"command": "Spark.exe",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -835,22 +843,7 @@
|
||||
"windows": {
|
||||
"command": "Spark.exe",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.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/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -875,7 +868,7 @@
|
||||
"${input:sparkConfigQuery}",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0"
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -901,24 +894,6 @@
|
||||
"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",
|
||||
@@ -940,65 +915,6 @@
|
||||
"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/net8.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",
|
||||
@@ -1087,40 +1003,26 @@
|
||||
"default": "sparkd-debug-clang",
|
||||
},
|
||||
{
|
||||
"id": "dataStreamPublisherEnvironment",
|
||||
"id": "dataStreamPublisherConfig",
|
||||
"type": "pickString",
|
||||
"description": "Publisher Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"MarketData",
|
||||
"Production",
|
||||
"ProductionAws",
|
||||
"Staging",
|
||||
"MarketDataPublisher",
|
||||
"SimpleEchoClient",
|
||||
"SimpleTestDataPublisher",
|
||||
"TestDataPublisher",
|
||||
],
|
||||
"default": "MarketDataPublisher",
|
||||
},
|
||||
{
|
||||
"id": "dataStreamQueryAnalyzerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "DataStreamQueryAnalyzer Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"Local",
|
||||
],
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "pubSubServerEnvironment",
|
||||
"id": "pubSubServerConfig",
|
||||
"type": "pickString",
|
||||
"description": "PubSub Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"EchoServer",
|
||||
"Production",
|
||||
"ProductionAws",
|
||||
"Staging",
|
||||
"PubSubServer",
|
||||
"SimpleEchoClient",
|
||||
],
|
||||
"default": "Development",
|
||||
"default": "PubSubServer",
|
||||
},
|
||||
{
|
||||
"id": "sparkConfigQuery",
|
||||
@@ -1131,16 +1033,6 @@
|
||||
"id": "sparkdConfigQuery",
|
||||
"type": "promptString",
|
||||
"description": "Config Type(s)"
|
||||
},
|
||||
{
|
||||
"id": "sparkTest",
|
||||
"type": "promptString",
|
||||
"description": "Test to run",
|
||||
},
|
||||
{
|
||||
"id": "sparkdTest",
|
||||
"type": "promptString",
|
||||
"description": "Test to run",
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
+66
-79
@@ -1,10 +1,7 @@
|
||||
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()
|
||||
@@ -44,90 +41,80 @@ if(DEFINED APP_DATA_DIR)
|
||||
add_compile_definitions(APP_DATA_DIR="${APP_DATA_DIR}")
|
||||
endif()
|
||||
add_compile_definitions(EXPORT_MD_CONSUMER="${EXPORT_MD_CONSUMER}")
|
||||
if(WIN32)
|
||||
# subdirs
|
||||
add_subdirectory(src/lib_spark)
|
||||
else()
|
||||
if(BUILD_SPARKD)
|
||||
# Note: All macros that begin w/ 'CCAPI' are ccapi's macros (defined and/or
|
||||
# read by their code). We override some below.
|
||||
add_compile_definitions(SPARK_ENABLE_CCAPI)
|
||||
|
||||
# This allows us to override hardcoded exchange-urls with ones read from
|
||||
# config (i.e., resolved at runtime rather than compile-time)
|
||||
add_compile_definitions(CCAPI_EXPOSE_INTERNAL)
|
||||
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)
|
||||
|
||||
# Enable ccapi services
|
||||
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
|
||||
add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT)
|
||||
# Enable ccapi exchanges
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_COIN_FUTURES)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_US)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_USDS_FUTURES)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_COINBASE)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_DERIBIT)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_OKX)
|
||||
# This allows us to override hardcoded exchange-urls with ones read from
|
||||
# config (i.e., resolved at runtime rather than compile-time)
|
||||
add_compile_definitions(CCAPI_EXPOSE_INTERNAL)
|
||||
|
||||
set(CCAPI_LOG_LEVEL
|
||||
"Warn"
|
||||
CACHE STRING "<Fatal|Error|Warn|Info|Debug|Trace> Log level for ccapi")
|
||||
string(TOUPPER "${CCAPI_LOG_LEVEL}" _ccapi_log_level_upper)
|
||||
add_compile_definitions("CCAPI_ENABLE_LOG_${_ccapi_log_level_upper}")
|
||||
# Enable ccapi services
|
||||
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
|
||||
add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT)
|
||||
# Enable ccapi exchanges
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_COIN_FUTURES)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_US)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_USDS_FUTURES)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_COINBASE)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_DERIBIT)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_OKX)
|
||||
|
||||
# ** Binance **
|
||||
add_compile_definitions(CCAPI_BINANCE_URL_REST_BASE="https://api.binance.com")
|
||||
add_compile_definitions(BINANCE_INSTRUMENTS_PATH="/api/v3/exchangeInfo")
|
||||
add_compile_definitions(BINANCE_PRICE_STATS_PATH="/api/v3/ticker/24hr")
|
||||
set(CCAPI_LOG_LEVEL
|
||||
"Warn"
|
||||
CACHE STRING "<Fatal|Error|Warn|Info|Debug|Trace> Log level for ccapi")
|
||||
string(TOUPPER "${CCAPI_LOG_LEVEL}" _ccapi_log_level_upper)
|
||||
add_compile_definitions("CCAPI_ENABLE_LOG_${_ccapi_log_level_upper}")
|
||||
|
||||
# ** Binance US **
|
||||
add_compile_definitions(BINANCE_US_INSTRUMENTS_PATH="/api/v3/exchangeInfo")
|
||||
add_compile_definitions(BINANCE_US_PRICE_STATS_PATH="/api/v3/ticker/24hr")
|
||||
# ** Binance **
|
||||
add_compile_definitions(CCAPI_BINANCE_URL_REST_BASE="https://api.binance.com")
|
||||
add_compile_definitions(BINANCE_INSTRUMENTS_PATH="/api/v3/exchangeInfo")
|
||||
add_compile_definitions(BINANCE_PRICE_STATS_PATH="/api/v3/ticker/24hr")
|
||||
|
||||
# ** Binance USDS Futures **
|
||||
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 US **
|
||||
add_compile_definitions(BINANCE_US_INSTRUMENTS_PATH="/api/v3/exchangeInfo")
|
||||
add_compile_definitions(BINANCE_US_PRICE_STATS_PATH="/api/v3/ticker/24hr")
|
||||
|
||||
# ** 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")
|
||||
# ** Binance USDS Futures **
|
||||
add_compile_definitions(CCAPI_BINANCE_USDS_FUTURES_URL_REST_BASE="https://dapi.binance.com")
|
||||
add_compile_definitions(BINANCE_USDS_FUTURES_INSTRUMENTS_PATH="/dapi/v1/exchangeInfo")
|
||||
add_compile_definitions(BINANCE_USDS_FUTURES_PRICE_STATS_PATH="/dapi/v1/ticker/24hr")
|
||||
|
||||
# ** Deribit **
|
||||
add_compile_definitions(DERIBIT_INSTRUMENT_PATH="/api/v2/public/get_instrument")
|
||||
add_compile_definitions(DERIBIT_INSTRUMENTS_PATH="/api/v2/public/get_instruments")
|
||||
add_compile_definitions(DERIBIT_COMBOS_PATH="/api/v2/public/get_combos")
|
||||
add_compile_definitions(DERIBIT_TICKER_PATH="/api/v2/public/ticker")
|
||||
add_compile_definitions(DERIBIT_CURRENCIES_METHOD="public/get_currencies")
|
||||
add_compile_definitions(DERIBIT_INSTRUMENT_METHOD="public/get_instrument")
|
||||
add_compile_definitions(DERIBIT_INSTRUMENTS_METHOD="public/get_instruments")
|
||||
add_compile_definitions(DERIBIT_COMBO_DETAILS_METHOD="public/get_combo_details")
|
||||
add_compile_definitions(DERIBIT_COMBOS_METHOD="public/get_combos")
|
||||
# ** Deribit **
|
||||
add_compile_definitions(DERIBIT_INSTRUMENT_PATH="/api/v2/public/get_instrument")
|
||||
add_compile_definitions(DERIBIT_INSTRUMENTS_PATH="/api/v2/public/get_instruments")
|
||||
add_compile_definitions(DERIBIT_COMBOS_PATH="/api/v2/public/get_combos")
|
||||
add_compile_definitions(DERIBIT_TICKER_PATH="/api/v2/public/ticker")
|
||||
add_compile_definitions(DERIBIT_CURRENCIES_METHOD="public/get_currencies")
|
||||
add_compile_definitions(DERIBIT_INSTRUMENT_METHOD="public/get_instrument")
|
||||
add_compile_definitions(DERIBIT_INSTRUMENTS_METHOD="public/get_instruments")
|
||||
add_compile_definitions(DERIBIT_COMBO_DETAILS_METHOD="public/get_combo_details")
|
||||
add_compile_definitions(DERIBIT_COMBOS_METHOD="public/get_combos")
|
||||
|
||||
# ** Okx **
|
||||
add_compile_definitions(OKX_INSTRUMENTS_PATH="/api/v5/public/instruments")
|
||||
add_compile_definitions(OKX_UNDERLYING_PATH="/api/v5/public/underlying")
|
||||
endif()
|
||||
# ** Okx **
|
||||
add_compile_definitions(OKX_INSTRUMENTS_PATH="/api/v5/public/instruments")
|
||||
add_compile_definitions(OKX_UNDERLYING_PATH="/api/v5/public/underlying")
|
||||
endif()
|
||||
|
||||
# subdirs
|
||||
add_subdirectory(src/lib_spark)
|
||||
if (BUILD_SPARKD)
|
||||
add_subdirectory(src/lib_python_interop)
|
||||
add_subdirectory(src/lib_onixs_fix)
|
||||
add_subdirectory(src/lib_binance)
|
||||
add_subdirectory(src/lib_okx_execution)
|
||||
add_subdirectory(src/app_sparkd)
|
||||
add_subdirectory(src/data_files)
|
||||
endif()
|
||||
if (BUILD_ADMIN_WEB_APP)
|
||||
add_subdirectory(src/Spark.Admin.WebApp)
|
||||
endif()
|
||||
if(BUILD_DOCS)
|
||||
add_subdirectory(doc/user)
|
||||
endif()
|
||||
if(BUILD_SDK)
|
||||
add_subdirectory(src/sdk)
|
||||
endif()
|
||||
# subdirs
|
||||
add_subdirectory(src/lib_system)
|
||||
add_subdirectory(src/lib_domain)
|
||||
add_subdirectory(src/lib_http)
|
||||
if (BUILD_SPARKD)
|
||||
add_subdirectory(src/lib_python_md)
|
||||
add_subdirectory(src/app_sparkd)
|
||||
add_subdirectory(src/data_files)
|
||||
endif()
|
||||
add_subdirectory(src/lib_spark)
|
||||
if (BUILD_ADMIN_WEB_APP)
|
||||
add_subdirectory(src/Spark.Admin.WebApp)
|
||||
endif()
|
||||
if(BUILD_DOCS)
|
||||
add_subdirectory(doc/user)
|
||||
endif()
|
||||
if(BUILD_SDK)
|
||||
add_subdirectory(src/sdk)
|
||||
endif()
|
||||
+12
-15
@@ -24,13 +24,12 @@
|
||||
"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": "spark/config/profiles/default/*.conf",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net8.0;${sourceDir}/build/$<CONFIG>/bin/net8.0-windows",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0;${sourceDir}/build/$<CONFIG>/bin/net7.0-windows",
|
||||
"EXPORT_MD_CONSUMER": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
@@ -50,20 +49,11 @@
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"platform": "",
|
||||
"CMAKE_BUILD_WITH_INSTALL_RPATH": {
|
||||
"type": "BOOL",
|
||||
"value": "OFF"
|
||||
},
|
||||
"CMAKE_CXX_STANDARD": "20",
|
||||
"CMAKE_INSTALL_RPATH": ".",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}",
|
||||
"CMAKE_PREFIX_PATH": "${sourceDir}/cmake/;${sourceDir}/.venv/lib/python3.10/site-packages/pybind11/share/cmake/pybind11",
|
||||
"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",
|
||||
@@ -174,13 +164,12 @@
|
||||
"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}",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
},
|
||||
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/Spark.Api.Server/$<CONFIG>/bin/net8.0",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/Spark.Api.Server/$<CONFIG>/bin/net7.0",
|
||||
"EXPORT_MD_CONSUMER": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
@@ -219,7 +208,7 @@
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf;spark/config/profiles/data_stream/*.conf",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net8.0;${sourceDir}/build/$<CONFIG>/bin/net8.0-windows"
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0;${sourceDir}/build/$<CONFIG>/bin/net7.0-windows"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -252,7 +241,7 @@
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -DDEBUG",
|
||||
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -fno-omit-frame-pointer -DNDEBUG -O3",
|
||||
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf;spark/config/profiles/data_stream/*.conf",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0;${sourceDir}/build/$<CONFIG>/bin/net8.0",
|
||||
"EXPORT_MD_CONSUMER": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
@@ -305,6 +294,14 @@
|
||||
"inherits": "sparkd"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-debug-clang-j6",
|
||||
"configurePreset": "sparkd-debug-clang",
|
||||
"displayName": "Sparkd (Debug | Clang | jobs=6)",
|
||||
"inherits": "sparkd",
|
||||
"jobs": 6
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-debug-gcc",
|
||||
"configurePreset": "sparkd-debug-gcc",
|
||||
|
||||
@@ -14,34 +14,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spark_test", "src\client\sp
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spark.Console", "src\client\Spark.Console\Spark.Console.csproj", "{89D666E6-B500-498F-B026-4D167F68ADFC}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{267F81EF-A8AB-49FD-9F56-D7EC3C1F7C7C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataStreamSuite", "DataStreamSuite", "{C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStreamCore", "src\DataStreamSuite\DataStreamCore\DataStreamCore.csproj", "{EF26A475-6101-4C9C-A717-D60BB92A2302}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedStreams", "src\DataStreamSuite\SharedStreams\SharedStreams.csproj", "{911B08A3-515A-441D-84C8-8A43740B5FC1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PubSub", "src\DataStreamSuite\PubSub\PubSub.csproj", "{14140310-2233-430A-821B-F3058A25234B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseUtilities", "src\DataStreamSuite\BaseUtilities\BaseUtilities.csproj", "{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExpressionCore", "src\DataStreamSuite\ExpressionCore\ExpressionCore.csproj", "{6F22DB96-6EAB-4034-99D9-287021C36F01}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArithmeticExpressions", "src\DataStreamSuite\ArithmeticExpressions\ArithmeticExpressions.csproj", "{A5C33956-A41F-49B3-A41D-1082CBA59D02}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStreamExpressions", "src\DataStreamSuite\DataStreamExpressions\DataStreamExpressions.csproj", "{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.ColumnSortExpressions", "src\DataStreamSuite\Bts.ColumnSortExpressions\Bts.ColumnSortExpressions.csproj", "{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColumnMapExpressions", "src\DataStreamSuite\ColumnMapExpressions\ColumnMapExpressions.csproj", "{B945A183-2174-4ACB-B289-8A5C546656FE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BooleanExpressions", "src\DataStreamSuite\BooleanExpressions\BooleanExpressions.csproj", "{9F6D7DE8-185B-4C1D-B809-3314D092DF28}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.ColumnExpressions", "src\DataStreamSuite\Bts.ColumnExpressions\Bts.ColumnExpressions.csproj", "{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStream", "src\DataStreamSuite\DataStream\DataStream.csproj", "{39AEA075-6457-46C0-8821-1158BE6EFA57}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -98,102 +70,6 @@ Global
|
||||
{89D666E6-B500-498F-B026-4D167F68ADFC}.Release|x64.Build.0 = Release|x64
|
||||
{89D666E6-B500-498F-B026-4D167F68ADFC}.RelWithDebInfo|x64.ActiveCfg = Debug|x64
|
||||
{89D666E6-B500-498F-B026-4D167F68ADFC}.RelWithDebInfo|x64.Build.0 = Debug|x64
|
||||
{EF26A475-6101-4C9C-A717-D60BB92A2302}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EF26A475-6101-4C9C-A717-D60BB92A2302}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EF26A475-6101-4C9C-A717-D60BB92A2302}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{EF26A475-6101-4C9C-A717-D60BB92A2302}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{EF26A475-6101-4C9C-A717-D60BB92A2302}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{EF26A475-6101-4C9C-A717-D60BB92A2302}.Release|x64.Build.0 = Release|Any CPU
|
||||
{EF26A475-6101-4C9C-A717-D60BB92A2302}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{EF26A475-6101-4C9C-A717-D60BB92A2302}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{911B08A3-515A-441D-84C8-8A43740B5FC1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{911B08A3-515A-441D-84C8-8A43740B5FC1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{911B08A3-515A-441D-84C8-8A43740B5FC1}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{911B08A3-515A-441D-84C8-8A43740B5FC1}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{911B08A3-515A-441D-84C8-8A43740B5FC1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{911B08A3-515A-441D-84C8-8A43740B5FC1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{911B08A3-515A-441D-84C8-8A43740B5FC1}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{911B08A3-515A-441D-84C8-8A43740B5FC1}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{14140310-2233-430A-821B-F3058A25234B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{14140310-2233-430A-821B-F3058A25234B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{14140310-2233-430A-821B-F3058A25234B}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{14140310-2233-430A-821B-F3058A25234B}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{14140310-2233-430A-821B-F3058A25234B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{14140310-2233-430A-821B-F3058A25234B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{14140310-2233-430A-821B-F3058A25234B}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{14140310-2233-430A-821B-F3058A25234B}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{6F22DB96-6EAB-4034-99D9-287021C36F01}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6F22DB96-6EAB-4034-99D9-287021C36F01}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6F22DB96-6EAB-4034-99D9-287021C36F01}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{6F22DB96-6EAB-4034-99D9-287021C36F01}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{6F22DB96-6EAB-4034-99D9-287021C36F01}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6F22DB96-6EAB-4034-99D9-287021C36F01}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6F22DB96-6EAB-4034-99D9-287021C36F01}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{6F22DB96-6EAB-4034-99D9-287021C36F01}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{A5C33956-A41F-49B3-A41D-1082CBA59D02}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.Release|x64.Build.0 = Release|Any CPU
|
||||
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{B945A183-2174-4ACB-B289-8A5C546656FE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B945A183-2174-4ACB-B289-8A5C546656FE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B945A183-2174-4ACB-B289-8A5C546656FE}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{B945A183-2174-4ACB-B289-8A5C546656FE}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{B945A183-2174-4ACB-B289-8A5C546656FE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B945A183-2174-4ACB-B289-8A5C546656FE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B945A183-2174-4ACB-B289-8A5C546656FE}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{B945A183-2174-4ACB-B289-8A5C546656FE}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{39AEA075-6457-46C0-8821-1158BE6EFA57}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{39AEA075-6457-46C0-8821-1158BE6EFA57}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{39AEA075-6457-46C0-8821-1158BE6EFA57}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{39AEA075-6457-46C0-8821-1158BE6EFA57}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{39AEA075-6457-46C0-8821-1158BE6EFA57}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{39AEA075-6457-46C0-8821-1158BE6EFA57}.Release|x64.Build.0 = Release|Any CPU
|
||||
{39AEA075-6457-46C0-8821-1158BE6EFA57}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{39AEA075-6457-46C0-8821-1158BE6EFA57}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{9F6D7DE8-185B-4C1D-B809-3314D092DF28}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -204,19 +80,4 @@ Global
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{C09ED521-D2DF-40BC-A76F-EB3CB870B2F6} = {267F81EF-A8AB-49FD-9F56-D7EC3C1F7C7C}
|
||||
{EF26A475-6101-4C9C-A717-D60BB92A2302} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{911B08A3-515A-441D-84C8-8A43740B5FC1} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{14140310-2233-430A-821B-F3058A25234B} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{43146EA8-6FCC-46B8-88B0-42F9BB5E6E0A} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{6F22DB96-6EAB-4034-99D9-287021C36F01} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{A5C33956-A41F-49B3-A41D-1082CBA59D02} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{2FE745C3-1EDF-4421-8CD7-A63EE0C1AE43} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{FDA791E0-2B91-4AD5-B91D-CF920A4C4E38} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{B945A183-2174-4ACB-B289-8A5C546656FE} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{39AEA075-6457-46C0-8821-1158BE6EFA57} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{9F6D7DE8-185B-4C1D-B809-3314D092DF28} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,48 +0,0 @@
|
||||
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()
|
||||
+1
-10
@@ -72,14 +72,6 @@ function(init_library)
|
||||
else()
|
||||
add_library(${_name} ${${_name}_SOURCES} ${${_name}_CXX_PROTO_SOURCES})
|
||||
endif()
|
||||
target_include_directories(
|
||||
${_name}
|
||||
SYSTEM
|
||||
BEFORE
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${EXTERNALS_ROOT}/include>
|
||||
$<BUILD_INTERFACE:${EXTERNALS_ROOT}/include/zlib>
|
||||
)
|
||||
target_include_directories(
|
||||
${_name}
|
||||
PUBLIC
|
||||
@@ -98,7 +90,6 @@ function(init_library)
|
||||
${_name}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
$<BUILD_INTERFACE:${EXTERNALS_ROOT}/lib/$<CONFIG>>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_LIBDIR}>
|
||||
)
|
||||
# Install main lib
|
||||
@@ -112,7 +103,7 @@ function(init_library)
|
||||
)
|
||||
|
||||
# Add tests executable (if there are any)
|
||||
if (${_name}_TEST_SOURCES AND NOT WIN32)
|
||||
if (${_name}_TEST_SOURCES)
|
||||
add_executable(${_name}-tests ${${_name}_TEST_SOURCES})
|
||||
|
||||
get_target_property(_lib_type ${_name} TYPE)
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
include_guard(DIRECTORY)
|
||||
include(GNUInstallDirs)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/ExportToParent.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/SetFirstDefined.cmake)
|
||||
|
||||
function(init_python_module)
|
||||
set(_options)
|
||||
set(_one_value_args
|
||||
NAME
|
||||
)
|
||||
set(_multi_value_args
|
||||
SOURCES
|
||||
)
|
||||
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
|
||||
set_first_defined(_name _ARGS_NAME PROJECT_NAME)
|
||||
set_first_defined(_sources _ARGS_SOURCES ${_name}_SOURCES)
|
||||
|
||||
set(module_proj ${_name}_module)
|
||||
set(${module_proj}_SOURCES ${_sources})
|
||||
pybind11_add_module(${module_proj} SHARED ${_sources})
|
||||
target_link_libraries(
|
||||
${module_proj}
|
||||
PUBLIC
|
||||
pybind11::embed
|
||||
spark
|
||||
${_name}
|
||||
)
|
||||
target_include_directories(
|
||||
${module_proj}
|
||||
PRIVATE
|
||||
$<BUILD_INTERFACE:${pybind11_INCLUDE_DIRS}>
|
||||
)
|
||||
target_include_directories(
|
||||
${module_proj}
|
||||
PUBLIC
|
||||
${Python3_INCLUDE_DIRS}
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/stubs/${_name}.pyi
|
||||
DEPENDS ${_name} ${module_proj}
|
||||
COMMAND PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR} pybind11-stubgen --numpy-array-use-type-var --ignore-invalid-expressions '.*' ${_name}_module
|
||||
COMMENT "Generating py stubs"
|
||||
)
|
||||
add_custom_target(
|
||||
"${_name}_py_stubs"
|
||||
ALL
|
||||
DEPENDS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/stubs/${_name}.pyi
|
||||
)
|
||||
install(
|
||||
TARGETS ${module_proj}
|
||||
EXPORT ${module_proj}Targets
|
||||
RUNTIME
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
foreach(dir ${pybind11_INCLUDE_DIRS})
|
||||
install(DIRECTORY ${dir} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
endforeach()
|
||||
install(
|
||||
EXPORT ${module_proj}Targets
|
||||
FILE ${module_proj}Targets.cmake
|
||||
NAMESPACE ${_name}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${_name}
|
||||
)
|
||||
endfunction()
|
||||
@@ -1,65 +0,0 @@
|
||||
include_guard(DIRECTORY)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
function(init_python_plugin)
|
||||
set(_options)
|
||||
set(_one_value_args NAME PLUGIN_NAME)
|
||||
set(_multi_value_args SOURCES)
|
||||
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
|
||||
set_first_defined(_name _ARGS_NAME PROJECT_NAME)
|
||||
set(_plugin_name ${_ARGS_PLUGIN_NAME})
|
||||
if (NOT DEFINED _ARGS_PLUGIN_NAME)
|
||||
set(_plugin_name ${_name}_plugins)
|
||||
endif()
|
||||
set(${_plugin_name}_SOURCES ${_ARGS_SOURCES})
|
||||
if (NOT DEFINED _ARGS_SOURCES)
|
||||
file(
|
||||
GLOB_RECURSE ${_plugin_name}_SOURCES
|
||||
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${_plugin_name}/*.py)
|
||||
endif()
|
||||
set(src_outs)
|
||||
foreach(_src ${${_plugin_name}_SOURCES})
|
||||
set(_src_in ${CMAKE_CURRENT_SOURCE_DIR}/${_src})
|
||||
set(_src_out ${CMAKE_CURRENT_BINARY_DIR}/${_src})
|
||||
add_custom_command(
|
||||
OUTPUT ${_src_out}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${_src_in} ${_src_out}
|
||||
DEPENDS ${_src_in}
|
||||
COMMENT "Copying ${_plugin_name} plugin ${_src} to ${_src_out}"
|
||||
)
|
||||
list(APPEND src_outs ${_src_out})
|
||||
endforeach()
|
||||
|
||||
add_custom_target(copy_${_plugin_name} ALL DEPENDS ${src_outs})
|
||||
|
||||
add_library(${_plugin_name} INTERFACE)
|
||||
add_library(${_name}::${_plugin_name} ALIAS ${_plugin_name})
|
||||
|
||||
set_target_properties(
|
||||
${_plugin_name}
|
||||
PROPERTIES
|
||||
INTERFACE_PYTHON_SCRIPTS_DIR
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/${_plugin_name}>$<INSTALL_INTERFACE:${CMAKE_INSTALL_BINDIR}/${_plugin_name}>
|
||||
)
|
||||
|
||||
set_target_properties(
|
||||
${_plugin_name}
|
||||
PROPERTIES
|
||||
INTERFACE_PYTHON_SCRIPTS $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/${${_plugin_name}_SOURCES}>$<INSTALL_INTERFACE:${CMAKE_INSTALL_BINDIR}/${${_plugin_name}_SOURCES}>
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS ${_plugin_name}
|
||||
EXPORT ${_plugin_name}Targets
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT ${_plugin_name}Targets
|
||||
FILE ${_plugin_name}Targets.cmake
|
||||
NAMESPACE ${_name}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${_name}
|
||||
)
|
||||
install(DIRECTORY ${_plugin_name} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endfunction()
|
||||
@@ -1,182 +0,0 @@
|
||||
set(Protobuf_PROTOC_EXECUTABLE "${EXTERNALS_BIN}/protoc")
|
||||
set(PROTOBUF_INCLUDE_DIRS "${EXTERNALS_INCLUDE}")
|
||||
set(PROTOBUF_STATIC_LIB "libprotobuf")
|
||||
set(_protobuf_src_dir ${CMAKE_SOURCE_DIR}/src/lib_spark)
|
||||
set(_protobuf_bin_dir ${CMAKE_BINARY_DIR}/src/lib_spark)
|
||||
|
||||
function(Protobuf_Generate_Cpp)
|
||||
set(_options)
|
||||
set(_one_value_args CXX_SOURCES CXX_HEADERS CXX_OUT_DIR)
|
||||
set(_multi_value_args PROTO_INCLUDE_DIRS PROTO_SOURCES)
|
||||
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
|
||||
set(${_ARGS_CXX_SOURCES})
|
||||
set(${_ARGS_CXX_HEADERS})
|
||||
|
||||
set(_proto_include_cli_args)
|
||||
foreach(_dir ${_ARGS_PROTO_INCLUDE_DIRS})
|
||||
list(APPEND _proto_include_cli_args -I ${_dir})
|
||||
endforeach()
|
||||
|
||||
foreach(FIL ${_ARGS_PROTO_SOURCES})
|
||||
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
|
||||
get_filename_component(FIL_WE ${FIL} NAME_WE)
|
||||
get_filename_component(FIL_DIR ${FIL} DIRECTORY)
|
||||
if(FIL_DIR)
|
||||
set(FIL_WE "${FIL_DIR}/${FIL_WE}")
|
||||
endif()
|
||||
|
||||
list(APPEND ${_ARGS_CXX_SOURCES} "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc")
|
||||
list(APPEND ${_ARGS_CXX_HEADERS} "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h"
|
||||
COMMAND
|
||||
${Protobuf_PROTOC_EXECUTABLE}
|
||||
ARGS
|
||||
--cpp_out=${_ARGS_CXX_OUT_DIR} ${_proto_include_cli_args} ${ABS_FIL}
|
||||
DEPENDS ${ABS_FIL}
|
||||
COMMENT "Running C++ protocol buffer compiler on ${FIL}"
|
||||
VERBATIM
|
||||
)
|
||||
endforeach()
|
||||
|
||||
set_source_files_properties(
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
${${_ARGS_CXX_HEADERS}}
|
||||
PROPERTIES
|
||||
GENERATED TRUE
|
||||
)
|
||||
|
||||
# remove some warnings from protobuf generated files
|
||||
if(WIN32)
|
||||
set_source_files_properties(
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "/wd4309 /wd4838"
|
||||
)
|
||||
else()
|
||||
set_source_files_properties(
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "-Wno-unused-parameter -Wno-effc++ -Wno-pedantic -Wno-sign-compare -Wno-uninitialized"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(${_ARGS_CXX_SOURCES} ${${_ARGS_CXX_SOURCES}} PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_HEADERS} ${${_ARGS_CXX_HEADERS}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(Service_Compiler_Generate_Cpp)
|
||||
set(_options)
|
||||
set(_one_value_args CXX_SOURCES CXX_HEADERS CXX_OUT_DIR)
|
||||
set(_multi_value_args PROTO_INCLUDE_DIRS PROTO_SOURCES)
|
||||
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
|
||||
set(${_ARGS_CXX_SOURCES})
|
||||
set(${_ARGS_CXX_HEADERS})
|
||||
|
||||
set(_proto_include_cli_args)
|
||||
foreach(_dir ${_ARGS_PROTO_INCLUDE_DIRS})
|
||||
list(APPEND _proto_include_cli_args -I ${_dir})
|
||||
endforeach()
|
||||
|
||||
foreach(FIL ${_ARGS_PROTO_SOURCES})
|
||||
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
|
||||
get_filename_component(FIL_WE ${FIL} NAME_WE)
|
||||
get_filename_component(FIL_DIR ${FIL} DIRECTORY)
|
||||
if(FIL_DIR)
|
||||
set(FIL_WE "${FIL_DIR}/${FIL_WE}")
|
||||
endif()
|
||||
|
||||
list(APPEND ${_ARGS_CXX_SOURCES} "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc")
|
||||
list(APPEND ${_ARGS_CXX_HEADERS} "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h")
|
||||
|
||||
list(APPEND ${_ARGS_CXX_SOURCES} "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.cc")
|
||||
list(APPEND ${_ARGS_CXX_HEADERS} "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.h")
|
||||
|
||||
list(APPEND ${_ARGS_CXX_SOURCES} "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.cc")
|
||||
list(APPEND ${_ARGS_CXX_HEADERS} "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.h")
|
||||
|
||||
set(TEMPLATES
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/client.pb.cc
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/client.pb.h
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/server.pb.cc
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/server.pb.h
|
||||
)
|
||||
|
||||
set(_plugin_py ${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/plugin.py)
|
||||
if(WIN32)
|
||||
set(_plugin_cmd ${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/plugin.cmd)
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.h"
|
||||
COMMAND SET PYTHONPATH=${SPARK_PYTHON}
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/.venv/Scripts/activate.bat
|
||||
COMMAND
|
||||
${Protobuf_PROTOC_EXECUTABLE}
|
||||
ARGS
|
||||
--cpp_out=${_ARGS_CXX_OUT_DIR}
|
||||
--plugin=protoc-gen-service=${_plugin_cmd}
|
||||
--service_out=lang=cpp:${_ARGS_CXX_OUT_DIR}
|
||||
-I ${PROTOBUF_INCLUDE_DIRS}
|
||||
-I ${_protobuf_src_dir}
|
||||
${ABS_FIL}
|
||||
DEPENDS
|
||||
${ABS_FIL}
|
||||
${TEMPLATES}
|
||||
${_plugin_cmd}
|
||||
${_plugin_py}
|
||||
COMMENT "Running C++ service compiler on ${FIL}"
|
||||
VERBATIM
|
||||
)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.h"
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/tools/venv_exec.sh
|
||||
ARGS
|
||||
${Protobuf_PROTOC_EXECUTABLE}
|
||||
--cpp_out=${_ARGS_CXX_OUT_DIR}
|
||||
--plugin=protoc-gen-service=${_plugin_py}
|
||||
--service_out=lang=cpp,make_file_name=${ABS_FIL}:${_ARGS_CXX_OUT_DIR}
|
||||
${_proto_include_cli_args} ${ABS_FIL}
|
||||
DEPENDS
|
||||
${ABS_FIL}
|
||||
${TEMPLATES}
|
||||
${_plugin_py}
|
||||
COMMENT "Running C++ service compiler on ${FIL}"
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# remove some warnings from protobuf generated files
|
||||
if(WIN32)
|
||||
set_source_files_properties(
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "/wd4309 /wd4838"
|
||||
)
|
||||
else()
|
||||
set_source_files_properties(
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "-Wno-unused-parameter -Wno-effc++ -Wno-pedantic -Wno-sign-compare -Wno-uninitialized"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(${_ARGS_CXX_SOURCES} ${${_ARGS_CXX_SOURCES}} PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_HEADERS} ${${_ARGS_CXX_HEADERS}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -15,11 +15,7 @@ function(protobuf_generate_cpp)
|
||||
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
|
||||
|
||||
if (NOT DEFINED _ARGS_PROTOC)
|
||||
if (WIN32)
|
||||
set(_ARGS_PROTOC "${EXTERNALS_BIN}/protoc.exe")
|
||||
else()
|
||||
set(_ARGS_PROTOC "${EXTERNALS_BIN}/protoc")
|
||||
endif()
|
||||
set(_ARGS_PROTOC "${EXTERNALS_BIN}/protoc")
|
||||
endif()
|
||||
set(${_ARGS_CXX_SOURCES})
|
||||
set(${_ARGS_CXX_HEADERS})
|
||||
@@ -39,8 +35,6 @@ function(protobuf_generate_cpp)
|
||||
list(APPEND ${_ARGS_CXX_SOURCES} "${_ARGS_CXX_OUT_DIR}/${_fil_we}.pb.cc")
|
||||
list(APPEND ${_ARGS_CXX_HEADERS} "${_ARGS_CXX_OUT_DIR}/${_fil_we}.pb.h")
|
||||
message(STATUS "add_custom_command for ${_fil} -> ${_ARGS_CXX_OUT_DIR}/${_fil_we}.pb.h")
|
||||
# TODO: Pass proto sources by relative path (so this fn can be called from
|
||||
# arbitrary subdirs).
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${_ARGS_CXX_OUT_DIR}/${_fil_we}.pb.cc"
|
||||
@@ -48,7 +42,7 @@ function(protobuf_generate_cpp)
|
||||
COMMAND
|
||||
${_ARGS_PROTOC}
|
||||
ARGS
|
||||
--cpp_out=${_ARGS_CXX_OUT_DIR} ${_proto_include_cli_args} ${_abs_fil}
|
||||
--cpp_out=${_ARGS_CXX_OUT_DIR} ${_proto_include_cli_args} ${_fil}
|
||||
DEPENDS ${_abs_fil}
|
||||
COMMENT "Running C++ protocol buffer compiler on ${_fil}"
|
||||
VERBATIM
|
||||
@@ -80,4 +74,3 @@ function(protobuf_generate_cpp)
|
||||
set(${_ARGS_CXX_SOURCES} ${${_ARGS_CXX_SOURCES}} PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_HEADERS} ${${_ARGS_CXX_HEADERS}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
include_guard(GLOBAL)
|
||||
|
||||
function(protobuf_generate_cpp_config)
|
||||
set(_options)
|
||||
set(_one_value_args
|
||||
@@ -58,4 +56,3 @@ function(protobuf_generate_cpp_config)
|
||||
file(WRITE "${_ARGS_PROTO_DEFAULTS_HEADER}" "${_cfg_defaults_str}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
+8
-6
@@ -20,14 +20,16 @@ endfunction()
|
||||
|
||||
function(sym_link_file)
|
||||
set(_options)
|
||||
set(_one_value_args SOURCE DEST INSTALL_DEST)
|
||||
set(_one_value_args TARGET_NAME SOURCE DEST INSTALL_DEST)
|
||||
set(_multi_value_args)
|
||||
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
|
||||
file(
|
||||
CREATE_LINK
|
||||
${_ARGS_SOURCE}
|
||||
${_ARGS_DEST}
|
||||
SYMBOLIC
|
||||
add_custom_command(
|
||||
OUTPUT ${_ARGS_DEST}
|
||||
COMMAND ln ARGS -s ${_ARGS_SOURCE} ${_ARGS_DEST}
|
||||
)
|
||||
add_custom_target(
|
||||
${_ARGS_TARGET_NAME} ALL
|
||||
DEPENDS ${_ARGS_DEST}
|
||||
)
|
||||
if (DEFINED _ARGS_INSTALL_DEST)
|
||||
install(
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
include_guard(DIRECTORY)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/SymLink.cmake)
|
||||
|
||||
function(sym_link_python_module)
|
||||
set(_options)
|
||||
set(_one_value_args LIB_NAME MODULE_NAME PLUGIN_NAME)
|
||||
set(_multi_value_args)
|
||||
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}"
|
||||
"${_multi_value_args}" ${ARGN})
|
||||
if(NOT DEFINED _ARGS_LIB_NAME)
|
||||
message(
|
||||
FATAL_ERROR "LIB_NAME must be specified for sym_link_python_module()")
|
||||
endif()
|
||||
set(_lib_name ${_ARGS_LIB_NAME})
|
||||
set(_module_name ${_ARGS_MODULE_NAME})
|
||||
if(NOT DEFINED _ARGS_MODULE_NAME)
|
||||
set(_module_name ${_lib_name}_module)
|
||||
endif()
|
||||
set(_plugin_name ${_ARGS_PLUGIN_NAME})
|
||||
set(_deps ${_lib_name} ${_module_name})
|
||||
if(DEFINED _ARGS_PLUGIN_NAME)
|
||||
list(APPEND _deps ${_plugin_name} copy_${_plugin_name})
|
||||
endif()
|
||||
add_dependencies(${PROJECT_NAME} ${_deps})
|
||||
sym_link_local_lib(${_lib_name})
|
||||
set(_module_suffix cpython-310-x86_64-linux-gnu.so)
|
||||
sym_link_file(
|
||||
SOURCE
|
||||
${CMAKE_BINARY_DIR}/src/lib_${_lib_name}/${_module_name}.${_module_suffix}
|
||||
DEST
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${_module_name}.${_module_suffix}
|
||||
INSTALL_DEST
|
||||
${CMAKE_INSTALL_BINDIR}/)
|
||||
if(DEFINED _ARGS_PLUGIN_NAME)
|
||||
get_target_property(plugins ${_plugin_name} INTERFACE_PYTHON_SCRIPTS_DIR)
|
||||
sym_link_dir(TARGET_NAME ${PROJECT_NAME}_link_${_plugin_name} SOURCE
|
||||
${plugins} DEST ${CMAKE_CURRENT_BINARY_DIR}/${_plugin_name})
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -1,11 +0,0 @@
|
||||
#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
|
||||
@@ -0,0 +1,24 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# Explicitly set policy to convert relative paths to absolute (although this is a default policy,
|
||||
# setting it explicitly prevents a compile-warning)
|
||||
cmake_policy(SET CMP0076 NEW)
|
||||
|
||||
# add protos to the library to facilitate source_group
|
||||
target_sources(libspark PUBLIC ${Config_Protos} ${NonConfig_Protos} ${Service_Protos})
|
||||
|
||||
function(assign_source_group)
|
||||
foreach(_source IN ITEMS ${ARGN})
|
||||
if(IS_ABSOLUTE "${_source}")
|
||||
file(RELATIVE_PATH _source_rel "${CMAKE_CURRENT_SOURCE_DIR}" "${_source}")
|
||||
else()
|
||||
set(_source_rel "${_source}")
|
||||
endif()
|
||||
get_filename_component(_source_path "${_source_rel}" PATH)
|
||||
string(REPLACE "/" "\\" _source_path_msvc "${_source_path}")
|
||||
source_group("${_source_path_msvc}" FILES "${_source}")
|
||||
set(SOURCE_FILES "${_source}")
|
||||
endforeach()
|
||||
endfunction(assign_source_group)
|
||||
|
||||
assign_source_group(${SparkLib_Sources} ${Config_Protos} ${NonConfig_Protos} ${Service_Protos})
|
||||
@@ -0,0 +1,51 @@
|
||||
services:
|
||||
sparkd:
|
||||
build:
|
||||
dockerfile: Dockerfile
|
||||
context: ./sparkd
|
||||
command: [ "./sparkd", "run" ]
|
||||
ports: [ "8000:8000", "8001:8001", "8002:8002" ]
|
||||
|
||||
pubsub:
|
||||
build:
|
||||
dockerfile: pubsub.Dockerfile
|
||||
context: ./DataStream
|
||||
command: [ "./PubSubServer" ]
|
||||
environment:
|
||||
- DOTNET_ENVIRONMENT=Production
|
||||
ports:
|
||||
- 22019:22019
|
||||
|
||||
md-publisher:
|
||||
build:
|
||||
dockerfile: md-publisher.Dockerfile
|
||||
context: ./DataStream
|
||||
depends_on:
|
||||
- pubsub
|
||||
- sparkd
|
||||
command:
|
||||
[
|
||||
"dockerize",
|
||||
"-wait",
|
||||
"tcp://pubsub:22019",
|
||||
"-wait",
|
||||
"tcp://sparkd:8000",
|
||||
"-timeout",
|
||||
"10s",
|
||||
"./DataStreamPublisher"
|
||||
]
|
||||
environment:
|
||||
- DOTNET_ENVIRONMENT=MarketData
|
||||
|
||||
webapp:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 8443:8443
|
||||
build:
|
||||
dockerfile: webapp.Dockerfile
|
||||
context: ./DataStream
|
||||
command: [ "./Bts.DataStreamWebApp.Server" ]
|
||||
environment:
|
||||
- ASPNETCORE_HTTP_PORT=8080
|
||||
- ASPNETCORE_HTTPS_PORT=8443
|
||||
- ASPNETCORE_ENVIRONMENT=Staging
|
||||
+52
-143
@@ -1,100 +1,62 @@
|
||||
services:
|
||||
sparkd:
|
||||
volumes:
|
||||
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/sparkdata/data
|
||||
build:
|
||||
dockerfile: src/app_sparkd/Dockerfile
|
||||
args:
|
||||
- IMAGE=${SPARKD__IMAGE}
|
||||
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
|
||||
- CONFIG_DIR=${SPARKD__CONFIG_DIR}
|
||||
- PYTHON_REQUIREMENTS=${SPARKD__PYTHON_REQUIREMENTS}
|
||||
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
|
||||
if [ -d /home/bts/sparkdata/conf/plugins ]; then
|
||||
echo 'Copying /home/bts/sparkdata/conf/plugins to runtime dir (/home/bts/bin)'
|
||||
cp -r /home/bts/sparkdata/conf/plugins /home/bts/bin/
|
||||
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}"
|
||||
dockerfile: src/server/sparkd/Dockerfile
|
||||
command: [ "./sparkd", "run" ]
|
||||
ports: [ "8000:8000", "8001:8001", "8002:8002" ]
|
||||
|
||||
sparkd-symbols:
|
||||
volumes:
|
||||
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/sparkdata/data
|
||||
- ${SPARKD__RUNTIME_CONF_DIR:-sparkd_conf}:/home/bts/sparkdata/conf
|
||||
pubsub:
|
||||
environment:
|
||||
- DOTNET_ENVIRONMENT=Staging
|
||||
build:
|
||||
dockerfile: src/app_sparkd/Dockerfile
|
||||
args:
|
||||
- IMAGE=${SPARKD__IMAGE}
|
||||
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
|
||||
- CONFIG_DIR=${SPARKD__CONFIG_DIR}
|
||||
- PYTHON_REQUIREMENTS=${SPARKD__PYTHON_REQUIREMENTS}
|
||||
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
|
||||
if [ -d /home/bts/sparkdata/conf/plugins ]; then
|
||||
echo 'Copying /home/bts/sparkdata/conf/plugins to runtime dir (/home/bts/bin)'
|
||||
cp -r /home/bts/sparkdata/conf/plugins /home/bts/bin/
|
||||
fi
|
||||
./sparkd run"
|
||||
env_file:
|
||||
- .env
|
||||
- ${SPARKD__CONFIG_DIR}/.env
|
||||
dockerfile: src/DataStreamSuite/PubSubServer/Dockerfile
|
||||
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}"
|
||||
- 22019:22019
|
||||
command: [ "./PubSubServer" ]
|
||||
|
||||
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"]
|
||||
md-publisher:
|
||||
build:
|
||||
dockerfile: src/DataStreamSuite/DataStreamPublisher/Dockerfile
|
||||
depends_on:
|
||||
- pubsub
|
||||
- sparkd
|
||||
command:
|
||||
[
|
||||
"dockerize",
|
||||
"-wait",
|
||||
"tcp://pubsub:22019",
|
||||
"-wait",
|
||||
"tcp://sparkd:8000",
|
||||
"-timeout",
|
||||
"10s",
|
||||
"./DataStreamPublisher"
|
||||
]
|
||||
environment:
|
||||
- DOTNET_ENVIRONMENT=MarketData
|
||||
|
||||
webapp:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 8443:8443
|
||||
build:
|
||||
dockerfile: src/DataStreamSuite/Bts.DataStreamWebApp.Server/Dockerfile
|
||||
command: [ "./Bts.DataStreamWebApp.Server" ]
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Staging
|
||||
|
||||
api-server:
|
||||
profiles:
|
||||
- api-server
|
||||
depends_on:
|
||||
- sparkd
|
||||
ports:
|
||||
- 8008:8008
|
||||
- 9443:9443
|
||||
build:
|
||||
dockerfile: src/client/spark_api_server/Dockerfile
|
||||
command: [ "./spark_api_server", "run" ]
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Staging
|
||||
|
||||
sparkd-ping-test:
|
||||
depends_on:
|
||||
@@ -108,56 +70,3 @@ services:
|
||||
USER "root"
|
||||
RUN apt-get update && apt-get -y install iputils-ping
|
||||
command: [ "ping", "sparkd" ]
|
||||
|
||||
pubsub:
|
||||
environment:
|
||||
- DOTNET_ENVIRONMENT=Staging
|
||||
build:
|
||||
dockerfile: src/DataStreamSuite/PubSubServer/Dockerfile
|
||||
args:
|
||||
- SOURCE_DIR=build/Release/bin/net8.0/linux-x64/publish
|
||||
- CONF_FILE=src/DataStreamSuite/PubSubServer/spark.conf
|
||||
ports:
|
||||
- 22019:22019
|
||||
command: [ "./PubSubServer" ]
|
||||
|
||||
md-publisher:
|
||||
build:
|
||||
dockerfile: src/DataStreamSuite/DataStreamPublisher/Dockerfile
|
||||
args:
|
||||
- SOURCE_DIR=build/Release/bin/net8.0/linux-x64/publish
|
||||
- CONF_FILE=src/DataStreamSuite/DataStreamPublisher/spark.conf
|
||||
depends_on:
|
||||
- pubsub
|
||||
- sparkd
|
||||
command: [ "dockerize", "-wait", "tcp://pubsub:22019", "-wait", "tcp://sparkd:8000", "-timeout", "10s", "./DataStreamPublisher" ]
|
||||
environment:
|
||||
- DOTNET_ENVIRONMENT=MarketData
|
||||
|
||||
api-server:
|
||||
depends_on:
|
||||
- sparkd
|
||||
ports:
|
||||
- 8008:8008
|
||||
- 9443:9443
|
||||
build:
|
||||
dockerfile: src/client/spark_api_server/Dockerfile
|
||||
command: [ "dockerize", "-wait", "tcp://sparkd:8000", "-timeout", "10s", "./spark_api_server", "run" ]
|
||||
|
||||
webapp:
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 8443:8443
|
||||
build:
|
||||
dockerfile: src/DataStreamSuite/Bts.DataStreamWebApp.Server/Dockerfile
|
||||
args:
|
||||
- SOURCE_DIR=build/Release/bin/net8.0/linux-x64/publish
|
||||
- WEB_ROOT=build/Bts.DataStreamWebApp.Client/production/dist
|
||||
- CONF_FILE=src/DataStreamSuite/Bts.DataStreamWebApp.Server/spark.conf
|
||||
command: [ "./Bts.DataStreamWebApp.Server" ]
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Staging
|
||||
|
||||
volumes:
|
||||
sparkd_data:
|
||||
name: "sparkd_${SPARKD__CONFIG_PORT:-8000}"
|
||||
@@ -124,8 +124,8 @@ service OrderService {
|
||||
```
|
||||
### C++ Example
|
||||
```cpp
|
||||
#include "spark/api/public/ServiceContext.h"
|
||||
#include "spark/api/services/OrderService.client.pb.h"
|
||||
#include "lib/api/public/ServiceContext.h"
|
||||
#include "lib/api/services/OrderService.client.pb.h"
|
||||
using namespace bts::api;
|
||||
ServiceContext ctx;
|
||||
auto orders = ctx.locate<orderman::OrderService>();
|
||||
|
||||
@@ -29,9 +29,9 @@ namespace sample {
|
||||
```
|
||||
|
||||
```cpp
|
||||
#include "spark/api/public/ServiceContext.h"
|
||||
#include "spark/domain_model/Security.h"
|
||||
#include "spark/api/services/MarketDataService.client.pb.h"
|
||||
#include "lib/api/public/ServiceContext.h"
|
||||
#include "spark/lib/domain_model/Security.h"
|
||||
#include "lib/api/services/MarketDataService.client.pb.h"
|
||||
#include <thread>
|
||||
|
||||
using namespace bts::api;
|
||||
|
||||
@@ -53,7 +53,7 @@ The status callback is called when the market for this security opens, closes, o
|
||||
// Subscribe to security trading status
|
||||
void IAlgoServices::subscribe_status(SecurityKey);
|
||||
// You implement
|
||||
virtual void on_status(SecurityKey, co2::TradingStatus) override;
|
||||
virtual void on_status(SecurityKey, domain::protobufs::TradingStatus) override;
|
||||
```
|
||||
|
||||
# Child Orders
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
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
|
||||
-1
Submodule docker/linux deleted from 6537812262.
Submodule docker/windows deleted from de7d40c09d.
+1
-1
Submodule externals updated: 4f6734703c...4f5e385556.
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "6.0.200",
|
||||
"rollForward": "latestMajor"
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,22 @@
|
||||
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
|
||||
numpy==2.2.6
|
||||
platformdirs==2.3.0
|
||||
protobuf==4.21.12
|
||||
pybars3==0.9.7
|
||||
pybind11==2.13.6
|
||||
pybind11-stubgen==2.5.3
|
||||
pybit==5.11.0
|
||||
pycodestyle==2.7.0
|
||||
pycparser==2.20
|
||||
pycryptodome==3.23.0
|
||||
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
|
||||
websocket-client==1.8.0
|
||||
Werkzeug==3.1.3
|
||||
wrapt==1.12.1
|
||||
yapf==0.31.0
|
||||
+103
-164
@@ -1,164 +1,103 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32922.545
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark.Console", "src\client\Spark.Console\Spark.Console.csproj", "{387566C6-C6F6-412C-A30C-9855BBCB4816}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_websocket", "src\client\spark_websocket\spark_websocket.csproj", "{3201359D-C071-4089-9EDE-B04D759F1508}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api_server", "src\client\spark_api_server\spark_api_server.csproj", "{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStreamCore", "src\DataStreamSuite\DataStreamCore\DataStreamCore.csproj", "{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStream", "src\DataStreamSuite\DataStream\DataStream.csproj", "{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedStreams", "src\DataStreamSuite\SharedStreams\SharedStreams.csproj", "{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PubSub", "src\DataStreamSuite\PubSub\PubSub.csproj", "{51C40BA9-F226-4A35-939D-1ED6F5FF7299}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4564E677-343A-46CB-AF02-AFC4E38BF94B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "client", "client", "{56A8A70A-DA03-4CED-A144-EC10F1379FD8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataStreamSuite", "DataStreamSuite", "{915EF238-CA0D-4E73-AF50-88CB3F29C7AD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Extensions.Hosting", "src\DataStreamSuite\Bts.Extensions.Hosting\Bts.Extensions.Hosting.csproj", "{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
MinSizeRel|x64 = MinSizeRel|x64
|
||||
Release|x64 = Release|x64
|
||||
RelWithDebInfo|x64 = RelWithDebInfo|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.Build.0 = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.Build.0 = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.Build.0 = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.ActiveCfg = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.Build.0 = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.ActiveCfg = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.Build.0 = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.Build.0 = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.ActiveCfg = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.Build.0 = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.Release|x64.Build.0 = Release|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {422D1620-0166-4C26-9A81-CA8A2EB1AB58}
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{56A8A70A-DA03-4CED-A144-EC10F1379FD8} = {4564E677-343A-46CB-AF02-AFC4E38BF94B}
|
||||
{915EF238-CA0D-4E73-AF50-88CB3F29C7AD} = {4564E677-343A-46CB-AF02-AFC4E38BF94B}
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460} = {915EF238-CA0D-4E73-AF50-88CB3F29C7AD}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32922.545
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark.Console", "src\client\Spark.Console\Spark.Console.csproj", "{387566C6-C6F6-412C-A30C-9855BBCB4816}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_websocket", "src\client\spark_websocket\spark_websocket.csproj", "{3201359D-C071-4089-9EDE-B04D759F1508}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api_server", "src\client\spark_api_server\spark_api_server.csproj", "{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
MinSizeRel|x64 = MinSizeRel|x64
|
||||
Release|x64 = Release|x64
|
||||
RelWithDebInfo|x64 = RelWithDebInfo|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.Build.0 = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.Build.0 = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.Build.0 = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.ActiveCfg = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.Build.0 = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.ActiveCfg = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.Build.0 = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.Build.0 = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.ActiveCfg = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.Build.0 = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {422D1620-0166-4C26-9A81-CA8A2EB1AB58}
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -6,80 +6,23 @@ using Spark.Core.Collections;
|
||||
|
||||
static class ArgumentComparer {
|
||||
public static int Compare(
|
||||
IArgument value1, IArgument value2, IDictionary<string, object?> env) {
|
||||
IArgument value1, IArgument value2, IDictionary<string,object?> env) {
|
||||
if (value1 is null) {
|
||||
throw new ArgumentNullException(nameof(value1));
|
||||
}
|
||||
if (value2 is null) {
|
||||
throw new ArgumentNullException(nameof(value2));
|
||||
}
|
||||
var obj1 = value1.GetValue(env);
|
||||
var obj2 = value2.GetValue(env);
|
||||
if (obj1 is null) {
|
||||
if (obj2 is null) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (obj2 is null) {
|
||||
return 1;
|
||||
}
|
||||
return compareObjs(obj1, obj2);
|
||||
}
|
||||
|
||||
static int compareObjs(object obj1, object obj2) {
|
||||
var cmp1 = value1.Cast<IComparable>();
|
||||
var cmp2 = value2.Cast<IComparable>();
|
||||
try {
|
||||
var typ1 = obj1.GetType();
|
||||
var typ2 = obj2.GetType();
|
||||
bool areSameTypes = typ1 == typ2;
|
||||
if (areSameTypes) {
|
||||
return ((IComparable)obj1).CompareTo(obj2);
|
||||
}
|
||||
if (typ1.IsNumeric()) {
|
||||
return tryCompareNumeric(obj1, obj2);
|
||||
} else if (typ2.IsNumeric()) {
|
||||
return -tryCompareNumeric(obj2, obj1);
|
||||
} else if (typ1.IsEnum) {
|
||||
if (typ2 == typeof(string)) {
|
||||
return -((string)obj2).CompareTo(obj1.ToString());
|
||||
}
|
||||
} else if (typ1 == typeof(string)) {
|
||||
return ((string)obj1).CompareTo(obj2.ToString());
|
||||
} else if (typ1 == typeof(DateTime)) {
|
||||
if (typ2 == typeof(TimeSpan)) {
|
||||
return ((DateTime)obj1).Ticks.CompareTo(((TimeSpan)obj2).Ticks);
|
||||
}
|
||||
} else if (typ1 == typeof(TimeSpan)) {
|
||||
if (typ2 == typeof(DateTime)) {
|
||||
return ((TimeSpan)obj1).Ticks.CompareTo(((DateTime)obj2).Ticks);
|
||||
}
|
||||
}
|
||||
var v1 = cmp1.GetValue(env);
|
||||
var v2 = cmp2.GetValue(env);
|
||||
return v1.GetType().IsNumeric() ?
|
||||
new NumericComparer().Compare(v1, v2) : v1.CompareTo(v2);
|
||||
} catch (Exception ex) {
|
||||
Log.Ui.error($"Comparison failed: {ex}");
|
||||
throw;
|
||||
}
|
||||
throw new ArgumentException("Failed to compare obj1 and obj2", nameof(obj1));
|
||||
}
|
||||
|
||||
static int tryCompareNumeric(object numericObj1, object obj2) {
|
||||
var typ2 = obj2.GetType();
|
||||
if (typ2.IsNumeric()) {
|
||||
return new NumericComparer().Compare(numericObj1, obj2);
|
||||
} else if (typ2.IsEnum) {
|
||||
var undTyp2 = typ2.GetEnumUnderlyingType();
|
||||
if (undTyp2 == typeof(byte)) {
|
||||
return new NumericComparer().Compare(numericObj1, (byte)obj2);
|
||||
}
|
||||
if (undTyp2 == typeof(short)) {
|
||||
return new NumericComparer().Compare(numericObj1, (short)obj2);
|
||||
}
|
||||
if (undTyp2 == typeof(int)) {
|
||||
return new NumericComparer().Compare(numericObj1, (int)obj2);
|
||||
}
|
||||
if (undTyp2 == typeof(long)) {
|
||||
return new NumericComparer().Compare(numericObj1, (long)obj2);
|
||||
}
|
||||
}
|
||||
throw new ArgumentException("Failed to compare numeric obj1 and obj2", nameof(obj2));
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ Identifier {Letter}({Letter}*[0-9]*_*)*
|
||||
OpenParenthesis \(
|
||||
CloseParenthesis \)
|
||||
Comma ,
|
||||
Negate '!'
|
||||
MapsTo ':'
|
||||
IsOfType '/'
|
||||
|
||||
@@ -93,6 +94,10 @@ IsOfType '/'
|
||||
return (int)Token.COMMA;
|
||||
}
|
||||
|
||||
{Negate} {
|
||||
return (int)Token.NEGATE;
|
||||
}
|
||||
|
||||
{MapsTo} {
|
||||
return (int)Token.MAPS_TO;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
|
||||
<PackageReference Include="YaccLexTools" Version="1.2.3" />
|
||||
<PackageReference Include="YaccLexTools" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,8 +2,6 @@ namespace Bts.BooleanExpressions;
|
||||
|
||||
using Bts.BooleanExpressions.Arguments;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
class BoundBooleanExpression : IBooleanExpression {
|
||||
readonly IBooleanExpression expression;
|
||||
readonly IDictionary<string, FunctionDefinition> definitions;
|
||||
@@ -19,10 +17,10 @@ class BoundBooleanExpression : IBooleanExpression {
|
||||
}
|
||||
|
||||
public bool Evaluate(IDictionary<string, object?> env) {
|
||||
if (identifiers.Count > 0) {
|
||||
env = AggregateDictionary.Create(env, identifiers);
|
||||
foreach (var kv in env) {
|
||||
identifiers[kv.Key] = kv.Value;
|
||||
}
|
||||
env = new EvaluationEnvironment(env, definitions);
|
||||
env = new EvaluationEnvironment(identifiers, definitions);
|
||||
return expression.Evaluate(env);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ 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
|
||||
@@ -58,10 +60,12 @@ 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
|
||||
}
|
||||
|
||||
@@ -349,15 +353,17 @@ namespace QUT.GplexBuffers
|
||||
{
|
||||
FileStream fStrm = (stream as FileStream);
|
||||
if (fStrm != null) FileName = fStrm.Name;
|
||||
NextBlk = BlockReaderFactory.Get(stream);
|
||||
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,
|
||||
@@ -428,19 +434,43 @@ 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;
|
||||
};
|
||||
}
|
||||
|
||||
public static BlockReader Get(Stream stream, int fallbackCodePage = -2)
|
||||
#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 >= 0) // Anything but "guess"
|
||||
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
|
||||
encoding = GuessEncoding(stream);
|
||||
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -458,14 +488,6 @@ 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.
|
||||
@@ -473,150 +495,7 @@ namespace QUT.GplexBuffers
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 // !BYTEMODE
|
||||
}
|
||||
#endif // !NOFILES
|
||||
#endregion Buffer classes
|
||||
@@ -661,6 +540,180 @@ 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1 +1 @@
|
||||
VITE_DATASTREAM_WEBSOCKET_URL=wss://localhost:8443/ws
|
||||
VITE_DATASTREAM_WEBSOCKET_URL=wss://localhost:443
|
||||
@@ -1 +1 @@
|
||||
VITE_DATASTREAM_WEBSOCKET_URL=wss://localhost:8443/ws
|
||||
VITE_DATASTREAM_WEBSOCKET_URL=wss://localhost:443
|
||||
@@ -12,6 +12,18 @@ module.exports = {
|
||||
settings: { react: { version: '18.3.1' } },
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
"import/order": [
|
||||
"error",
|
||||
{
|
||||
"groups": [
|
||||
"builtin",
|
||||
"external",
|
||||
"internal",
|
||||
["parent", "sibling", "index"]
|
||||
],
|
||||
"newlines-between": "always"
|
||||
}
|
||||
],
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-react": "^7.34.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.7",
|
||||
@@ -3178,6 +3179,12 @@
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
|
||||
@@ -3492,6 +3499,26 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/array.prototype.findlastindex": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
|
||||
"integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"es-shim-unscopables": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/array.prototype.flat": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
|
||||
@@ -4306,6 +4333,121 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-node": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
|
||||
"integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^3.2.7",
|
||||
"is-core-module": "^2.13.0",
|
||||
"resolve": "^1.22.4"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-node/node_modules/debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-node/node_modules/resolve": {
|
||||
"version": "1.22.8",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.13.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-module-utils": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz",
|
||||
"integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^3.2.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"eslint": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-module-utils/node_modules/debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
|
||||
"integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.7",
|
||||
"array.prototype.findlastindex": "^1.2.3",
|
||||
"array.prototype.flat": "^1.3.2",
|
||||
"array.prototype.flatmap": "^1.3.2",
|
||||
"debug": "^3.2.7",
|
||||
"doctrine": "^2.1.0",
|
||||
"eslint-import-resolver-node": "^0.3.9",
|
||||
"eslint-module-utils": "^2.8.0",
|
||||
"hasown": "^2.0.0",
|
||||
"is-core-module": "^2.13.1",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^3.1.2",
|
||||
"object.fromentries": "^2.0.7",
|
||||
"object.groupby": "^1.0.1",
|
||||
"object.values": "^1.1.7",
|
||||
"semver": "^6.3.1",
|
||||
"tsconfig-paths": "^3.15.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import/node_modules/debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import/node_modules/doctrine": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esutils": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react": {
|
||||
"version": "7.34.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.2.tgz",
|
||||
@@ -5603,6 +5745,15 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
@@ -5731,6 +5882,20 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object.groupby": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
|
||||
"integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/object.hasown": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz",
|
||||
@@ -6584,6 +6749,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-json-comments": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||
@@ -6677,6 +6851,30 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
|
||||
"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json5": "^0.0.29",
|
||||
"json5": "^1.0.2",
|
||||
"minimist": "^1.2.6",
|
||||
"strip-bom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths/node_modules/json5": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-react": "^7.34.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.7",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { DataGrid } from '@mui/x-data-grid';
|
||||
import './DataGrid.css';
|
||||
import './DataGrid.css'
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
export default function DataTable({ columns, rows }) {
|
||||
@@ -23,7 +23,7 @@ export default function DataTable({ columns, rows }) {
|
||||
headerName: col.name,
|
||||
width: columnWidths[col.name],
|
||||
};
|
||||
};
|
||||
}
|
||||
}, [columnWidths]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -13,7 +13,7 @@ function getGridColDef(col) {
|
||||
export default function ReactDataGrid({columns, rows}) {
|
||||
return (
|
||||
<DataGrid className={"data-grid"} rows={rows} columns={columns.map(getGridColDef)} />
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
ReactDataGrid.propTypes = {
|
||||
|
||||
@@ -3,7 +3,7 @@ import Button from '@mui/material/Button';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import PropTypes from 'prop-types';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import ChevronLeftRounded from "@mui/icons-material/ChevronLeftRounded";
|
||||
import ChevronLeftRounded from "@mui/icons-material/ChevronLeftRounded"
|
||||
import ChevronRightRounded from '@mui/icons-material/ChevronRightRounded';
|
||||
import FileCopyIcon from '@mui/icons-material/FileCopy';
|
||||
import './SideBar.css';
|
||||
@@ -51,7 +51,7 @@ const Sidebar = ({ onSelection, onOpened, onClosed }) => {
|
||||
} catch (error) {
|
||||
console.error('Error fetching WebSocket config:', error);
|
||||
}
|
||||
};
|
||||
}
|
||||
fetchCannedQueries();
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { fileURLToPath, URL } from 'node:url';
|
||||
import { defineConfig } from 'vite';
|
||||
import { defineConfig, loadEnv } from 'vite';
|
||||
import plugin from '@vitejs/plugin-react';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
@@ -29,13 +29,12 @@ if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) {
|
||||
}
|
||||
}
|
||||
|
||||
const target = env.ASPNETCORE_HTTPS_PORT
|
||||
? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}`
|
||||
: env.ASPNETCORE_URLS
|
||||
? env.ASPNETCORE_URLS.split(';')[0]
|
||||
: 'https://localhost:8443';
|
||||
|
||||
export default defineConfig(({ $$command, mode, $$isSsrBuild, $$isPreview }) => {
|
||||
const target = env.ASPNETCORE_HTTPS_PORT
|
||||
? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}`
|
||||
: env.ASPNETCORE_URLS
|
||||
? env.ASPNETCORE_URLS.split(';')[0]
|
||||
: 'https://localhost:8443';
|
||||
return {
|
||||
plugins: [plugin()],
|
||||
resolve: {
|
||||
@@ -52,18 +51,7 @@ export default defineConfig(({ $$command, mode, $$isSsrBuild, $$isPreview }) =>
|
||||
proxy: {
|
||||
'^/api': {
|
||||
target,
|
||||
secure: false,
|
||||
configure: (proxy) => {
|
||||
proxy.on('error', (err) => {
|
||||
console.log('proxy error', err);
|
||||
});
|
||||
proxy.on('proxyReq', (proxyReq, req) => {
|
||||
console.log(`Forwarding ${proxyReq.method} ${proxyReq.protocol}//${proxyReq.host}${proxyReq.path} to ${req.socket.remoteAddress}${req.url}`);
|
||||
});
|
||||
proxy.on('proxyRes', (proxyRes, req, res) => {
|
||||
console.log(`Forwarding response ${req.socket.localAddress} to ${res.socket.remoteAddress}. Status=${proxyRes.statusCode}`);
|
||||
});
|
||||
},
|
||||
secure: false
|
||||
},
|
||||
'^/ws': {
|
||||
target,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
@@ -12,10 +12,10 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="8.0.18" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.18" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="7.0.20" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="7.0.20" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+30
-34
@@ -1,34 +1,30 @@
|
||||
namespace Bts.DataStreamWebApp.Server.Controllers;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
[Route("/ws")]
|
||||
public class DataStreamSubscriptionController : ControllerBase {
|
||||
readonly ILogger logger;
|
||||
readonly IDataStreamFactory streamFactory;
|
||||
|
||||
public DataStreamSubscriptionController(ILogger<DataStreamSubscriptionController> logger, IEnumerable<IDataStreamFactory> streamFactories) {
|
||||
this.logger = logger;
|
||||
logger.LogInformation("Creating {ControllerType}", GetType().Name);
|
||||
streamFactory = DataStreamFactory.Create(streamFactories);
|
||||
}
|
||||
|
||||
[Route("/ws")]
|
||||
public async Task Get(CancellationToken cancellationToken) {
|
||||
if (!HttpContext.WebSockets.IsWebSocketRequest) {
|
||||
logger.LogError("Expected websocket request on path '{}'", HttpContext.Request.Path);
|
||||
return;
|
||||
}
|
||||
logger.LogInformation("Establishing websocket connection...");
|
||||
try {
|
||||
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
||||
logger.LogInformation("Websocket connection established.");
|
||||
using var server = new DataStreamWebSocketServer(webSocket, streamFactory, logger);
|
||||
await server.Run(cancellationToken);
|
||||
} catch (Exception ex) {
|
||||
logger.LogError("DataStreamSubscriptionController.Run threw exception: {Exception}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Bts.DataStreamWebApp.Server.Controllers;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
[Route("/ws")]
|
||||
public class DataStreamSubscriptionController : ControllerBase {
|
||||
readonly ILogger logger;
|
||||
|
||||
public DataStreamSubscriptionController(ILogger<DataStreamSubscriptionController> logger) {
|
||||
this.logger = logger;
|
||||
logger.LogInformation("Creating {ControllerType}", GetType().Name);
|
||||
}
|
||||
|
||||
[Route("/ws")]
|
||||
public async Task Get(CancellationToken cancellationToken) {
|
||||
if (!HttpContext.WebSockets.IsWebSocketRequest) {
|
||||
logger.LogError("Expected websocket request on path '{}'", HttpContext.Request.Path);
|
||||
return;
|
||||
}
|
||||
logger.LogInformation("Establishing websocket connection...");
|
||||
try {
|
||||
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
||||
logger.LogInformation("Websocket connection established.");
|
||||
using var server = new DataStreamWebSocketServer(webSocket, logger);
|
||||
await server.Run(cancellationToken);
|
||||
} catch (Exception ex) {
|
||||
logger.LogError("DataStreamSubscriptionController.Run threw exception: {Exception}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ namespace Bts.DataStreamWebApp.Server.Controllers;
|
||||
|
||||
using bts.websocket_core.json_rpc;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.DataStreamWebApp.Server.Messages;
|
||||
|
||||
using System.Net.WebSockets;
|
||||
@@ -14,11 +13,9 @@ public class DataStreamWebSocketServer : IDisposable, IAsyncDisposable {
|
||||
readonly ILogger logger;
|
||||
readonly WebSocket webSocket;
|
||||
readonly Dictionary<string, DataStreamSubscription> subscriptions = new();
|
||||
readonly IDataStreamFactory streamFactory;
|
||||
|
||||
public DataStreamWebSocketServer(WebSocket webSocket, IDataStreamFactory streamFactory, ILogger logger) {
|
||||
public DataStreamWebSocketServer(WebSocket webSocket, ILogger logger) {
|
||||
this.webSocket = webSocket;
|
||||
this.streamFactory = streamFactory;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@@ -70,7 +67,7 @@ public class DataStreamWebSocketServer : IDisposable, IAsyncDisposable {
|
||||
}
|
||||
var subId = subReq.SubscriptionId ?? throw new InvalidOperationException("SubscriptionId is null (parse false)");
|
||||
disposeSubscription(subId);
|
||||
if (!subReq.ParseQuery(streamFactory, out var vs, out parseErr, out errCode)) {
|
||||
if (!subReq.ParseQuery(out var vs, out parseErr, out errCode)) {
|
||||
logger.LogError("Invalid 'subscribe' request: {Reason}", parseErr);
|
||||
var rpcError = JsonRpcResponse.CreateError<SubscriptionError>(
|
||||
req.Id, new() { Code = (long)errCode, Message = "Failed to parse subscription request", Data = parseErr });
|
||||
|
||||
@@ -7,5 +7,5 @@ ARG CONF_FILE="src/DataStreamSuite/Bts.DataStreamWebApp.Server/spark.conf"
|
||||
RUN dotnet dev-certs https --trust
|
||||
COPY --chown=bts:bts "${SOURCE_DIR}" "bin"
|
||||
COPY --chown=bts:bts "${WEB_ROOT}" "bin/wwwroot"
|
||||
COPY --chown=bts:bts "${CONF_FILE}" ".local/share/DataStream/conf/spark.conf"
|
||||
COPY --chown=bts:bts "${CONF_FILE}" ".local/share/bts/Bts.DataStreamWebApp.Server/conf/spark.conf"
|
||||
WORKDIR "/home/bts/bin"
|
||||
@@ -4,7 +4,6 @@ using BCG;
|
||||
|
||||
using bts.websocket_core.json_rpc;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.DataStreamExpressions;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
@@ -38,12 +37,7 @@ public class SubscribeRequest {
|
||||
return true;
|
||||
}
|
||||
|
||||
internal bool ParseQuery(
|
||||
IDataStreamFactory streamFactory,
|
||||
[NotNullWhen(true)] out ViewStream? stream,
|
||||
[NotNullWhen(false)] out SubscriptionError? error,
|
||||
out ErrorCode errorCode
|
||||
) {
|
||||
internal bool ParseQuery([NotNullWhen(true)] out ViewStream? stream, [NotNullWhen(false)] out SubscriptionError? error, out ErrorCode errorCode) {
|
||||
stream = null;
|
||||
errorCode = ErrorCode.None;
|
||||
error = null;
|
||||
@@ -60,7 +54,7 @@ public class SubscribeRequest {
|
||||
}
|
||||
Exception? exception = null;
|
||||
try {
|
||||
stream = exp.Evaluate(streamFactory) as ViewStream;
|
||||
stream = exp.getView(new Dictionary<string, StatementExpression>(0));
|
||||
} catch (Exception ex) {
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Bts.DataStreamCore.Services;
|
||||
using Bts.PubSub.Services;
|
||||
using Bts.SharedStreams.Services;
|
||||
|
||||
using Spark.Api.Services;
|
||||
using Spark.Core.Services;
|
||||
@@ -79,9 +78,5 @@ static void ConfigureServices(IServiceCollection services, IConfiguration config
|
||||
.AddSparkApi(config.GetSection("SparkApi"))
|
||||
.AddMasterWorker(config.GetSection("MasterWorker"))
|
||||
.AddViewStreamDatabase()
|
||||
.AddPrimitiveStreams(config.GetSection("PrimitiveStreams"))
|
||||
.AddMarketDataStreams()
|
||||
.AddNaturalLanguageStreams(config.GetSection("NaturalLanguageStream"))
|
||||
.AddCompositeDataStreamFactory()
|
||||
.AddPubSubClient(config.GetSection("PubSub"));
|
||||
}
|
||||
@@ -1,4 +1,14 @@
|
||||
{
|
||||
"Kestrel": {
|
||||
"Endpoints": {
|
||||
"Http": {
|
||||
"Url": "http://localhost:8080"
|
||||
},
|
||||
"Https": {
|
||||
"Url": "https://localhost:8443"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PubSub": {
|
||||
"Routing": {
|
||||
"PublisherRoutes": [
|
||||
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
{
|
||||
"NaturalLanguagePrompt": {
|
||||
"prompts": [
|
||||
{
|
||||
"category": "Impact of financial events on the market",
|
||||
"description": "Show how trading metrics (e.g., price movement, volume) are affected by events related to finance (rate announcements, earnings reports, etc.).",
|
||||
"prompt": "Show me the price movement and volume of Crude Oil futures during the 5-minute window following the last 5 OPEC meetings",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "Show me the price movement and volume of Crude Oil futures during the 5-minute window following the last 5 OPEC meetings",
|
||||
"dsl": [
|
||||
"time_idx=EventTimeIndex.OpecMeetings(which: \"last 5\", duration: \"+5min\")",
|
||||
"contract_idx=ActiveFutureContracts(predicate: \"product==CL\")",
|
||||
"Bars(time_index: time_idx, contract_index: contract_idx, fields: [\"price_movement\", \"volume\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"natural_language": "How do OPEC meetings affect the price of Crude futures? Examine the 10 minutes after each meeting this year.",
|
||||
"dsl": [
|
||||
"time_idx=EventTimeIndex.OpecMeetings(duration: \"+10min\", predicate: \"timestamp.year==2024\")",
|
||||
"contract_idx=ActiveFutureContracts(predicate: \"product==CL\")",
|
||||
"Bars(time_index: time_idx, contract_index: contract_idx, fields: [\"price_movement\", \"volume\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"natural_language": "Show me how the SP 500 price moves after FOMC rate announcements that day",
|
||||
"dsl": [
|
||||
"time_idx=EventTimeIndex.FomcRateAnnouncements(which: \"timestamp.year==2024\", duration: \"+10min\")",
|
||||
"contract_idx=ActiveFutureContracts(predicate: \"product==ES\")",
|
||||
"Bars(time_index: time_idx, contract_index: contract_idx, fields: [\"price_movement\", \"volume\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"natural_language": "Analyze the impact of the FED's interest rate hikes in 2022 on the 10-year Treasury yield, focusing on the 2-week period following each hike.",
|
||||
"dsl": [
|
||||
"time_idx=FedInterestRateAnnouncements(predicate: \"timestamp.year==2022 && change_pct>0\", duration: \"+2 weeks\")",
|
||||
"contract_idx=ActiveFutureContracts(predicate: \"product==ZN\")",
|
||||
"Bars(time_index: time_idx, contract_index: contract_idx)"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -30,15 +30,5 @@
|
||||
"benzinga_news"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Spark": {
|
||||
"ConfigServer": "http://sparkd:8000/config"
|
||||
},
|
||||
"SparkApi": {
|
||||
"IsEnabled": true,
|
||||
"Credentials": {
|
||||
"User": "bts",
|
||||
"Password": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -11,14 +11,8 @@
|
||||
"Http": {
|
||||
"Url": "http://0.0.0.0:8080"
|
||||
},
|
||||
"HttpIpv6": {
|
||||
"Url": "http://[::1]:8080"
|
||||
},
|
||||
"Https": {
|
||||
"Url": "https://0.0.0.0:8443"
|
||||
},
|
||||
"HttpsIpv6": {
|
||||
"Url": "https://[::1]:8443"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -28,358 +22,6 @@
|
||||
"ViewStreamDatabase": {
|
||||
"Interval": "00:00:00.1"
|
||||
},
|
||||
"PrimitiveStream": {
|
||||
"Assemblies": [
|
||||
"DataStream.dll",
|
||||
"SharedStreams.dll"
|
||||
],
|
||||
"ExcludedTypes": [
|
||||
"SettlementPriceStream",
|
||||
"OHLCVStream"
|
||||
]
|
||||
},
|
||||
"StreamDatabase": {
|
||||
"Path": "/home/bts/.local/share/bts/silver_pine/store.db",
|
||||
"Query": "select * from metadata"
|
||||
},
|
||||
"NaturalLanguageStream": {
|
||||
"prompts": [
|
||||
{
|
||||
"category": "Settlement",
|
||||
"MulitLineDescription": [
|
||||
"This is a few shot learning example for an NL to DSL. The DSL function in question is Settlement (symbol_or_contract, datetime1). ",
|
||||
"The first argument is a future (like CL, for crude oil) or a specific future contract like crude oil Dec 24 future (CLZ4). ",
|
||||
"The second argument is the date at which the settlement is to be fetched. There is an overloaded function, Settlement ",
|
||||
"(symbol_or_contract, begin_dt, end_dt) which gets the settlements for all dates from begin_dt to end_dt. This will also have ",
|
||||
"datetimes expressed as Today, Yesterday, Last Friday, First Friday of the month, Last Thursday of August etc. You will need to know ",
|
||||
"what Today is, since there will be referecnes to last week, yesterday etc. These examples are assuming Today is 10/11/2024, however ",
|
||||
"you should use the Today's real date"
|
||||
],
|
||||
"prompt": "What was the settlement for SP 500 Future on June 8th?",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "Find Settlement price of the SP500 future on 04/22/2023.",
|
||||
"dsl": "Settlement(\"ES\", 4/22/2023)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Find Settlement price of the Silver Dec 24 Future on 04/22/2023.",
|
||||
"dsl": "Settlement(\"SIZ4\", 4/22/2023)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Find Yesterday's Settlement of the Crude Oil Future.",
|
||||
"dsl": "Settlement(\"CL\", 10/10/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Find today's settlement of the 10 year treasury future.",
|
||||
"dsl": "Settlement(\"ZN\", 10/11/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Find the Settlement of Natural Gas Dec 24 future on the first Friday of Sept.",
|
||||
"dsl": "Settlement(\"NGZ4\", 9/6/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Find the Settlement of WTI Jan 25 future in the first Week of Sept.",
|
||||
"dsl": "Settlement(\"CLF5\", 9/2/2024, 9/6/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Find the Settlement price for the Sp 500 Dec 24 Mar 25 spread for the first two weeks of September.",
|
||||
"dsl": "Settlement(\"ESZ4-ESH5\", 9/14/2024, 9/1/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Find the Settlement of Natural Gas future on the first Friday of Sept.",
|
||||
"dsl": "Settlement(\"NG\", 9/6/2024)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "BBO",
|
||||
"MulitLineDescription": [
|
||||
"This is a few shot learning example for an NL to DSL. The DSL function in question is Bbo(args...). ",
|
||||
"It accepts the following parameters: ",
|
||||
"symbol (a product code such as ZN for 10 year T-Note futures), ",
|
||||
"contract (a specific contract, such as ZNZ4 for the 10 Year T-Note future Dec 2024 exp), ",
|
||||
"venue (name of the exchange, such as CME, NASDAQ, NYSE, NYMEX, DERIBIT etc.), ",
|
||||
"interval (sample frequency of the data), ",
|
||||
"begin and end (inclusive beginning and end of the time window to query, respectively), ",
|
||||
"Arguments are specified by name, for example: Bbo(symbol: \"ZN\", venue: \"CME\", interval: \"PT1M\", begin: \"2024-10-10\", end: \"2024-10-11\"). ",
|
||||
"Depending on the wording of the request, some arguments may be omitted. ",
|
||||
"The begin, end, and interval args should be expressed in iso 8601 format. ",
|
||||
"Interpret dates according to the trading schedule rather than calendar date whenever possible. ",
|
||||
"In some prompts, the time window will be expressed in relative terms (e.g., \"last Monday\", or \"yesterday\") ",
|
||||
"which must be translated to exact dates. To correctly interpret the dsl in the examples, assume the current time is 2024-10-11T12:00-05:00."
|
||||
],
|
||||
"prompt": "Show me bbo for SP 500 futures on Sep 23rd of this year.",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "Get SP500 future bbo from Wednesday.",
|
||||
"dsl": "Bbo(symbol: \"ES\", venue: \"CME\", begin: \"2024-10-08T17:00:00-06:00\", end: \"2024-10-09T16:00:00-06:00\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "Get bbo for 10 year T-Notes in the first minute after the market opened yesterday.",
|
||||
"dsl": "Bbo(symbol: \"ES\", venue: \"CME\", begin: \"2024-10-10T17:00:00-06:00\", end: \"2024-10-10T17:01:00-06:00\", exclusive_end: true)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Retrieve NVIDIA L1 books from Oct 3",
|
||||
"dsl": "Bbo(symbol: \"NVDA\", venue: \"NASDAQ\", begin: \"2024-10-02TT18:00:00-05:00\", end: \"2024-10-03T17:00:00-05:00\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "Show me L1 data for Crude oil futures this week",
|
||||
"dsl": "Bbo(symbol: \"CL\", venue: \"CME\", begin: \"2024-10-06:T17:00:00-06:00\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "Fetch hourly bbo for Gold futures this week",
|
||||
"dsl": "Bbo(symbol: \"GC\", venue: \"CME\", begin: \"2024-10-06:T17:00:00-06:00\", interval: \"PT1H\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "What was the minute by minute bbo for Tesla yesterday?",
|
||||
"dsl": "Bbo(symbol: \"TSLA\", venue: \"NASDAQ\", begin: \"2024-10-09T18:00:00-05:00\", end: \"2024-10-10T17:00:00-05:00\", interval: \"PT1M\")"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Order flow imbalance",
|
||||
"MulitLineDescription": [
|
||||
"This is a few shot learning example for an NL to DSL. The DSL function in question is OrderImbalance(args...). ",
|
||||
"It accepts the following parameters: ",
|
||||
"symbol (a product code such as ZN for 10 year T-Note futures), ",
|
||||
"contract (a specific contract, such as ZNZ4 for the 10 Year T-Note future Dec 2024 exp), ",
|
||||
"venue (name of the exchange, such as CME, NASDAQ, NYSE, NYMEX, DERIBIT etc.), ",
|
||||
"interval (sample frequency of the data), ",
|
||||
"levels (the number of price levels to examine)",
|
||||
"begin and end (inclusive beginning and end of the time window to query, respectively), ",
|
||||
"inclusive_end (a bool flag that, when true, makes the end time inclusive). ",
|
||||
"Arguments are specified by name, for example: OrderImbalance(symbol: \"ZN\", venue: \"CME\", interval: \"PT1M\", begin: \"2024-10-10\", end: \"2024-10-11\"). ",
|
||||
"Depending on the wording of the request, some arguments may be omitted. ",
|
||||
"The begin, end, and interval args should be expressed in iso 8601 format. ",
|
||||
"Interpret dates according to the trading schedule rather than calendar date whenever possible. ",
|
||||
"In some prompts, the time window will be expressed in relative terms (e.g., \"last Monday\", or \"yesterday\") ",
|
||||
"which must be translated to exact dates. To correctly interpret the dsl in the examples, assume the current time is 2024-10-11T12:00-05:00."
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "Get SP500 order imbalance from Wednesday.",
|
||||
"dsl": "OrderImbalance(symbol: \"ES\", venue: \"CME\", begin: \"2024-10-08T17:00:00-06:00\", end: \"2024-10-09T16:00:00-06:00\", \"PT1M\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "Get SP500 order imbalance from Wednesday for the top 5 price levels.",
|
||||
"dsl": "OrderImbalance(symbol: \"ES\", venue: \"CME\", begin: \"2024-10-08T17:00:00-06:00\", end: \"2024-10-09T16:00:00-06:00\", levels: 5, interval: \"PT1M\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "Get orderflow imbalance for 10 year T-Notes in the first minute after the market opened yesterday.",
|
||||
"dsl": "OrderImbalance(symbol: \"ES\", venue: \"CME\", begin: \"2024-10-10T17:00:00-06:00\", end: \"2024-10-10T17:01:00-06:00\", interval: \"PT1S\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "Retrieve NVIDIA order flow from Oct 3",
|
||||
"dsl": "OrderImbalance(symbol: \"NVDA\", venue: \"NASDAQ\", begin: \"2024-10-02TT18:00:00-05:00\", end: \"2024-10-03T17:00:00-05:00\", interval: \"PT1S\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "Show me order imbalance for Crude oil futures this week",
|
||||
"dsl": "OrderImbalance(symbol: \"CL\", venue: \"CME\", begin: \"2024-10-06:T17:00:00-06:00\", interval: \"PT1H\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "Fetch hourly orderflow for Gold futures this week",
|
||||
"dsl": "OrderImbalance(symbol: \"GC\", venue: \"CME\", begin: \"2024-10-06:T17:00:00-06:00\", interval: \"PT1H\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "What was the minute by minute orderflow for Tesla yesterday?",
|
||||
"dsl": "OrderImbalance(symbol: \"TSLA\", venue: \"NASDAQ\", begin: \"2024-10-09T18:00:00-05:00\", end: \"2024-10-10T17:00:00-05:00\", interval: \"PT1M\")"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "VWAP",
|
||||
"description": "This is a few shot learning example for an NL to DSL. The DSL function in question is VWAP (symbol_or_contract, datetime1, datetime2). The first argument is a future (like CL, for crude oil, or ES for SP 500) or a specific future contract like crude oil Dec 24 future (CLZ4) or SP 500 Dec 2024 (ESZ4). The second argument is where the VWAP has to be calculated (also the beginning of the time window), and the third argument is datetime specifying the end of the time window. So, for example, a 20-day VWAP on 9/30/2023, the first argument will be 9/30/2023, and the third argument will be 9/10/2023 (20 days prior). This will also have datetimes expressed as Today, Yesterday, Last Friday, Last Sunday, etc. For the purpose of this few-shot prompts, let's assume today is 10/11/2024.",
|
||||
"prompt": "What was the VWAP for SP 500 Future over the past 30 days?",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "Find the 20 day VWAP of the SP future on 04/22/2023.",
|
||||
"dsl": "VWAP(\"ES\", 4/22/2023, 4/02/2023)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Find Yesterday's 10 day VWAP of the Crude Oil Future.",
|
||||
"dsl": "VWAP(\"CL\", 10/10/2024, 10/1/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Find today's 30-day VWAP of the 10 year treasury future.",
|
||||
"dsl": "VWAP(\"ZN\", 10/11/2024, 9/11/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Find the 10 hour VWAP of the Natural Gas future from yesterday at 5:00 PM.",
|
||||
"dsl": "VWAP(\"NG\", 9/27/2024 17:00:00, 9/27/2024 7:00:00)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Price Diff",
|
||||
"description": "This is a few shot learning example for an NL to DSL. The DSL function in question is OHLCVPriceDiff (symbol_or_contract, datetime1, datetime2). The first argument is a future (like CL, for crude oil) or a specific future contract like crude oil Dec 24 future (CLZ4). The second and third arguments are dates, that the function finds the difference of prices at. Assume today is 10/15/2024",
|
||||
"prompt": "What is the difference in SP 500 Future from July 10th to July 14th?",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "What is the difference in ZN price from July 10th to July 14th?",
|
||||
"dsl": "OHLCVPriceDiff(\"ZN\", 7/14/2024, 7/10/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "What is the price difference in SP Future price from Sept 10th and Sept 5th?",
|
||||
"dsl": "OHLCVPriceDiff(\"ES\", 9/10/2024, 9/5/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "What is the price difference in Natural Gas Dec Future price from Aug 30th and Aug 20th?",
|
||||
"dsl": "OHLCVPriceDiff(\"NGZ4\", 8/30/2024, 8/20/2024)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Absolute Volume",
|
||||
"description": "this is a few shot learning example for an NL to DSL. The DSL function in question is AbsVolume(symbol, ContractType, datetime1, datetime2), which computes the highest volume in the date range, specified by datetime1, and datetime2. The first argument is a future symbol (like CL for crude oil, ES for SP 500 etc). The second argument is the ContractType, which is \"Future\" for futures and \"FutureSpread\" for future spreads. the 3rd argument is the begin date and the 4th argument is the end date, between which the max volume is computed. If no future is specified use \"*\" from the first arugment. For this prompt, assume today is 10/11/2024 ",
|
||||
"prompt": "Which SP 500 Future traded the most between 7/14/2024 and 7/10/2024",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "Which SP Future traded the most between 7/14/2024 and 7/10/2024",
|
||||
"dsl": "AbsVolume(\"ES\", \"Future\", 7/14/2024, 7/10/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Which Gold Spread traded the most between Today and Sept 20th",
|
||||
"dsl": "AbsVolume(\"GC\", \"FutureSpread\", 10/1/2024, 9/20/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Which 10 year Spread traded the highest volume last week?",
|
||||
"dsl": "AbsVolume(\"ZN\", \"FutureSpread\", 9/27/2024, 9/23/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Which Corn Spread traded the most today?",
|
||||
"dsl": "AbsVolume(\"ZC\", \"FutureSpread\", 10/1/2024, 10/1/2024)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Which Gold Future traded the most today?",
|
||||
"dsl": "AbsVolume(\"GC\", \"Future\", 9/30/2024, 9/30/2024)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Roll",
|
||||
"description": "This is a few shot learning example for an NL to DSL. The DSL function in question is FuturesRoll(symbol) which computes the rollover date for a future, ie when the highest volume swtches from one expiration to the next one. ",
|
||||
"prompt": "When does the roll typically occur In SP 500?",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "When does the roll typically occur In CL?",
|
||||
"dsl": "FuturesRoll(\"CL\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "When does the roll typically occur for 10 year treasury?",
|
||||
"dsl": "FuturesRoll(\"ZN\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "When does the roll usually occur for Gold Future",
|
||||
"dsl": "FuturesRoll(\"GC\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "At what date does the future rollover happens for SP500?",
|
||||
"dsl": "FuturesRoll(\"ES\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "When does the future rollover happens for the Corn Future?",
|
||||
"dsl": "FuturesRoll(\"ZC\")"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Daily Move",
|
||||
"description": "This is a few shot learning example for an NL to DSL. ",
|
||||
"prompt": "How often did Sp 500 Future settle + or - 10% over the previous day?",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "List all the days when the SP 500 closed + or -5% from the previous day's close",
|
||||
"dsl": "ColDiff(filteredOHLCV(\"ES\"),\"ts_event\", -1, \"close\", \"close\", \"close_diff\", 5)"
|
||||
},
|
||||
{
|
||||
"natural_language": "List all the days when the Crude Oil closed + or -2.5% from the previous day's close",
|
||||
"dsl": "ColDiff(filteredOHLCV(\"CL\"),\"ts_event\", -1, \"close\", \"close\", \"close_diff\", 2.5)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Show me all the days when the Ten year Treaury Future opened + or -1% from the previous day's open",
|
||||
"dsl": "ColDiff(filteredOHLCV(\"ZN\"),\"ts_event\", -1, \"open\", \"open\", \"open_diff\", 1.0)"
|
||||
},
|
||||
{
|
||||
"natural_language": "List all the trading days when the Silver Future opened + or -1% from the previous day's close",
|
||||
"dsl": "ColDiff(filteredOHLCV(\"SI\"),\"ts_event\", -1, \"open\", \"open\", \"open_diff\", 1.0)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Average Volume",
|
||||
"description": "This is a few shot learning example for an NL to DSL. For the purpose of this few shot prompts, lets assume today is 10/3/2024 ",
|
||||
"prompt": "When does the most open interest typically shift from one contract to another in SP 500 Future?",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "When does the most open interest typically shift from one contract to another in e-minis? ",
|
||||
"dsl": "FuturesRoll(\"ES\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "Usually when does the open interest move from one contract to another in WTI?",
|
||||
"dsl": "FuturesRoll(\"CL\")"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Events",
|
||||
"description": "This is a few shot learning example for an NL to DSL. In the NL prompt the user is asking to show the price of a future (treasury future, or SP 500 future etc) around an event type. The event type could be \"FOMC Announcement\" or \"Storage numbers\" etc. The DSL is as follows: EventsPriceAction(future_name, event_type, pre_event_window, post_event_window, number_of_events) first arg is the name of the future, (ex ES or ZN etc), the second argument is the event type, for example, \"FOMC announcement\", the 3rd argument is a time window for how much pre-event data to include in the end result, the 4th argument is how much post-event data to include in the end result. Both are strings of the form \"5d\" for 5 days, \"5h\" for 5 hours and \"120m\" for 120 minutes and so on. Usually, only one of the event periods is provided. Set the other to be half of what the user provided. The last argument is the number of events to consider. So if it’s 7, that means the most recent 7 events. If the user does not specify that, pass a large number.",
|
||||
"prompt": "What did the volume and price of SP500 Future do following the release of the last 10 FOMC rates?",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "How did SP 500 Future do in the 5 days following the FOMC announcements?",
|
||||
"dsl": "EventsPriceAction(\"ES\", \"FOMC Announcement\", \"2d\", \"5d\", 10)"
|
||||
},
|
||||
{
|
||||
"natural_language": "How did the price of Treasury Future evolve in the 2 days following the Job Reports?",
|
||||
"dsl": "EventsPriceAction(\"ZN\", \"Job Reports\", \"1d\", \"2d\", 10)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Show me the price movement and volume of Crude Oil futures during the 5-minute window following the last 5 OPEC meetings.",
|
||||
"dsl": "EventsPriceAction(\"CL\", \"OPEC Meeting\", \"2m\", \"5m\", 5)"
|
||||
},
|
||||
{
|
||||
"natural_language": "Show me the price movement and volume of SP 500 futures preceding the 10-minute window of the last 5 OPEC meetings.",
|
||||
"dsl": "EventsPriceAction(\"CL\", \"OPEC Meeting\", \"10m\", \"5m\", 5)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Indicator, Standard Deviation",
|
||||
"MulitLineDescription": [
|
||||
"This is a few shot learning example for an NL to DSL. In the NL prompt the user is asking to show all the days when ",
|
||||
"the price of a future (treasury future, or SP 500 future etc) moved more than m times the N days standard deviation, ",
|
||||
"where both m and N are provided. For example, the DSL for \"Using a 90d standard deviation, give me the dates and ",
|
||||
"amounts of the last 4+ standard deviation moves in WTI futures\" would be: ",
|
||||
"r=standardDeviation(\"ES\", \"90d\")\n",
|
||||
"r=math(r, \"abs_daily_change = Abs(close - open) comp = std_dev * 4\")\n",
|
||||
"r=filter(r,\"abs_daily_change >= comp\"). ",
|
||||
"The first line, creates a stream for StandardDeviation, based on the number of days, for example 90d standard deviation, ",
|
||||
"and assigned it to r, the second line takes r from the first line and passes it to a math stream that creates 2 new columns, ",
|
||||
"abs_daily_change and comp. comp is the factor (4, from 4+ in the prompt) times standard deviation. The third line filters ",
|
||||
"(like a sql where) of rows where abs_daily_change >= comp"
|
||||
],
|
||||
"prompt": "Using a 90d standard deviation, give me the dates and amounts of the last 1+ standard deviation moves in SP futures ?",
|
||||
"examples": [
|
||||
{
|
||||
"natural_language": "Using a 90d standard deviation, give me the dates and amounts of the last 1+ standard deviation moves in WTI futures ?",
|
||||
"dsl": "r=standardDeviation(\"CL\", \"90d\")\nr=math(r, \"abs_daily_change = Abs(close - open) comp = std_dev * 1.0\")\nr=filter(r,\"abs_daily_change >= comp\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "Show me the times the SP Futures moved twice the 60 day standard deviation",
|
||||
"dsl": "r=standardDeviation(\"ES\", \"60d\")\nr=math(r, \"abs_daily_change = Abs(close - open) comp = std_dev * 2.0\")\nr=filter(r,\"abs_daily_change >= comp\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "List all the days the Gold Futures moved 1.5 times the 45 day standard deviation",
|
||||
"dsl": "r=standardDeviation(\"GC\", \"45d\")\nr=math(r, \"abs_daily_change = Abs(close - open) comp = std_dev * 1.5\")\nr=filter(r,\"abs_daily_change >= comp\")"
|
||||
},
|
||||
{
|
||||
"natural_language": "List all the days the 10 year treasury future moved more than twice the 1 month standard deviation",
|
||||
"dsl": "r=standardDeviation(\"ZN\", \"30d\")\nr=math(r, \"abs_daily_change = Abs(close - open) comp = std_dev * 2.0\")\nr=filter(r,\"abs_daily_change >= comp\")"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"SparkApi": {
|
||||
"IsEnabled": false,
|
||||
"Credentials": {
|
||||
@@ -435,7 +77,7 @@
|
||||
{
|
||||
"TagType": ".*",
|
||||
"Assembly": "DataStreamCore",
|
||||
"Class": "bts.PubsubServerGenericDataHandler"
|
||||
"Class": "bts.PubsubServerGenericDataHandler"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -3,12 +3,15 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
public static class HostBuilderExtensions {
|
||||
public static IHostBuilder CreateBtsBuilder(string[] args) {
|
||||
// The calling assembly's name serves as the "appsettings" json file prefix.
|
||||
// Obtain calling assembly name here, rather than in the lambda where it is actually needed,
|
||||
// because want the name of the assembly that called this function, not the assembly that will eventually invoke
|
||||
// the lambda...that will be the Microsoft.Extensions.Hosting assembly.
|
||||
// Get the name of the assembly that called this function. That will act as the "appsettings"
|
||||
// json file prefix
|
||||
var exeName = GetCallingAssemblyName();
|
||||
return Host.CreateDefaultBuilder(args)
|
||||
.ConfigureAppConfiguration((context, configBuilder) =>
|
||||
@@ -53,21 +56,4 @@ public static class HostBuilderExtensions {
|
||||
?.GetName()
|
||||
?.Name
|
||||
?? throw new InvalidOperationException("Failed to determine name of calling assembly (calling method is null)");
|
||||
|
||||
/// <summary>
|
||||
/// Separates command line args from config args, using '--' as the delimiter. Args
|
||||
/// before the delimiter are considered command line args, while those after it are
|
||||
/// config args.
|
||||
/// </summary>
|
||||
public static (string[] Args, string[] ConfigArgs) SplitConfigArgs(string[] args) {
|
||||
int splitIdx = Array.IndexOf(args, "--");
|
||||
if (splitIdx == -1) {
|
||||
return (args, Array.Empty<string>());
|
||||
}
|
||||
var cfgArgs = new string[args.Length - splitIdx - 1];
|
||||
Array.Copy(args, splitIdx + 1, cfgArgs, 0, cfgArgs.Length);
|
||||
var nonCfgArgs = new string[args.Length - cfgArgs.Length - 1];
|
||||
Array.Copy(args, 0, nonCfgArgs, 0, nonCfgArgs.Length);
|
||||
return (nonCfgArgs, cfgArgs);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
public class AddColumnRow : IBlueRow {
|
||||
readonly IBlueRow inputRow;
|
||||
readonly IBlueTableSchema outputSchema;
|
||||
readonly object? value;
|
||||
readonly int valueIndex;
|
||||
|
||||
public AddColumnRow(IBlueRow inputRow, IBlueTableSchema outputSchema, object? value, int valueIndex) {
|
||||
this.inputRow = inputRow;
|
||||
this.outputSchema = outputSchema;
|
||||
this.value = value;
|
||||
this.valueIndex = valueIndex;
|
||||
}
|
||||
|
||||
public object? this[int index] {
|
||||
get {
|
||||
if (index == valueIndex) {
|
||||
return value;
|
||||
}
|
||||
if (index >= valueIndex) {
|
||||
index--;
|
||||
}
|
||||
return inputRow[index];
|
||||
}
|
||||
}
|
||||
|
||||
IBlueTableSchema IBlueRow.schema => outputSchema;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class AddColumnTable : IBlueRowCollection {
|
||||
readonly IBlueRowCollection inputRows;
|
||||
readonly Func<IBlueRow, object?> getValue;
|
||||
readonly IBlueTableSchema outputSchema;
|
||||
readonly int valueIndex;
|
||||
|
||||
public AddColumnTable(IBlueRowCollection inputRows, string columnName, Type columnType, Func<IBlueRow, object?> getValue) {
|
||||
this.inputRows = inputRows;
|
||||
this.getValue = getValue;
|
||||
var inputCols = inputRows.schema.columnInfo;
|
||||
var outputCols = new ColumnInfo[inputCols.Length + 1];
|
||||
Array.Copy(inputCols, outputCols, inputCols.Length);
|
||||
outputCols[^1] = new(columnName, inputCols.Length, columnType);
|
||||
outputSchema = new BlueTableSchema(outputCols, "AddColumnTable");
|
||||
valueIndex = inputCols.Length;
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] {
|
||||
get {
|
||||
var r = inputRows[id];
|
||||
return new AddColumnRow(r, outputSchema, getValue(r), valueIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueTableSchema schema => outputSchema;
|
||||
|
||||
public int Count => inputRows.Count;
|
||||
|
||||
public bool containsID(int id) =>
|
||||
inputRows.containsID(id);
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
foreach (var r in inputRows) {
|
||||
yield return new AddColumnRow(r, outputSchema, getValue(r), valueIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) {
|
||||
var r = inputRows.GetRow(index);
|
||||
return new AddColumnRow(r, outputSchema, getValue(r), valueIndex);
|
||||
}
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int id = item.Id();
|
||||
if (!inputRows.containsID(id)) {
|
||||
return -1;
|
||||
}
|
||||
var r = inputRows[id];
|
||||
return BlueRowEqualityComparer.Equals(new AddColumnRow(r, outputSchema, getValue(r), valueIndex), item)
|
||||
? inputRows.IndexOf(r)
|
||||
: -1;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
|
||||
[DataStreamUserRespresentation("AddColumnsStream")]
|
||||
public class AddColumnsStream: ViewStream {
|
||||
public AddColumnsStream(ViewStream parent_str, string add_col_expr) {
|
||||
ViewStream rs = new BCG.AddColumnsStream(parent_str, add_col_expr);
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
#nullable enable
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
|
||||
public class ApplyStream : ViewStream {
|
||||
readonly ViewStream source;
|
||||
readonly Func<IBlueRow, object?> apply;
|
||||
IBlueTableSchema? outputSchema;
|
||||
BlueTableImmutable? lastFired;
|
||||
IDisposable? sub;
|
||||
|
||||
public ApplyStream(ViewStream source, IFunctionEvaluator applyEvaluator) {
|
||||
this.source = source;
|
||||
apply = Apply;
|
||||
|
||||
object? Apply(IBlueRow r) {
|
||||
var res = applyEvaluator.Evaluate(string.Empty, new StreamArgument[] { (null, 0, r) });
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
public ApplyStream(ViewStream source, Func<IBlueRow, object?> apply) {
|
||||
this.source = source;
|
||||
this.apply = apply;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
sub = source.Subscribe(OnSourceChanged);
|
||||
|
||||
void OnSourceChanged(IDataPacket dp) {
|
||||
Lazy<BlueTableImmutable> lastFired = new(() => this.lastFired ??= new(Log.notnull(outputSchema)));
|
||||
Lazy<BlueTableImmutable.DataPacketBuilder> bd = new(() => lastFired.Value.ToDataPacketBuilder());
|
||||
|
||||
foreach (var r in dp.deletedRows) {
|
||||
var res = apply(r);
|
||||
if (res is IBlueRow blueRow) {
|
||||
bd.Value.Remove(blueRow.Id());
|
||||
} else if (res is IBlueRowCollection blueRows) {
|
||||
foreach (var br in blueRows) {
|
||||
bd.Value.Remove(br.Id());
|
||||
}
|
||||
} else {
|
||||
Log.assert(false, $"apply delegate returned obj of unexpected type '{res?.GetType()}'");
|
||||
}
|
||||
}
|
||||
foreach (var r in dp.addedRows) {
|
||||
var res = apply(r);
|
||||
if (res is IBlueRow blueRow) {
|
||||
outputSchema ??= blueRow.schema;
|
||||
bd.Value.AddOrUpdate(blueRow);
|
||||
} else if (res is IBlueRowCollection blueRows) {
|
||||
outputSchema ??= blueRows.schema;
|
||||
foreach (var br in blueRows) {
|
||||
bd.Value.AddOrUpdate(br);
|
||||
}
|
||||
} else {
|
||||
if (outputSchema is null) {
|
||||
// We get the outputSchema from the result of the first apply, if it's null, we
|
||||
// cannot determine the output data type.
|
||||
// TODO: maybe support specifying return type in DSL?
|
||||
Log.notnull(res);
|
||||
}
|
||||
var resType = res?.GetType();
|
||||
if (outputSchema is null) {
|
||||
Log.notnull(resType);
|
||||
Log.assert(ColumnInfo.isAllowedType(resType));
|
||||
outputSchema = new BlueTableSchema(new ColumnInfo[] {
|
||||
new("id", 0, typeof(int)),
|
||||
new("result", 1, resType),
|
||||
}, dp.newRows.schema.tableName + "_Apply");
|
||||
}
|
||||
bd.Value.AddOrUpdate(new BlueRow(outputSchema, new object?[] { r.Id(), res }));
|
||||
// Log.assert(false, $"apply delegate returned obj of unexpected type '{res?.GetType()}'");
|
||||
}
|
||||
}
|
||||
if (bd.IsValueCreated) {
|
||||
myFireEvent(bd.Value.ToDataPacket(out this.lastFired));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
Disposable.dispose(ref sub);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class ApplyTable : IBlueRowCollection {
|
||||
readonly IBlueRowCollection source;
|
||||
readonly IBlueTableSchema outputSchema;
|
||||
readonly List<IBlueRow> outputRows;
|
||||
readonly Dictionary<int, int> idToIndex = new();
|
||||
readonly Func<IBlueRow, IBlueRow> applyFn;
|
||||
|
||||
public ApplyTable(IBlueRowCollection source, IBlueTableSchema? outputSchema, Func<IBlueRow, IBlueRow> applyFn) {
|
||||
this.source = source;
|
||||
this.applyFn = applyFn;
|
||||
outputRows = new(source.Count);
|
||||
foreach (var r in source) {
|
||||
outputRows.Add(applyFn(r));
|
||||
}
|
||||
if (outputRows.Count > 0) {
|
||||
outputSchema ??= outputRows[0].schema;
|
||||
}
|
||||
this.outputSchema = outputSchema ?? source.schema;
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] => outputRows[idToIndex[id]];
|
||||
|
||||
IBlueRow IList<IBlueRow>.this[int index] {
|
||||
get => GetRow(index);
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public IBlueTableSchema schema => outputSchema;
|
||||
|
||||
public int Count => source.Count;
|
||||
|
||||
public bool containsID(int id) =>
|
||||
source.containsID(id);
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() =>
|
||||
outputRows.GetEnumerator();
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
outputRows[index];
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int id = item.Id();
|
||||
if (!source.containsID(id)) {
|
||||
return -1;
|
||||
}
|
||||
var inputRow = source[id];
|
||||
int idx = source.IndexOf(inputRow);
|
||||
if (BlueRowEqualityComparer.Equals(outputRows[idx], item)) {
|
||||
return idx;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
namespace Bts.DataStream.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.PubSub;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public static class AsyncViewStream {
|
||||
public static ViewStream Create(IWorkScheduler workScheduler, Func<Task<ViewStream?>> factory) {
|
||||
return ViewStreamFactory.Create(Subscribe);
|
||||
|
||||
IDisposable Subscribe(Action<IDataPacket> fire) {
|
||||
var cts = new CancellationTokenSource();
|
||||
var tcs = new TaskCompletionSource<IDisposable>();
|
||||
var syncRoot = new object();
|
||||
IDisposable? streamSub = null;
|
||||
workScheduler.Post(Init);
|
||||
return Disposable.Create(Dispose);
|
||||
|
||||
async void Init() {
|
||||
lock (syncRoot) {
|
||||
if (cts.IsCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var stream = await factory();
|
||||
if (stream is null) {
|
||||
return;
|
||||
}
|
||||
var tempStreamSub = stream.Subscribe(fire);
|
||||
lock (syncRoot) {
|
||||
if (cts.IsCancellationRequested) {
|
||||
tempStreamSub.Dispose();
|
||||
} else {
|
||||
streamSub = tempStreamSub;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dispose() {
|
||||
IDisposable? tempStreamSub;
|
||||
lock (syncRoot) {
|
||||
tempStreamSub = streamSub;
|
||||
if (tempStreamSub is null) {
|
||||
cts.Cancel();
|
||||
return;
|
||||
}
|
||||
streamSub = null;
|
||||
}
|
||||
tempStreamSub?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.collections;
|
||||
using bts.utils;
|
||||
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class BlueAddIndexColumnTable : IBlueRowCollection {
|
||||
readonly IBlueTableSchema schema;
|
||||
readonly IList<object?>[] columnValues;
|
||||
readonly int count;
|
||||
|
||||
BlueAddIndexColumnTable(IBlueTableSchema schema, IList<object?>[] columnValues, int? count = null) {
|
||||
this.schema = schema;
|
||||
this.columnValues = columnValues;
|
||||
this.count = count ?? columnValues[0].Count;
|
||||
}
|
||||
|
||||
IBlueTableSchema IBlueRowCollection.schema => schema;
|
||||
|
||||
public int Count => count;
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
id > 0 && id <= count
|
||||
? GetRow(id - 1)
|
||||
: throw new KeyNotFoundException();
|
||||
|
||||
public static BlueAddIndexColumnTable Create(string tableName, ColumnInfo[] columnInfos, IList<object?>[] columnValues) {
|
||||
if (columnInfos.Any(c => c.colName == "id")) {
|
||||
throw new ArgumentException("'id' column already exists", nameof(columnInfos));
|
||||
}
|
||||
if (columnInfos.Length != columnValues.Length) {
|
||||
throw new ArgumentException("columnValues length differs from columnInfos length", nameof(columnValues));
|
||||
}
|
||||
int count = columnValues.FirstOrDefault()?.Count ?? 0;
|
||||
var origCols = columnInfos;
|
||||
var origColValues = columnValues;
|
||||
columnInfos = new ColumnInfo[origCols.Length + 1];
|
||||
columnInfos[0] = new ColumnInfo("id", 0, typeof(int));
|
||||
columnValues = new IList<object?>[origCols.Length + 1];
|
||||
columnValues[0] = new StepList<int>(1, 1, count).WrapSelector(id => (object?)id, null);
|
||||
for (int i = 1; i < columnInfos.Length; i++) {
|
||||
columnInfos[i] = new ColumnInfo(origCols[i - 1].colName, i, origCols[i - 1].colType);
|
||||
columnValues[i] = origColValues[i - 1];
|
||||
}
|
||||
var schema = new BlueTableSchema(columnInfos, tableName);
|
||||
return new(schema, columnValues, count);
|
||||
}
|
||||
|
||||
public static BlueAddIndexColumnTable Create(IBlueTableSchema schema, IList<object?>[] columnValues) {
|
||||
int count = columnValues.FirstOrDefault()?.Count ?? 0;
|
||||
int? idColIdx = schema.TryResolveIndices("id");
|
||||
var idColValues = new StepList<int>(1, 1, count).WrapSelector(id => (object?)id, null);
|
||||
var columnInfos = schema.columnInfo;
|
||||
if (idColIdx.HasValue) {
|
||||
// Replace existing id column. columnValues may or may not contain the old ids (if its
|
||||
// length is one less column than that of columnInfos, it doesn't contain them).
|
||||
switch (columnValues.Length - schema.columnInfo.Length) {
|
||||
case 0:
|
||||
columnValues[idColIdx.Value] = idColValues;
|
||||
break;
|
||||
case -1:
|
||||
columnValues = ArrayUtils.InsertExact(columnValues, idColIdx.Value, true, idColValues);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("ColumnInfos length disagrees with columnValues length");
|
||||
}
|
||||
} else {
|
||||
if (columnValues.Length != columnInfos.Length) {
|
||||
throw new ArgumentException("ColumnInfos length disagrees with columnValues length");
|
||||
}
|
||||
var origColInfos = columnInfos;
|
||||
columnInfos = new ColumnInfo[columnInfos.Length + 1];
|
||||
columnInfos[0] = new("id", 0, typeof(int));
|
||||
for (int i = 1; i < columnInfos.Length; i++) {
|
||||
var c = origColInfos[i - 1];
|
||||
columnInfos[i] = new(c.colName, c.colNo + 1, c.colType);
|
||||
}
|
||||
columnValues = ArrayUtils.InsertExact(columnValues, 0, true, idColValues);
|
||||
}
|
||||
return new(new BlueTableSchema(schema.tableName, columnInfos), columnValues);
|
||||
}
|
||||
|
||||
public bool containsID(int id) =>
|
||||
id > 0 && id <= count;
|
||||
|
||||
public IList<object?> GetColumn(int index) =>
|
||||
columnValues[index];
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
new BlueRowColumnWrapper(schema, index, columnValues);
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int id = item.Id();
|
||||
return id > 0 && id <= count && BlueRowEqualityComparer.Equals(GetRow(id - 1), item)
|
||||
? id - 1
|
||||
: -1;
|
||||
}
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
int count = Count;
|
||||
for (int i = 0; i < count; i++) {
|
||||
yield return GetRow(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class BlueRowColumnWrapper : IBlueRow {
|
||||
readonly int index;
|
||||
readonly IList<object?>[] columns;
|
||||
|
||||
public BlueRowColumnWrapper(IBlueTableSchema schema, int index, IList<object?>[] columns) {
|
||||
this.schema = schema;
|
||||
this.index = index;
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public object? this[int index] =>
|
||||
columns[index][this.index];
|
||||
|
||||
public IBlueTableSchema schema { get; }
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class BlueIndexedColumnTable : IBlueRowCollection {
|
||||
readonly IBlueTableSchema schema;
|
||||
readonly IList<object?>[] columnValues;
|
||||
readonly Dictionary<int, int> rowIdToIndex;
|
||||
|
||||
public BlueIndexedColumnTable(IBlueTableSchema schema, IList<object?>[] columnValues) {
|
||||
this.schema = schema;
|
||||
this.columnValues = columnValues;
|
||||
int idColumnIndex = schema.ResolveIndices("id");
|
||||
rowIdToIndex = columnValues[idColumnIndex]
|
||||
.Select((idObj, idx) => new KeyValuePair<int, int>(ExceptionAssert.Argument.Is<int>(idObj), idx))
|
||||
.ToDictionary();
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
rowIdToIndex.TryGetValue(id, out var idx)
|
||||
? GetRow(idx)
|
||||
: throw new KeyNotFoundException();
|
||||
|
||||
IBlueTableSchema IBlueRowCollection.schema => schema;
|
||||
|
||||
public int Count => rowIdToIndex.Count;
|
||||
|
||||
public bool containsID(int id) =>
|
||||
rowIdToIndex.ContainsKey(id);
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
int count = Count;
|
||||
for (int i = 0; i < count; i++) {
|
||||
yield return GetRow(i);
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
new BlueRowColumnWrapper(schema, index, columnValues);
|
||||
|
||||
public int IndexOf(IBlueRow item) =>
|
||||
rowIdToIndex.TryGetValue(item.Id(), out var idx) && BlueRowEqualityComparer.Equals(GetRow(idx), item)
|
||||
? idx
|
||||
: -1;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using System;
|
||||
|
||||
using BCG;
|
||||
|
||||
[DataStreamUserRespresentation("CSVReaderStream")]
|
||||
public class CSVReaderStream : ViewStream {
|
||||
public CSVReaderStream(string file_name)
|
||||
: this(file_name, false) { }
|
||||
public CSVReaderStream(string file_name, bool guess_schema) {
|
||||
ViewStream rs = new BCG.CSVReaderStream(file_name);
|
||||
if (guess_schema) {
|
||||
rs = new SchemaGuesserStream(rs);
|
||||
}
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
|
||||
using System;
|
||||
|
||||
[DataStreamUserRespresentation("CSVSaverStream")]
|
||||
public class CSVSaverStream: ViewStream {
|
||||
public CSVSaverStream(ViewStream parent_str, string file_name) {
|
||||
BCG.CSVSaverStream rs = new BCG.CSVSaverStream(parent_str, file_name, true, Int32.MaxValue, false);
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStream;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
|
||||
public class CastStream : ViewStream, IDisposable {
|
||||
readonly ViewStream inputStream;
|
||||
readonly (string, Type)[] casts;
|
||||
IDisposable? sub;
|
||||
|
||||
public CastStream(ViewStream inputStream, params (string, Type)[] casts) {
|
||||
this.inputStream = inputStream;
|
||||
this.casts = casts;
|
||||
}
|
||||
|
||||
~CastStream() =>
|
||||
Dispose();
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
Disposable.dispose(ref sub);
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
inputStream.Subscribe(OnInputChanged);
|
||||
|
||||
void OnInputChanged(IDataPacket dp) {
|
||||
var dpOut = new DataPacket(
|
||||
new CastTable(dp.newRows, casts),
|
||||
new CastTable(dp.addedRows, casts),
|
||||
new CastTable(dp.deletedRows, casts));
|
||||
myFireEvent(dpOut);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() =>
|
||||
Disposable.dispose(ref sub);
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.collections;
|
||||
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class CastTable : IBlueRowCollection {
|
||||
readonly IBlueRowCollection rows;
|
||||
readonly IBlueTableSchema outputSchema;
|
||||
readonly (int Index, Func<IBlueRow, object?> GetValue)[] casts;
|
||||
readonly IComparer<(int Index, Func<IBlueRow, object?> GetValue)> castComparer =
|
||||
TupleComparer.Comparer<int, Func<IBlueRow, object?>>(item1Ordinal: 0);
|
||||
|
||||
public CastTable(IBlueRowCollection rows, params (string, Type)[] casts) {
|
||||
this.rows = rows;
|
||||
var inputSchema = rows.schema;
|
||||
var inputCols = inputSchema.columnInfo;
|
||||
var castIndices = inputSchema.ResolveIndices(Array.ConvertAll(casts, c => c.Item1));
|
||||
this.casts = new (int Index, Func<IBlueRow, object?> GetValue)[casts.Length];
|
||||
var outputCols = inputCols.ToArray();
|
||||
for (int i = 0; i < casts.Length; i++) {
|
||||
var colIdx = castIndices[i];
|
||||
this.casts[i] = (colIdx, GetCaster(casts[i].Item2));
|
||||
var inputCol = inputCols[colIdx];
|
||||
Log.assert(inputCol.colNo == colIdx);
|
||||
outputCols[colIdx] = new(inputCol.colName, inputCol.colNo, casts[i].Item2);
|
||||
|
||||
Func<IBlueRow, object?> GetCaster(Type to) {
|
||||
if (to == typeof(short)) {
|
||||
return r => r.GetInt16(colIdx);
|
||||
}
|
||||
if (to == typeof(int)) {
|
||||
return r => r.GetInt32(colIdx);
|
||||
}
|
||||
if (to == typeof(long)) {
|
||||
return r => r.GetInt64(colIdx);
|
||||
}
|
||||
if (to == typeof(ushort)) {
|
||||
return r => r.GetUInt16(colIdx);
|
||||
}
|
||||
if (to == typeof(uint)) {
|
||||
return r => r.GetUInt32(colIdx);
|
||||
}
|
||||
if (to == typeof(ulong)) {
|
||||
return r => r.GetUInt64(colIdx);
|
||||
}
|
||||
if (to == typeof(double)) {
|
||||
return r => r.GetFloat64(colIdx);
|
||||
}
|
||||
if (to == typeof(float)) {
|
||||
return r => r.GetFloat32(colIdx);
|
||||
}
|
||||
if (to == typeof(DateTime)) {
|
||||
return r => r.GetDateTime(colIdx);
|
||||
}
|
||||
if (to == typeof(TimeSpan)) {
|
||||
return r => r.GetTimeSpan(colIdx);
|
||||
}
|
||||
throw new NotImplementedException($"CastTable cast not implemented for (out) type {to}");
|
||||
}
|
||||
}
|
||||
outputSchema = new BlueTableSchema(inputSchema.tableName + "_Cast", outputCols);
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
new Row(rows[id], outputSchema, casts, castComparer);
|
||||
|
||||
public IBlueTableSchema schema => outputSchema;
|
||||
|
||||
public int Count => rows.Count;
|
||||
|
||||
public bool containsID(int id) =>
|
||||
rows.containsID(id);
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
foreach (var r in rows) {
|
||||
yield return new Row(r, outputSchema, casts, castComparer);
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
new Row(rows.GetRow(index), outputSchema, casts, castComparer);
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
var inputRow = rows[item.Id()];
|
||||
return BlueRowEqualityComparer.Equals(item, new Row(inputRow, outputSchema, casts, castComparer))
|
||||
? rows.IndexOf(inputRow)
|
||||
: -1;
|
||||
}
|
||||
|
||||
class Row : IBlueRow {
|
||||
readonly IBlueRow source;
|
||||
readonly (int Index, Func<IBlueRow, object?> GetValue)[] casts;
|
||||
readonly IComparer<(int Index, Func<IBlueRow, object?> GetValue)> castComparer;
|
||||
readonly IBlueTableSchema outputSchema;
|
||||
|
||||
public Row(IBlueRow source, IBlueTableSchema outputSchema, (int Index, Func<IBlueRow, object?> GetValue)[] casts, IComparer<(int Index, Func<IBlueRow, object?> GetValue)> castComparer) {
|
||||
this.source = source;
|
||||
this.casts = casts;
|
||||
this.castComparer = castComparer;
|
||||
this.outputSchema = outputSchema;
|
||||
}
|
||||
|
||||
public object? this[int index] {
|
||||
get {
|
||||
var castIdx = casts.BinarySearch((index, null!), castComparer);
|
||||
return castIdx > -1
|
||||
? casts[castIdx].GetValue(source)
|
||||
: source[index];
|
||||
}
|
||||
}
|
||||
|
||||
IBlueTableSchema IBlueRow.schema => outputSchema;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStream;
|
||||
|
||||
using System.Reactive.Linq;
|
||||
|
||||
public class ColumnInjectionStream : ViewStream {
|
||||
public ColumnInjectionStream(ViewStream inputStream, IInjectedColumn[] outputColumns) {
|
||||
IBlueTableSchema? outputSchema = null;
|
||||
mySetRealSource(inputStream.AsObservable().Select(Transform).AsViewStream());
|
||||
|
||||
IDataPacket Transform(IDataPacket dp) {
|
||||
outputSchema ??= ColumnInjectionTable.GetOutputSchema(dp.Schema, outputColumns);
|
||||
var newRows = new ColumnInjectionTable(dp.newRows, outputSchema, outputColumns);
|
||||
var addedRows = new ColumnInjectionTable(dp.addedRows, outputSchema, outputColumns);
|
||||
var deletedRows = new ColumnInjectionTable(dp.deletedRows, outputSchema, outputColumns);
|
||||
return new DataPacket(newRows, addedRows, deletedRows);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public interface IInjectedColumn {
|
||||
string Name { get; }
|
||||
Type Type { get; }
|
||||
int Ordinal { get; }
|
||||
ColumnInfo ColumnInfo => new(Name, Ordinal, Type);
|
||||
object? GetValue(IBlueRow row);
|
||||
}
|
||||
|
||||
public interface IInjectedColumn<T> : IInjectedColumn {
|
||||
Type IInjectedColumn.Type => typeof(T);
|
||||
|
||||
new T? GetValue(IBlueRow row);
|
||||
|
||||
object? IInjectedColumn.GetValue(IBlueRow row) =>
|
||||
GetValue(row);
|
||||
}
|
||||
|
||||
public class InjectedColumn : IInjectedColumn {
|
||||
readonly Func<IBlueRow, object?> getValue;
|
||||
|
||||
public InjectedColumn(string name, int index, Type type, Func<IBlueRow, object?> getValue) {
|
||||
Name = name;
|
||||
Ordinal = index;
|
||||
Type = type;
|
||||
this.getValue = getValue;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public int Ordinal { get; }
|
||||
public Type Type { get; }
|
||||
|
||||
public object? GetValue(IBlueRow row) =>
|
||||
getValue(row);
|
||||
}
|
||||
|
||||
public class InjectedColumn<T> : IInjectedColumn<T> {
|
||||
readonly Func<IBlueRow, T?> getValue;
|
||||
|
||||
public InjectedColumn(string name, int index, Func<IBlueRow, T?> getValue) {
|
||||
Name = name;
|
||||
Ordinal = index;
|
||||
this.getValue = getValue;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public int Ordinal { get; }
|
||||
|
||||
public T? GetValue(IBlueRow row) =>
|
||||
getValue(row);
|
||||
}
|
||||
|
||||
public class ColumnInjectionTable : IBlueRowCollection {
|
||||
readonly IBlueTableSchema outputSchema;
|
||||
readonly IInjectedColumn[] outputColumns;
|
||||
readonly IBlueRowCollection source;
|
||||
|
||||
public ColumnInjectionTable(IBlueRowCollection source, IBlueTableSchema outputSchema, IInjectedColumn[] outputColumns) {
|
||||
this.source = source;
|
||||
this.outputSchema = outputSchema;
|
||||
this.outputColumns = outputColumns;
|
||||
}
|
||||
|
||||
public static ColumnInjectionTable Create(IBlueRowCollection source, IEnumerable<IInjectedColumn> injectedColumns) {
|
||||
var inputCols = source.schema.columnInfo;
|
||||
var outputColumns = new List<IInjectedColumn>(inputCols.Length + 1);
|
||||
var outputColInfos = new List<ColumnInfo>(inputCols.Length + 1);
|
||||
int injectionIdx = 0;
|
||||
using var en = injectedColumns.GetEnumerator();
|
||||
bool hasMoreInjections = en.MoveNext();
|
||||
for (int i = 0; i < inputCols.Length;) {
|
||||
if (hasMoreInjections && en.Current.Ordinal <= i) {
|
||||
outputColInfos.Add(new(en.Current.Name, outputColumns.Count, en.Current.Type));
|
||||
outputColumns.Add(en.Current);
|
||||
injectionIdx++;
|
||||
continue;
|
||||
}
|
||||
var ci = inputCols[i];
|
||||
outputColInfos.Add(new(ci.colName, outputColumns.Count, ci.colType));
|
||||
outputColumns.Add(new InjectedColumn(ci.colName, outputColumns.Count, ci.colType, r => r[ci.colNo]));
|
||||
}
|
||||
var outputSchema = new BlueTableSchema(outputColInfos.ToArray(), $"ColumnInjection({source.schema.tableName})");
|
||||
return new(source, outputSchema, outputColumns.ToArray());
|
||||
}
|
||||
|
||||
public static IBlueTableSchema GetOutputSchema(IBlueTableSchema inputSchema, IEnumerable<IInjectedColumn> injectedColumns) {
|
||||
var inputCols = inputSchema.columnInfo;
|
||||
var outputColumns = new List<IInjectedColumn>(inputCols.Length + 1);
|
||||
var outputColInfos = new List<ColumnInfo>(inputCols.Length + 1);
|
||||
using var en = injectedColumns.GetEnumerator();
|
||||
bool hasMoreInjections = en.MoveNext();
|
||||
for (int i = 0; i < inputCols.Length;) {
|
||||
if (hasMoreInjections && en.Current.Ordinal <= i) {
|
||||
outputColInfos.Add(new(en.Current.Name, outputColumns.Count, en.Current.Type));
|
||||
outputColumns.Add(en.Current);
|
||||
hasMoreInjections = en.MoveNext();
|
||||
continue;
|
||||
}
|
||||
var ci = inputCols[i];
|
||||
outputColInfos.Add(new(ci.colName, outputColumns.Count, ci.colType));
|
||||
outputColumns.Add(new InjectedColumn(ci.colName, outputColumns.Count, ci.colType, r => r[ci.colNo]));
|
||||
i++;
|
||||
}
|
||||
return new BlueTableSchema(outputColInfos.ToArray(), $"ColumnInjection({inputSchema.tableName})");
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
new ColumnInjectionRow(source[id], outputSchema, outputColumns);
|
||||
|
||||
public IBlueTableSchema schema => throw new System.NotImplementedException();
|
||||
|
||||
public int Count => source.Count;
|
||||
|
||||
public bool containsID(int id) =>
|
||||
source.containsID(id);
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
foreach (var r in source) {
|
||||
yield return new ColumnInjectionRow(r, outputSchema, outputColumns);
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
new ColumnInjectionRow(source.GetRow(index), outputSchema, outputColumns);
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int id = item.Id();
|
||||
return source.containsID(id) && BlueRowEqualityComparer.Equals(item, this[id])
|
||||
? source.IndexOf(source[id])
|
||||
: -1;
|
||||
}
|
||||
|
||||
class ColumnInjectionRow : IBlueRow {
|
||||
readonly IBlueRow row;
|
||||
readonly IInjectedColumn[] columns;
|
||||
|
||||
public ColumnInjectionRow(IBlueRow row, IBlueTableSchema schema, IInjectedColumn[] columns) {
|
||||
this.row = row;
|
||||
this.schema = schema;
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public IBlueTableSchema schema { get; }
|
||||
|
||||
public object? this[int index] =>
|
||||
columns[index].GetValue(row);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
public class ColumnMaskRow : IBlueRow {
|
||||
readonly IBlueRow inputRow;
|
||||
readonly (string? Name, int Index)[] columnMap;
|
||||
|
||||
public ColumnMaskRow(IBlueRow inputRow, (string? Name, int Index)[] columnMap, IBlueTableSchema schema) {
|
||||
this.inputRow = inputRow;
|
||||
this.columnMap = columnMap;
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public IBlueTableSchema schema { get; }
|
||||
|
||||
public object? this[int index] =>
|
||||
inputRow[columnMap[index].Index];
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStream;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
public class ColumnMaskStream : ViewStream {
|
||||
readonly ViewStream source;
|
||||
readonly string? columnMaskExpression;
|
||||
|
||||
IDisposable? sub;
|
||||
IBlueTableSchema? outputSchema;
|
||||
// Each item in this array represents an output column as a tuple of
|
||||
// new name, and corresponding index in the input schema.
|
||||
(string? OutputName, int InputIndex)[]? columnMappings;
|
||||
(string From, string To)[]? columnNameMappings;
|
||||
readonly bool includeUnmappedColumns;
|
||||
|
||||
public ColumnMaskStream(ViewStream source, string columnMaskExpression) {
|
||||
this.source = source;
|
||||
this.columnMaskExpression = columnMaskExpression;
|
||||
}
|
||||
|
||||
public ColumnMaskStream(ViewStream source, bool includeUnmappedColumns, params (string From, string To)[] columnNameMappings) {
|
||||
this.source = source;
|
||||
this.columnNameMappings = columnNameMappings;
|
||||
this.includeUnmappedColumns = includeUnmappedColumns;
|
||||
}
|
||||
|
||||
~ColumnMaskStream() =>
|
||||
Disposable.dispose(ref sub);
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
Log.isnull(sub);
|
||||
sub = source.Subscribe(OnSourceChanged);
|
||||
|
||||
void OnSourceChanged(IDataPacket dp) {
|
||||
ensureOutputSchema(dp.Schema);
|
||||
var addedRows = new ColumnMaskTable(dp.addedRows, columnMappings, outputSchema);
|
||||
var deletedRows = new ColumnMaskTable(dp.deletedRows, columnMappings, outputSchema);
|
||||
var allRows = new ColumnMaskTable(dp.newRows, columnMappings, outputSchema);
|
||||
myFireEvent(new DataPacket(allRows, addedRows, deletedRows));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() =>
|
||||
Disposable.dispose(ref sub);
|
||||
|
||||
[MemberNotNull(nameof(outputSchema), nameof(columnMappings))]
|
||||
void ensureOutputSchema(IBlueTableSchema inputSchema) {
|
||||
if (outputSchema is not null) {
|
||||
Log.notnull(columnMappings);
|
||||
return;
|
||||
}
|
||||
if (columnMaskExpression is not null) {
|
||||
outputSchema = ColumnMaskTable.GetOutputSchema(inputSchema, columnMaskExpression, out columnMappings);
|
||||
} else if (columnNameMappings is not null) {
|
||||
outputSchema = ColumnMaskTable.GetOutputSchema(inputSchema, includeUnmappedColumns, columnNameMappings, out columnMappings);
|
||||
} else {
|
||||
throw new InvalidOperationException("Cannot build output schema");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.collections;
|
||||
using bts.utils;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class ColumnMaskTable : IBlueRowCollection {
|
||||
readonly IBlueRowCollection inputRows;
|
||||
readonly (string? Name, int Index)[] columnMap;
|
||||
|
||||
public ColumnMaskTable(IBlueRowCollection inputRows, (string? Name, int Index)[] columnMap, IBlueTableSchema schema) {
|
||||
this.inputRows = inputRows;
|
||||
this.columnMap = columnMap;
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public IBlueTableSchema schema { get; }
|
||||
|
||||
public int Count => inputRows.Count;
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
new ColumnMaskRow(inputRows[id], columnMap, schema);
|
||||
|
||||
public static ColumnMaskTable Create(IBlueRowCollection table, string columnMaskExpression) {
|
||||
var outputSchema = GetOutputSchema(table.schema, columnMaskExpression, out var columnMappings);
|
||||
return new ColumnMaskTable(table, columnMappings, outputSchema);
|
||||
}
|
||||
|
||||
public static IBlueTableSchema GetOutputSchema(IBlueTableSchema inputSchema, string columnMaskExpression, out (string? Name, int Index)[] columnMappings) {
|
||||
bool includeOthers;
|
||||
if (columnMaskExpression.StartsWith('!')) {
|
||||
columnMaskExpression = columnMaskExpression[1..].TrimStart();
|
||||
includeOthers = false;
|
||||
} else {
|
||||
includeOthers = true;
|
||||
}
|
||||
var map = columnMaskExpression.Split(' ').Select(MapColumn).ToOrderedDictionary(tup => tup.Index, tup => tup.Name);
|
||||
var inputCols = inputSchema.columnInfo;
|
||||
if (includeOthers) {
|
||||
var implicitCols = inputCols.Where(c => !map.ContainsKey(c.colNo)).ToList();
|
||||
map.AddRange(implicitCols.Select(c => new KeyValuePair<int, string?>(c.colNo, null)));
|
||||
} else if (!map.Any(c => inputCols[c.Key].colName == "id") && inputCols.TryGetFirst(c => c.colName == "id", out var idColInfo)) {
|
||||
// Add 'id' col if missing
|
||||
map.Insert(0, new(idColInfo.colNo, "id"));
|
||||
}
|
||||
var outputCols = new ColumnInfo[map.Count];
|
||||
for (int i = 0; i < outputCols.Length; i++) {
|
||||
var inputColInfo = inputCols[map.Keys[i]];
|
||||
outputCols[i] = new(map.Values[i] ?? inputColInfo.colName, i, inputColInfo.colType);
|
||||
}
|
||||
columnMappings = map.WrapSelector(kv => (kv.Value, kv.Key), null).ToArray();
|
||||
return new BlueTableSchema(outputCols, inputSchema.tableName + "_ColumnMask");
|
||||
|
||||
(string? Name, int Index) MapColumn(string columnStr) {
|
||||
var parts = columnStr.Split(':');
|
||||
return parts.Length switch {
|
||||
1 => ((string?)null, inputSchema[parts[0]].colNo),
|
||||
2 => (parts[1], inputSchema[parts[0]].colNo),
|
||||
_ => throw new InvalidOperationException("Unable to get output schema due to invalid column expression"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static IBlueTableSchema GetOutputSchema(IBlueTableSchema inputSchema, bool includeUnmapped, (string From, string To)[] columnNameMappings, out (string? OutputName, int InputIndex)[] columnMappings) {
|
||||
var inputCols = inputSchema.columnInfo;
|
||||
ColumnInfo[]? outputCols;
|
||||
if (includeUnmapped) {
|
||||
columnMappings = Array.ConvertAll(inputCols, c => ((string?)c.colName, c.colNo));
|
||||
outputCols = ArrayUtils.Clone(inputCols);
|
||||
foreach (var (from, to) in columnNameMappings) {
|
||||
var idx = inputCols.ResolveIndices(from);
|
||||
var c = outputCols[idx];
|
||||
Log.assert(c.colNo == idx);
|
||||
outputCols[idx] = new(to, c.colNo, c.colType);
|
||||
columnMappings[idx] = (to, idx);
|
||||
}
|
||||
} else {
|
||||
outputCols = new ColumnInfo[columnNameMappings.Length];
|
||||
columnMappings = Array.ConvertAll(columnNameMappings, m => ((string?)m.To, inputCols.ResolveIndices(m.From)));
|
||||
Array.Copy(inputCols, outputCols, inputCols.Length);
|
||||
for (int i = 0; i < columnNameMappings.Length; i++) {
|
||||
var (from, to) = columnNameMappings[i];
|
||||
var idx = inputCols.ResolveIndices(from);
|
||||
outputCols[idx] = new(to, i, inputCols[columnMappings[i].InputIndex].colType);
|
||||
}
|
||||
}
|
||||
return new BlueTableSchema(outputCols, inputSchema.tableName + "_ColumnMask");
|
||||
}
|
||||
|
||||
public bool containsID(int id) =>
|
||||
inputRows.containsID(id);
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
foreach (var r in inputRows) {
|
||||
yield return new ColumnMaskRow(r, columnMap, schema);
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
new ColumnMaskRow(inputRows.GetRow(index), columnMap, schema);
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int id = item.Id();
|
||||
if (inputRows.containsID(id)) {
|
||||
var inputRow = inputRows[id];
|
||||
var outputRow = new ColumnMaskRow(inputRow, columnMap, schema);
|
||||
if (BlueRowEqualityComparer.Equals(item, outputRow)) {
|
||||
return inputRows.IndexOf(inputRow);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
// namespace bts.BlueOrb;
|
||||
|
||||
// using BCG;
|
||||
|
||||
// using System;
|
||||
// using System.Linq;
|
||||
|
||||
// /// <summary>
|
||||
// /// Represents a row transformation table (all columns except 'id' can be changed).
|
||||
// /// </summary>
|
||||
// public class ColumnSelectorRow : IBlueRow {
|
||||
// readonly IBlueRow source;
|
||||
// readonly IBlueTableSchema outputSchema;
|
||||
// readonly Func<object?, object?>[] columnSelectors;
|
||||
|
||||
// public ColumnSelectorRow(IBlueRow source, params (int Index, Type Type, Func<object?, object?> GetValue)[] columnSelectors) {
|
||||
// this.source = source;
|
||||
// this.columnSelectors = Array.ConvertAll(columnSelectors, c => (c.Index, c.GetValue));
|
||||
// outputSchema = getSchema(source.schema, columnSelectors);
|
||||
// }
|
||||
|
||||
// public ColumnSelectorRow(IBlueRow source, IBlueTableSchema outputSchema, params (int Index, Func<object?, object?> GetValue)[] columnSelectors) {
|
||||
// this.source = source;
|
||||
// this.outputSchema = outputSchema;
|
||||
// this.columnSelectors = columnSelectors;
|
||||
// }
|
||||
|
||||
// public object? this[int index] {
|
||||
// get {
|
||||
// for (int i = 0; i < columnSelectors.Length; i++) {
|
||||
// if (columnSelectors[i].Index == index) {
|
||||
// return columnSelectors[i].GetValue(source[index]);
|
||||
// }
|
||||
// }
|
||||
// return source[index];
|
||||
// }
|
||||
// }
|
||||
|
||||
// public IBlueTableSchema schema => outputSchema;
|
||||
|
||||
// public static Func<object?, object?>[] BuildColumnSelectors(IBlueTableSchema schema, params (int Index, Func<object?, object?> GetValue)[] columnSelectors) {
|
||||
// var cols = schema.columnInfo;
|
||||
// var rv = Array.ConvertAll(schema.columnInfo, c => new Func<object?, object?>(_ => _));
|
||||
// for (int i = 0; i < columnSelectors.Length; i++) {
|
||||
// var cs = columnSelectors[i];
|
||||
// rv[cs.Index] = cs.GetValue;
|
||||
// }
|
||||
// return rv;
|
||||
// }
|
||||
|
||||
// static IBlueTableSchema getSchema(IBlueTableSchema inputSchema, (int Index, Type Type, Func<object?, object?> GetValue)[] columnSelectors) {
|
||||
// var inputCols = inputSchema.columnInfo;
|
||||
// var outputCols = inputCols.ToArray();
|
||||
// for (int i = 0; i < columnSelectors.Length; i++) {
|
||||
// var (idx, typ, _) = columnSelectors[i];
|
||||
// var col = inputCols[idx];
|
||||
// outputCols[idx] = new(col.colName, col.colNo, typ);
|
||||
// }
|
||||
// return new BlueTableSchema(outputCols, "ColumnSelector");
|
||||
// }
|
||||
// }
|
||||
@@ -1,107 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.collections;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class ColumnSelectorRowFactory {
|
||||
readonly IBlueTableSchema outputSchema;
|
||||
readonly Func<object?, object?>[] columnSelectors;
|
||||
|
||||
public ColumnSelectorRowFactory(IBlueTableSchema outputSchema, Func<object?, object?>[] columnSelectors) {
|
||||
this.outputSchema = outputSchema;
|
||||
this.columnSelectors = columnSelectors;
|
||||
}
|
||||
|
||||
public IBlueTableSchema OutputSchema => outputSchema;
|
||||
|
||||
public static ColumnSelectorRowFactory Create(IBlueTableSchema inputSchema, params (string Name, Type Type, Func<object?, object?> GetValue)[] columnOverrides) =>
|
||||
Create(inputSchema, columnOverrides.AsEnumerable());
|
||||
|
||||
public static ColumnSelectorRowFactory Create(IBlueTableSchema inputSchema, params (int Index, Type Type, Func<object?, object?> GetValue)[] columnOverrides) =>
|
||||
Create(inputSchema, columnOverrides.AsEnumerable());
|
||||
|
||||
public static ColumnSelectorRowFactory Create(IBlueTableSchema inputSchema, IEnumerable<(string Name, Type Type, Func<object?, object?> GetValue)> columnOverrides) =>
|
||||
Create(inputSchema, columnOverrides.Select(c => (inputSchema.ResolveIndices(c.Name), c.Type, c.GetValue)));
|
||||
|
||||
public static ColumnSelectorRowFactory Create(IBlueTableSchema inputSchema, IEnumerable<(int Index, Type Type, Func<object?, object?> GetValue)> columnOverrides) {
|
||||
var bd = new Builder(inputSchema);
|
||||
foreach (var c in columnOverrides) {
|
||||
bd.AddOrUpdate(c);
|
||||
}
|
||||
return bd.ToImmutable();
|
||||
}
|
||||
|
||||
public IBlueRow Create(IBlueRow row) =>
|
||||
new Row(row, outputSchema, columnSelectors);
|
||||
|
||||
public Builder ToBuilder() =>
|
||||
new(outputSchema);
|
||||
|
||||
class Row : IBlueRow {
|
||||
readonly IBlueRow source;
|
||||
readonly IBlueTableSchema schema;
|
||||
readonly Func<object?, object?>[] columnSelectors;
|
||||
|
||||
public Row(IBlueRow source, IBlueTableSchema schema, Func<object?, object?>[] columnSelectors) {
|
||||
this.source = source;
|
||||
this.schema = schema;
|
||||
this.columnSelectors = columnSelectors;
|
||||
}
|
||||
|
||||
public object? this[int index] =>
|
||||
columnSelectors[index](source[index]);
|
||||
|
||||
IBlueTableSchema IBlueRow.schema => schema;
|
||||
}
|
||||
|
||||
public class Builder {
|
||||
readonly IBlueTableSchema inputSchema;
|
||||
readonly List<(int Index, Type Type, Func<object?, object?> GetValue)> columnOverrides = new();
|
||||
|
||||
public Builder(IBlueTableSchema inputSchema) {
|
||||
this.inputSchema = inputSchema;
|
||||
}
|
||||
|
||||
public IBlueTableSchema ToSchema() =>
|
||||
ToSchema(inputSchema.tableName + "_ColumnSelector");
|
||||
|
||||
public IBlueTableSchema ToSchema(string tableName) {
|
||||
var inputCols = inputSchema.columnInfo;
|
||||
var outputCols = inputCols.ToArray();
|
||||
foreach (var c in columnOverrides) {
|
||||
var inputCol = inputCols[c.Index];
|
||||
outputCols[c.Index] = new(inputCol.colName, c.Index, c.Type);
|
||||
}
|
||||
return new BlueTableSchema(outputCols, tableName);
|
||||
}
|
||||
|
||||
public ColumnSelectorRowFactory ToImmutable() {
|
||||
var outputSchema = ToSchema();
|
||||
var columnSelectors = Array.ConvertAll(outputSchema.columnInfo, c => new Func<object?, object?>(_ => _));
|
||||
foreach (var cs in columnOverrides) {
|
||||
columnSelectors[cs.Index] = cs.GetValue;
|
||||
}
|
||||
return new(outputSchema, columnSelectors);
|
||||
}
|
||||
|
||||
public void AddOrUpdate((int Index, Type Type, Func<object?, object?> GetValue) item) =>
|
||||
columnOverrides.Add(item);
|
||||
|
||||
public void AddOrUpdate(int index, Type type, Func<object?, object?> getValue) =>
|
||||
columnOverrides.Add((index, type, getValue));
|
||||
|
||||
public void AddOrUpdate<T>(int index, Func<object?, T> getValue) {
|
||||
columnOverrides.Add((index, typeof(T), GetValueWrapper));
|
||||
|
||||
object? GetValueWrapper(object? inputVal) =>
|
||||
getValue(inputVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace 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 int myId = 0;
|
||||
private ViewStream myVS;
|
||||
|
||||
public CountStream(ViewStream vs) {
|
||||
myVS = vs;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
myVS.onChange += myHandleChanges;
|
||||
}
|
||||
protected override void myOnLastSubscriber() {
|
||||
myVS.onChange -= 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using MathNet.Numerics.Statistics;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class CovarianceTable : IBlueRowCollection {
|
||||
readonly IBlueTableSchema schema;
|
||||
readonly Lazy<IBlueRow> row;
|
||||
|
||||
public CovarianceTable(IBlueRowCollection rows1, IBlueRowCollection rows2) {
|
||||
var inputSchema = rows1.schema;
|
||||
var inputCols = inputSchema.columnInfo;
|
||||
var outputCols = Array.ConvertAll(rows1.schema.columnInfo, ColumnFactory);
|
||||
schema = new BlueTableSchema(outputCols, inputSchema.tableName + "_" + rows2.schema.tableName + "_Covariance");
|
||||
row = new(RowFactory);
|
||||
|
||||
static ColumnInfo ColumnFactory(ColumnInfo inputCol) {
|
||||
var t = inputCol.colType;
|
||||
if (inputCol.colName != "id") {
|
||||
if (t == typeof(short) || t == typeof(int) || t == typeof(long)
|
||||
|| t == typeof(ushort) || t == typeof(uint) || t == typeof(ulong)
|
||||
|| t == typeof(double) || t == typeof(float)) {
|
||||
t = typeof(double);
|
||||
} else if (t == typeof(DateTime)) {
|
||||
t = typeof(TimeSpan);
|
||||
}
|
||||
}
|
||||
return new(inputCol.colName, inputCol.colNo, t);
|
||||
}
|
||||
|
||||
IBlueRow RowFactory() {
|
||||
var rowVals = new object[inputCols.Length];
|
||||
for (int i = 0; i < inputCols.Length; i++) {
|
||||
var col = inputCols[i];
|
||||
var colType = col.colType;
|
||||
if (col.colName == "id") {
|
||||
rowVals[i] = 1;
|
||||
} else if (colType == typeof(short)) {
|
||||
rowVals[i] = GetValue(v => v as short?);
|
||||
} else if (colType == typeof(int)) {
|
||||
rowVals[i] = GetValue(v => v as int?);
|
||||
} else if (colType == typeof(long)) {
|
||||
rowVals[i] = GetValue(v => v as long?);
|
||||
} else if (colType == typeof(ushort)) {
|
||||
rowVals[i] = GetValue(v => v as ushort?);
|
||||
} else if (colType == typeof(uint)) {
|
||||
rowVals[i] = GetValue(v => v as uint?);
|
||||
} else if (colType == typeof(ulong)) {
|
||||
rowVals[i] = GetValue(v => v as ulong?);
|
||||
} else if (colType == typeof(double)) {
|
||||
rowVals[i] = GetValue(v => v as double?);
|
||||
} else if (colType == typeof(float)) {
|
||||
rowVals[i] = GetValue(v => v as float?);
|
||||
} else if (colType == typeof(DateTime)) {
|
||||
rowVals[i] = TimeSpan.FromSeconds(GetValue(v => (v as DateTime?)?.Ticks / 10_000_000));
|
||||
}
|
||||
|
||||
double GetValue(Func<object?, double?> convert) {
|
||||
var vals1 = rows1.GetColumn(i)
|
||||
.Select(convert)
|
||||
.SelectWhereValues();
|
||||
var vals2 = rows2.GetColumn(i)
|
||||
.Select(convert)
|
||||
.SelectWhereValues();
|
||||
return vals1.Covariance(vals2);
|
||||
}
|
||||
}
|
||||
return new Row(schema, rowVals);
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
id == 1 ? row.Value : throw new KeyNotFoundException();
|
||||
|
||||
IBlueTableSchema IBlueRowCollection.schema => schema;
|
||||
|
||||
public int Count => 1;
|
||||
|
||||
IBlueRow IList<IBlueRow>.this[int index] {
|
||||
get => GetRow(index);
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public bool containsID(int id) =>
|
||||
id == 1;
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
yield return row.Value;
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
index == 0 ? row.Value : throw new IndexOutOfRangeException();
|
||||
|
||||
public int IndexOf(IBlueRow item) =>
|
||||
BlueRowEqualityComparer.Equals(item, row.Value) ? 0 : -1;
|
||||
|
||||
class Row : IBlueRow {
|
||||
readonly IBlueTableSchema schema;
|
||||
readonly object?[] values;
|
||||
|
||||
public Row(IBlueTableSchema schema, object?[] values) {
|
||||
this.schema = schema;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public object? this[int index] => values[index];
|
||||
|
||||
IBlueTableSchema IBlueRow.schema => schema;
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.collections;
|
||||
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
public class CummulativeSumStream : ViewStream, IDisposable {
|
||||
readonly ViewStream inputStream;
|
||||
readonly CummulativeSumTable.StringBehavior stringBehavior;
|
||||
IBlueTableSchema? schema;
|
||||
IDisposable? sub;
|
||||
SingleRowTable? lastFired;
|
||||
object?[]? lastFiredValues;
|
||||
Func<object?, object?, object?>[]? columnOperators;
|
||||
int idColumnIdx = -1;
|
||||
|
||||
public CummulativeSumStream(ViewStream inputStream, CummulativeSumTable.StringBehavior stringBehavior = CummulativeSumTable.StringBehavior.LastValue) {
|
||||
this.inputStream = inputStream;
|
||||
this.stringBehavior = stringBehavior;
|
||||
}
|
||||
|
||||
~CummulativeSumStream() =>
|
||||
Disposable.dispose(ref sub);
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
Disposable.dispose(ref sub);
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
Disposable.dispose(ref sub);
|
||||
sub = inputStream.Subscribe(OnInputStreamChanged);
|
||||
|
||||
void OnInputStreamChanged(IDataPacket dp) {
|
||||
ensureInit(dp);
|
||||
var values = lastFiredValues?.ToArray() ?? new object?[schema.columnInfo.Length];
|
||||
foreach (var r in dp.addedRows) {
|
||||
for (int i = 0; i < values.Length; i++) {
|
||||
values[i] = columnOperators[i](values[i], r[i]);
|
||||
}
|
||||
}
|
||||
var table = new SingleRowTable(new BlueRow(schema, values));
|
||||
DataPacket dpOut = new(table, table, lastFired as IBlueRowCollection ?? new BlueTable(schema));
|
||||
lastFired = table;
|
||||
lastFiredValues = values;
|
||||
myFireEvent(dpOut);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() =>
|
||||
Disposable.dispose(ref sub);
|
||||
|
||||
[MemberNotNull(nameof(schema), nameof(columnOperators))]
|
||||
void ensureInit(IDataPacket dp) {
|
||||
if (schema is not null) {
|
||||
Log.notnull(columnOperators);
|
||||
return;
|
||||
}
|
||||
schema = dp.Schema;
|
||||
idColumnIdx = schema.ResolveIndices("id");
|
||||
var colInfos = schema.columnInfo;
|
||||
columnOperators = new Func<object?, object?, object?>[schema.columnInfo.Length];
|
||||
for (int i = 0; i < colInfos.Length; i++) {
|
||||
if (i == idColumnIdx) {
|
||||
columnOperators[i] = (x, y) => 1;
|
||||
continue;
|
||||
}
|
||||
columnOperators[i] = schema.columnInfo[i].type_code() switch {
|
||||
TypeCode.Int32 => (x, y) => (x as int? ?? 0) + (BlueDataUtility.GetInt32(y) ?? 0),
|
||||
TypeCode.Int64 => (x, y) => (x as long? ?? 0) + (BlueDataUtility.GetInt64(y) ?? 0),
|
||||
TypeCode.UInt32 => (x, y) => (x as uint? ?? 0) + (BlueDataUtility.GetUInt32(y) ?? 0),
|
||||
TypeCode.UInt64 => (x, y) => (x as ulong? ?? 0) + (BlueDataUtility.GetUInt64(y) ?? 0),
|
||||
TypeCode.Single => (x, y) => (x as float? ?? 0) + (BlueDataUtility.GetFloat32(y) ?? 0),
|
||||
TypeCode.Double => (x, y) => (x as double? ?? 0) + (BlueDataUtility.GetFloat64(y) ?? 0),
|
||||
TypeCode.String => stringBehavior switch {
|
||||
CummulativeSumTable.StringBehavior.Concatenate => (x, y) => (x as string ?? string.Empty) + (y as string ?? string.Empty),
|
||||
_ => (accum, next) => next,
|
||||
},
|
||||
TypeCode.DateTime => (x, y) => y,
|
||||
_ => throw new InvalidOperationException($"Failed to add row values for col '{schema.columnInfo[i]}'"),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.collections;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class CummulativeSumTable : IBlueRowCollection {
|
||||
readonly IBlueRowCollection input;
|
||||
readonly IList<object?>[] columns;
|
||||
readonly StringBehavior stringBehavior;
|
||||
|
||||
public CummulativeSumTable(IBlueRowCollection input, StringBehavior stringBehavior = StringBehavior.LastValue) {
|
||||
this.input = input;
|
||||
var colInfos = input.schema.columnInfo.OrderBy(c => c.colNo).ToArray();
|
||||
if (colInfos.Length > 0) {
|
||||
Log.assert(colInfos[0].colNo == 0 && colInfos[^1].colNo == colInfos.Length - 1);
|
||||
}
|
||||
columns = colInfos.WrapSelector(c => GetColumn(c.colNo), null).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// By default, we take the last value for strings intstead of adding (concatenating) them.
|
||||
/// Otherwise it would be too easy to create massive concatenated strings by mistake.
|
||||
/// </summary>
|
||||
public enum StringBehavior {
|
||||
LastValue,
|
||||
Concatenate
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
id == 1 ? GetRow(0) : throw new KeyNotFoundException();
|
||||
|
||||
public IBlueTableSchema schema => input.schema;
|
||||
|
||||
public int Count => 1;
|
||||
|
||||
public bool containsID(int id) =>
|
||||
id == 1;
|
||||
|
||||
public IList<object?> GetColumn(int colIndex) {
|
||||
var count = input.Count;
|
||||
var colInfo = input.schema.columnInfo[colIndex];
|
||||
if (colInfo.colName == "id") {
|
||||
return new object?[] { 1 };
|
||||
}
|
||||
object? res = null;
|
||||
var colVals = input.GetColumn(colIndex);
|
||||
if (colInfo.colType == typeof(TimeSpan)) {
|
||||
// TimeSpan is a special case because it doesn't have a TypeCode.
|
||||
res = TimeSpanImpl(colVals);
|
||||
} else {
|
||||
var typeCode = colInfo.type_code();
|
||||
const int MAX_STRING_LENGTH = 1024;
|
||||
res = typeCode switch {
|
||||
TypeCode.Int32 => colVals.Cast<int>().Sum(),
|
||||
TypeCode.Int64 => colVals.Cast<long>().Sum(),
|
||||
TypeCode.UInt32 => colVals.Cast<uint>().Sum(),
|
||||
TypeCode.UInt64 => colVals.Cast<ulong>().Aggregate(0UL, (s, v) => s + v),
|
||||
TypeCode.Single => colVals.Cast<float>().Sum(),
|
||||
TypeCode.Double => colVals.Cast<double>().Sum(),
|
||||
TypeCode.DateTime => colVals.Cast<DateTime>().Aggregate(DateTime.MinValue, (s, v) => new DateTime(s.Ticks + v.Ticks)),
|
||||
TypeCode.String => stringBehavior switch {
|
||||
StringBehavior.Concatenate => colVals.Cast<string>().Aggregate(string.Empty, (s, v) => {
|
||||
if (s.Length + v.Length > MAX_STRING_LENGTH) {
|
||||
throw new InvalidOperationException("Cannot sum strings because the result is too long");
|
||||
}
|
||||
return s + v;
|
||||
}),
|
||||
_ => count == 0 ? null : colVals[^1] as string,
|
||||
},
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
return new object?[] { res };
|
||||
|
||||
static object? TimeSpanImpl(IList<object?> colVals) {
|
||||
var ticks = colVals.Cast<TimeSpan>().Select(ts => ts.Ticks).Sum();
|
||||
return TimeSpan.FromTicks(ticks);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
yield return GetRow(0);
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
new BlueRowColumnWrapper(input.schema, index, columns);
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int id = item.Id();
|
||||
var inputRow = input[id];
|
||||
int idx = input.IndexOf(inputRow);
|
||||
if (idx != -1) {
|
||||
var row = GetRow(idx);
|
||||
if (BlueRowEqualityComparer.Equals(item, row)) {
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public class CummulativeSumTableEvaluator : IFunctionEvaluator {
|
||||
public object? Evaluate(string functionId, IEnumerable<StreamArgument> args) {
|
||||
if (args.TryGetFirst(out var a)) {
|
||||
var table = a.Value as IBlueRowCollection;
|
||||
if (table is not null) {
|
||||
return new CummulativeSumTable(table);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
public class DiffStream : ViewStream, IDisposable {
|
||||
readonly ViewStream source;
|
||||
readonly int period;
|
||||
IBlueTableSchema? outputSchema;
|
||||
IDisposable? sub;
|
||||
BlueTableImmutable? lastFired;
|
||||
|
||||
public DiffStream(ViewStream source, int period) {
|
||||
this.source = source;
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
~DiffStream() =>
|
||||
Dispose();
|
||||
|
||||
public void Dispose() =>
|
||||
Disposable.dispose(ref sub);
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
Log.isnull(sub);
|
||||
sub = source.Subscribe(OnSourceChange);
|
||||
|
||||
void OnSourceChange(IDataPacket dp) {
|
||||
if (outputSchema is null) {
|
||||
var inputSchema = dp.Schema;
|
||||
var outputCols = new ColumnInfo[inputSchema.columnInfo.Length];
|
||||
for (int i = 0; i < inputSchema.columnInfo.Length; i++) {
|
||||
outputCols[i] = GetOutputColumn(inputSchema.columnInfo[i]);
|
||||
}
|
||||
outputSchema = new BlueTableSchema($"{inputSchema.tableName}_Diff{period}", outputCols);
|
||||
}
|
||||
lastFired ??= new(outputSchema);
|
||||
var newTable = new DiffTable(dp.newRows, period);
|
||||
var allRows = new List<object?[]>();
|
||||
foreach (IBlueRow r in newTable) {
|
||||
var rvals = new object?[r.schema.columnInfo.Length];
|
||||
int x = 0;
|
||||
foreach (var col in r.schema.columnInfo) {
|
||||
var val = r[col.colNo];
|
||||
rvals[x++] = val;
|
||||
}
|
||||
allRows.Add(rvals);
|
||||
}
|
||||
var bd = lastFired.ToDataPacketBuilder();
|
||||
var removedIndices = new List<int>();
|
||||
var addedIndices = new List<int>();
|
||||
var ops = new List<(int Index, bool IsAdd)>();
|
||||
foreach (var r in dp.deletedRows) {
|
||||
int id = r.Id();
|
||||
var rOut = lastFired[id];
|
||||
var idx = lastFired.IndexOf(rOut);
|
||||
Log.assert(idx >= 0 && idx < lastFired.Count);
|
||||
removedIndices.Add(idx);
|
||||
ops.Add((idx, false));
|
||||
}
|
||||
foreach (var r in dp.addedRows) {
|
||||
var idx = dp.newRows.IndexOf(r);
|
||||
Log.assert(idx >= 0 && idx < dp.newRows.Count);
|
||||
addedIndices.Add(idx);
|
||||
ops.Add((idx, true));
|
||||
}
|
||||
ops.Sort(Comparer<(int Index, bool IsAdd)>.Create((a, b) => a.Index.CompareTo(b.Index)));
|
||||
int rmCount = 0;
|
||||
var removedRows = new Dictionary<int, IBlueRow>();
|
||||
for (int i = 0; i < ops.Count; i++) {
|
||||
var op = ops[i];
|
||||
if (op.IsAdd) {
|
||||
continue;
|
||||
}
|
||||
rmCount++;
|
||||
int j = op.Index/* - rmCount*/;
|
||||
var stop = Math.Min(j + period, lastFired.Count/* - rmCount*/);
|
||||
// Remove the row that was removed in the incoming DataPacket.
|
||||
bd.Remove(lastFired.GetRow(j).Id());
|
||||
for (j++; j < stop; j++) {
|
||||
// Remove rows that changed as a result. We will add the updated versions
|
||||
// of these rows in the next pass.
|
||||
var r = lastFired.GetRow(j);
|
||||
bd.Remove(r.Id());
|
||||
}
|
||||
}
|
||||
int addCount = ops.Count - rmCount;
|
||||
for (int i = ops.Count - 1; i >= 0; i--) {
|
||||
var op = ops[i];
|
||||
if (op.IsAdd) {
|
||||
addCount--;
|
||||
int j = op.Index;
|
||||
var stop = Math.Min(j + period, newTable.Count);
|
||||
for (; j < stop; j++) {
|
||||
var r = newTable.GetRow(j);
|
||||
bd.AddOrUpdate(r);
|
||||
}
|
||||
} else {
|
||||
rmCount--;
|
||||
int j = op.Index - rmCount + addCount;
|
||||
var stop = Math.Min(j + period, newTable.Count);
|
||||
for (; j < stop; j++) {
|
||||
// Add rows that changed due to the removed row (the row with which they compute
|
||||
// the diff has changed).
|
||||
var r = newTable.GetRow(j);
|
||||
bd.AddOrUpdate(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
var dpOut = bd.ToDataPacket(out lastFired, false);
|
||||
myFireEvent(dpOut);
|
||||
}
|
||||
|
||||
ColumnInfo GetOutputColumn(ColumnInfo inputColumn) {
|
||||
return inputColumn.type_code() switch {
|
||||
TypeCode.Boolean => inputColumn.Clone(),
|
||||
TypeCode.Byte or TypeCode.SByte or TypeCode.Int16 => WithType(TypeCode.Int32),
|
||||
TypeCode.UInt32 or TypeCode.UInt64 => WithType(TypeCode.Int64),
|
||||
_ => inputColumn.Clone(),
|
||||
};
|
||||
|
||||
ColumnInfo WithType(TypeCode typeCode) =>
|
||||
new(inputColumn.colName, inputColumn.colNo, typeCode);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() =>
|
||||
Disposable.dispose(ref sub);
|
||||
|
||||
static class ExpressionBuilder {
|
||||
public static Func<IBlueRow, IBlueRow, int?> Int32DiffExpression(int colIndex) {
|
||||
var colIndexParam = Expression.Constant(colIndex, typeof(int));
|
||||
var rowParam = Expression.Parameter(typeof(IBlueRow), "row");
|
||||
var getValMethod = typeof(ExpressionBuilder).GetMethod(nameof(getInt32Value))
|
||||
?? throw new InvalidOperationException("Failed to find int32 value getter via reflection");
|
||||
var getVal = Expression.Lambda<Func<IBlueRow, int?>>(Expression.Call(null, getValMethod, rowParam, colIndexParam), rowParam).Compile();
|
||||
return ComputeDiff;
|
||||
|
||||
int? ComputeDiff(IBlueRow leftRow, IBlueRow rightRow) {
|
||||
var leftVal = getVal(leftRow);
|
||||
var rightVal = getVal(rightRow);
|
||||
if (leftVal.HasValue && rightVal.HasValue) {
|
||||
return leftVal.Value - rightVal.Value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static int? getInt32Value(IBlueRow row, int colIndex) {
|
||||
var obj = row[colIndex];
|
||||
return obj as int?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.collections;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class DiffTable : IBlueRowCollection {
|
||||
readonly IBlueRowCollection input;
|
||||
readonly int period;
|
||||
readonly IList<object?>[] columns;
|
||||
|
||||
public DiffTable(IBlueRowCollection input, int period) {
|
||||
this.input = input;
|
||||
this.period = period;
|
||||
var colInfos = input.schema.columnInfo.OrderBy(c => c.colNo).ToArray();
|
||||
if (colInfos.Length > 0) {
|
||||
Log.assert(colInfos[0].colNo == 0 && colInfos[^1].colNo == colInfos.Length - 1);
|
||||
}
|
||||
columns = colInfos.WrapSelector(c => GetColumn(c.colNo), null).ToArray();
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
GetRow(input.IndexOf(input[id]));
|
||||
|
||||
public IBlueTableSchema schema => input.schema;
|
||||
|
||||
public int Count => input.Count;
|
||||
|
||||
public bool containsID(int id) =>
|
||||
input.containsID(id);
|
||||
|
||||
public IList<object?> GetColumn(int colIndex) {
|
||||
var count = input.Count;
|
||||
var colInfo = input.schema.columnInfo[colIndex];
|
||||
if (colInfo.colName == "id") {
|
||||
return new StepList<int>(0, 1, count).as_mutable().WrapSelector(GetId, null);
|
||||
}
|
||||
var typeCode = colInfo.type_code();
|
||||
return new StepList<int>(0, 1, count).as_mutable().WrapSelector(GetValue, null);
|
||||
|
||||
object? GetId(int rowIndex) {
|
||||
var row = input.GetRow(rowIndex);
|
||||
return row.Id();
|
||||
}
|
||||
|
||||
object? GetValue(int rowIndex) {
|
||||
var rightIndex = rowIndex - period;
|
||||
if (rowIndex < 0 || rowIndex >= count || rightIndex < 0 || rightIndex >= count) {
|
||||
return null;
|
||||
}
|
||||
var leftRow = input.GetRow(rowIndex);
|
||||
var rightRow = input.GetRow(rightIndex);
|
||||
return GetDiff(leftRow[colIndex], rightRow[colIndex], typeCode);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
var count = input.Count;
|
||||
for (int i = 0; i < count; i++) {
|
||||
yield return GetRow(i);
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
new BlueRowColumnWrapper(input.schema, index, columns);
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int id = item.Id();
|
||||
var inputRow = input[id];
|
||||
int idx = input.IndexOf(inputRow);
|
||||
if (idx != -1) {
|
||||
var row = GetRow(idx);
|
||||
if (BlueRowEqualityComparer.Equals(item, row)) {
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static object? GetDiff(object? leftVal, object? rightVal, TypeCode colType) {
|
||||
if (leftVal is null || rightVal is null) {
|
||||
return null;
|
||||
}
|
||||
return colType switch {
|
||||
TypeCode.Int32 => (int)leftVal - (int)rightVal,
|
||||
TypeCode.Int64 => (long)leftVal - (long)rightVal,
|
||||
TypeCode.Double => (double)leftVal - (double)rightVal,
|
||||
TypeCode.String => ((string)leftVal).Replace((string)rightVal, string.Empty),
|
||||
TypeCode.DateTime => new DateTime(((DateTime)leftVal).Ticks - ((DateTime)rightVal).Ticks),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,506 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using Apache.Arrow;
|
||||
using Apache.Arrow.Ipc;
|
||||
using Apache.Arrow.Types;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.collections;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Threading;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[DataStreamUserRespresentation("featherReader")]
|
||||
public class FeatherReaderStream : ViewStream {
|
||||
readonly string file;
|
||||
FileStream fileStream;
|
||||
// Let the table leak in case some dangling references linger around after
|
||||
// myOnLastSubscriber is called. This should be fine since it disposes itself
|
||||
// in its finalizer.
|
||||
FeatherTable? table;
|
||||
|
||||
public FeatherReaderStream(string file) =>
|
||||
this.file = file;
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
if (!Path.Exists(file)) {
|
||||
throw new InvalidOperationException("Feather file does not exist");
|
||||
}
|
||||
fileStream = File.OpenRead(file);
|
||||
table = new(new ArrowStreamReader(fileStream));
|
||||
myFireEvent(new DataPacket(table, table, new BlueTableImmutable(table.schema)));
|
||||
}
|
||||
|
||||
interface IFeatherColumn {
|
||||
int Count { get; }
|
||||
|
||||
object? GetValue(int i);
|
||||
}
|
||||
|
||||
interface IFeatherColumn<T> : IFeatherColumn {
|
||||
new T? GetValue(int i);
|
||||
|
||||
object? IFeatherColumn.GetValue(int i) =>
|
||||
GetValue(i);
|
||||
}
|
||||
|
||||
class FeatherColumn : IFeatherColumn {
|
||||
readonly IArrowArray array;
|
||||
|
||||
public FeatherColumn(IArrowArray array) {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
public int Count => array.Length;
|
||||
|
||||
public static IFeatherColumn Create(IArrowArray array) =>
|
||||
array switch {
|
||||
Int32Array a => new FeatherInt32Column(a),
|
||||
Int64Array a => new FeatherInt64Column(a),
|
||||
DoubleArray a => new FeatherFloat64Column(a),
|
||||
StringArray a => new FeatherStringColumn(a),
|
||||
BooleanArray a => new FeatherBooleanColumn(a),
|
||||
Date64Array a => new FeatherDateTimeColumn(a),
|
||||
Time64Array a => new FeatherTimeStampColumn(a),
|
||||
_ => throw new NotSupportedException($"Unsupported type: {array.GetType()}")
|
||||
};
|
||||
|
||||
public object? GetValue(int i) =>
|
||||
array switch {
|
||||
Int32Array a => a.GetValue(i),
|
||||
Int64Array a => a.GetValue(i),
|
||||
DoubleArray a => a.GetValue(i),
|
||||
StringArray a => a.GetString(i),
|
||||
BooleanArray a => a.GetValue(i),
|
||||
Date64Array a => a.GetValue(i),
|
||||
Time64Array a => a.GetValue(i),
|
||||
_ => throw new NotSupportedException($"Unsupported type: {array.GetType()}")
|
||||
};
|
||||
}
|
||||
|
||||
class FeatherInt32Column : IFeatherColumn<int?> {
|
||||
readonly Int32Array array;
|
||||
|
||||
public FeatherInt32Column(Int32Array array) =>
|
||||
this.array = array;
|
||||
|
||||
public int Count => array.Length;
|
||||
|
||||
public int? GetValue(int i) => array.GetValue(i);
|
||||
}
|
||||
|
||||
class FeatherInt64Column : IFeatherColumn<long?> {
|
||||
readonly Int64Array array;
|
||||
|
||||
public FeatherInt64Column(Int64Array array) =>
|
||||
this.array = array;
|
||||
|
||||
public int Count => array.Length;
|
||||
|
||||
public long? GetValue(int i) => array.GetValue(i);
|
||||
}
|
||||
|
||||
class FeatherFloat64Column : IFeatherColumn<double?> {
|
||||
readonly DoubleArray array;
|
||||
|
||||
public FeatherFloat64Column(DoubleArray array) =>
|
||||
this.array = array;
|
||||
|
||||
public int Count => array.Length;
|
||||
|
||||
public double? GetValue(int i) => array.GetValue(i);
|
||||
}
|
||||
|
||||
class FeatherFloat32Column : IFeatherColumn<float?> {
|
||||
readonly FloatArray array;
|
||||
|
||||
public FeatherFloat32Column(FloatArray array) =>
|
||||
this.array = array;
|
||||
|
||||
public int Count => array.Length;
|
||||
|
||||
public float? GetValue(int i) => array.GetValue(i);
|
||||
}
|
||||
|
||||
class FeatherStringColumn : IFeatherColumn<string?> {
|
||||
readonly StringArray array;
|
||||
|
||||
public FeatherStringColumn(StringArray array) =>
|
||||
this.array = array;
|
||||
|
||||
public int Count => array.Length;
|
||||
|
||||
public string? GetValue(int i) => array.GetString(i);
|
||||
}
|
||||
|
||||
class FeatherBooleanColumn : IFeatherColumn<bool?> {
|
||||
readonly BooleanArray array;
|
||||
|
||||
public FeatherBooleanColumn(BooleanArray array) =>
|
||||
this.array = array;
|
||||
|
||||
public int Count => array.Length;
|
||||
|
||||
public bool? GetValue(int i) => array.GetValue(i);
|
||||
}
|
||||
|
||||
class FeatherDateTimeColumn : IFeatherColumn<DateTime?> {
|
||||
readonly Date64Array array;
|
||||
|
||||
public FeatherDateTimeColumn(Date64Array array) =>
|
||||
this.array = array;
|
||||
|
||||
public int Count => array.Length;
|
||||
|
||||
public DateTime? GetValue(int i) {
|
||||
var nanos = array.GetValue(i);
|
||||
if (!nanos.HasValue) {
|
||||
return null;
|
||||
}
|
||||
return new(nanos.Value / 100);
|
||||
}
|
||||
}
|
||||
|
||||
class FeatherTimeStampColumn : IFeatherColumn<DateTime?> {
|
||||
readonly Time64Array array;
|
||||
|
||||
public FeatherTimeStampColumn(Time64Array array) =>
|
||||
this.array = array;
|
||||
|
||||
public int Count => array.Length;
|
||||
|
||||
public DateTime? GetValue(int i) {
|
||||
var nanos = array.GetValue(i);
|
||||
if (!nanos.HasValue) {
|
||||
return null;
|
||||
}
|
||||
return new(nanos.Value / 100);
|
||||
}
|
||||
}
|
||||
|
||||
class FeatherBlueRow : IBlueRow {
|
||||
readonly int id;
|
||||
readonly int rowIndex;
|
||||
readonly IFeatherColumn[] data;
|
||||
|
||||
public FeatherBlueRow(int id, int rowIndex, IFeatherColumn[] data, IBlueTableSchema schema) {
|
||||
this.id = id;
|
||||
this.rowIndex = rowIndex;
|
||||
this.data = data;
|
||||
Schema = schema;
|
||||
}
|
||||
|
||||
public object? this[int index] =>
|
||||
index == 0
|
||||
? id
|
||||
: data[index - 1].GetValue(rowIndex);
|
||||
|
||||
public IBlueTableSchema Schema { get; }
|
||||
IBlueTableSchema IBlueRow.schema => Schema;
|
||||
}
|
||||
|
||||
class FeatherColumnDataList : IReadOnlyList<object?> {
|
||||
// Represents 1 column split into batches (hence it being an array)
|
||||
readonly IReadOnlyList<IFeatherColumn> columns;
|
||||
int? count;
|
||||
|
||||
public FeatherColumnDataList(IReadOnlyList<IFeatherColumn> columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public object? this[int index] {
|
||||
get {
|
||||
for (int i = 0; i < columns.Count; i++) {
|
||||
var col = columns[i];
|
||||
if (index < col.Count) {
|
||||
return col.GetValue(index);
|
||||
}
|
||||
index -= col.Count;
|
||||
}
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public int Count =>
|
||||
count ??= columns.Sum(c => c.Count);
|
||||
|
||||
public IEnumerator<object?> GetEnumerator() {
|
||||
for (int i = 0; i < columns.Count; i++) {
|
||||
var col = columns[i];
|
||||
for (int j = 0; j < col.Count; j++) {
|
||||
yield return col.GetValue(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() =>
|
||||
GetEnumerator();
|
||||
}
|
||||
|
||||
class FeatherTable : IImmutableRowCollection, IDisposable {
|
||||
ImmutableList<(RecordBatch Records, IFeatherColumn[] Columns)> recordBatches = ImmutableList<(RecordBatch Records, IFeatherColumn[] Columns)>.Empty;
|
||||
readonly IReadOnlyDictionary<string, Field> fields;
|
||||
readonly AtomicGate gate = new();
|
||||
int count;
|
||||
ArrowStreamReader? reader;
|
||||
|
||||
public FeatherTable(ArrowStreamReader reader) {
|
||||
this.reader = reader;
|
||||
if (reader.Schema is null) {
|
||||
var batch = reader.ReadNextRecordBatch();
|
||||
Log.notnull(batch);
|
||||
Log.notnull(reader.Schema);
|
||||
var fcols = new IFeatherColumn[batch.ColumnCount];
|
||||
for (int i = 0; i < fcols.Length; i++) {
|
||||
fcols[i] = FeatherColumn.Create(batch.Column(i));
|
||||
}
|
||||
recordBatches = recordBatches.Add((batch, fcols));
|
||||
count = batch.Length;
|
||||
}
|
||||
fields = reader.Schema.Fields;
|
||||
var columns = new ColumnInfo[fields.Count + 1];
|
||||
columns[0] = new("id", 0, typeof(int));
|
||||
for (int i = 0; i < fields.Count; i++) {
|
||||
var f = reader.Schema.GetFieldByIndex(i);
|
||||
Log.assert(f.Name != "id");
|
||||
columns[i + 1] = new(f.Name, i + 1, getFieldType(f));
|
||||
}
|
||||
schema = new BlueTableSchema("FeatherReader", columns);
|
||||
}
|
||||
|
||||
~FeatherTable() =>
|
||||
Disposable.DisposeThreadSafe(ref reader);
|
||||
|
||||
public IBlueTableSchema schema { get; }
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
if (reader is not null) {
|
||||
readBatches().Wait();
|
||||
Log.isnull(reader);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] => GetRow(id - 1);
|
||||
|
||||
public bool containsID(int id) {
|
||||
while (id > count && reader is not null) {
|
||||
readBatches(1).Wait();
|
||||
}
|
||||
return id <= count;
|
||||
}
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int id = item.Id();
|
||||
while (id > count && reader is not null) {
|
||||
readBatches(1).Wait();
|
||||
}
|
||||
return id <= count && BlueRowEqualityComparer.Equals(GetRow(id - 1), item)
|
||||
? id - 1
|
||||
: -1;
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) {
|
||||
if (index < 0) {
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
if (count <= index) {
|
||||
readRows(index + 1).Wait();
|
||||
}
|
||||
int id = index + 1;
|
||||
foreach (var (records, columns) in recordBatches) {
|
||||
if (index < records.Length) {
|
||||
return new FeatherBlueRow(id, index, columns, schema);
|
||||
}
|
||||
index -= records.Length;
|
||||
}
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
public IList<object?> GetColumn(int index) =>
|
||||
new FeatherColumnDataList(new MyColList(this, index)).as_mutable();
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
int i = 0;
|
||||
foreach (var (records, columns) in recordBatches) {
|
||||
yield return new FeatherBlueRow(i + 1, i, columns, schema);
|
||||
i++;
|
||||
}
|
||||
while (reader is not null) {
|
||||
var task = readBatches(1);
|
||||
task.Wait();
|
||||
if (!task.Result) {
|
||||
break;
|
||||
}
|
||||
yield return new FeatherBlueRow(i + 1, i, recordBatches[i].Columns, schema);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() =>
|
||||
Disposable.DisposeThreadSafe(ref reader);
|
||||
|
||||
static Type getFieldType(Field f) =>
|
||||
f.DataType.TypeId switch {
|
||||
ArrowTypeId.Null => throw new NotImplementedException(),
|
||||
ArrowTypeId.Boolean => typeof(bool),
|
||||
ArrowTypeId.UInt8 => typeof(byte),
|
||||
ArrowTypeId.Int8 => typeof(sbyte),
|
||||
ArrowTypeId.UInt16 => typeof(ushort),
|
||||
ArrowTypeId.Int16 => typeof(short),
|
||||
ArrowTypeId.UInt32 => typeof(uint),
|
||||
ArrowTypeId.Int32 => typeof(int),
|
||||
ArrowTypeId.UInt64 => typeof(ulong),
|
||||
ArrowTypeId.Int64 => typeof(long),
|
||||
ArrowTypeId.HalfFloat => throw new NotImplementedException(),
|
||||
ArrowTypeId.Float => typeof(float),
|
||||
ArrowTypeId.Double => typeof(double),
|
||||
ArrowTypeId.String => typeof(string),
|
||||
ArrowTypeId.Binary => throw new NotImplementedException(),
|
||||
ArrowTypeId.FixedSizedBinary => throw new NotImplementedException(),
|
||||
ArrowTypeId.Date32 => throw new NotImplementedException(),
|
||||
ArrowTypeId.Date64 => throw new NotImplementedException(),
|
||||
ArrowTypeId.Timestamp => throw new NotImplementedException(),
|
||||
ArrowTypeId.Time32 => throw new NotImplementedException(),
|
||||
ArrowTypeId.Time64 => throw new NotImplementedException(),
|
||||
ArrowTypeId.Interval => throw new NotImplementedException(),
|
||||
ArrowTypeId.Decimal128 => throw new NotImplementedException(),
|
||||
ArrowTypeId.Decimal256 => throw new NotImplementedException(),
|
||||
ArrowTypeId.List => throw new NotImplementedException(),
|
||||
ArrowTypeId.Struct => throw new NotImplementedException(),
|
||||
ArrowTypeId.Union => throw new NotImplementedException(),
|
||||
ArrowTypeId.Dictionary => throw new NotImplementedException(),
|
||||
ArrowTypeId.Map => throw new NotImplementedException(),
|
||||
_ => throw new ArgumentException("Unsupported field type", nameof(f)),
|
||||
};
|
||||
|
||||
async Task<bool> readRows(int minCount) {
|
||||
if (reader is null) {
|
||||
return count >= minCount;
|
||||
}
|
||||
int n = 0;
|
||||
using (gate.BeginTransaction()) {
|
||||
if (reader is not null) {
|
||||
int origCount = count;
|
||||
while ((count + n) < minCount) {
|
||||
Log.assert(count == origCount);
|
||||
var batch = await reader.ReadNextRecordBatchAsync();
|
||||
if (batch is null) {
|
||||
Disposable.dispose(ref reader);
|
||||
break;
|
||||
}
|
||||
var columns = new IFeatherColumn[batch.ColumnCount];
|
||||
for (int i = 0; i < columns.Length; i++) {
|
||||
columns[i] = FeatherColumn.Create(batch.Column(i));
|
||||
}
|
||||
recordBatches.Add((batch, columns));
|
||||
n += batch.Length;
|
||||
}
|
||||
count += n;
|
||||
}
|
||||
}
|
||||
return count >= minCount;
|
||||
}
|
||||
|
||||
async Task<bool> readBatches(int? count = null) {
|
||||
if (reader is null) {
|
||||
return !count.HasValue || count.Value == 0;
|
||||
}
|
||||
if (count.HasValue && count.Value <= recordBatches.Count) {
|
||||
return true;
|
||||
}
|
||||
int n = 0;
|
||||
using (gate.BeginTransaction()) {
|
||||
if (reader is not null) {
|
||||
int origCount = this.count;
|
||||
var recordBatchesBd = recordBatches.ToBuilder();
|
||||
while (!count.HasValue || count-- > recordBatchesBd.Count) {
|
||||
Log.assert(count == origCount);
|
||||
var batch = await reader.ReadNextRecordBatchAsync();
|
||||
if (batch is null) {
|
||||
Disposable.dispose(ref reader);
|
||||
break;
|
||||
}
|
||||
var columns = new IFeatherColumn[batch.ColumnCount];
|
||||
for (int i = 0; i < columns.Length; i++) {
|
||||
columns[i] = FeatherColumn.Create(batch.Column(i));
|
||||
}
|
||||
recordBatchesBd.Add((batch, columns));
|
||||
n += batch.Length;
|
||||
}
|
||||
recordBatches = recordBatchesBd.ToImmutable();
|
||||
this.count += n;
|
||||
}
|
||||
}
|
||||
return !count.HasValue || count.Value <= recordBatches.Count;
|
||||
}
|
||||
|
||||
class MyColList : IReadOnlyList<IFeatherColumn> {
|
||||
readonly FeatherTable owner;
|
||||
readonly int columnIndex;
|
||||
|
||||
public MyColList(FeatherTable owner, int columnIndex) {
|
||||
this.owner = owner;
|
||||
this.columnIndex = columnIndex;
|
||||
}
|
||||
|
||||
public IFeatherColumn this[int index] {
|
||||
get {
|
||||
if (index < 0) {
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
if (index >= owner.recordBatches.Count) {
|
||||
var task = owner.readBatches(index + 1);
|
||||
task.Wait();
|
||||
if (!task.Result) {
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
return owner.recordBatches[index].Columns[columnIndex];
|
||||
}
|
||||
}
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
if (owner.reader is not null) {
|
||||
owner.readBatches().Wait();
|
||||
}
|
||||
return owner.recordBatches.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<IFeatherColumn> GetEnumerator() {
|
||||
int i = 0;
|
||||
foreach (var batch in owner.recordBatches) {
|
||||
yield return batch.Columns[columnIndex];
|
||||
i++;
|
||||
}
|
||||
while (owner.reader is not null) {
|
||||
var task = owner.readBatches(1);
|
||||
task.Wait();
|
||||
if (!task.Result) {
|
||||
break;
|
||||
}
|
||||
yield return owner.recordBatches[i].Columns[columnIndex];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() =>
|
||||
GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
[DataStreamUserRespresentation("FilterStream")]
|
||||
public class FilterStream : ViewStream {
|
||||
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() ?? string.Empty);
|
||||
if (!rv)
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
BlueTableImmutable? myLastFiredRows;
|
||||
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() ?? string.Empty;
|
||||
if (filter is IDynamicStreamFilter dynFilter) {
|
||||
dynFilter.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 += myHandleCallbacks;
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
myLastFiredRows = null;
|
||||
myParentStream.onChange -= myHandleCallbacks;
|
||||
}
|
||||
|
||||
protected override void myFireEvent(object o) {
|
||||
var dp = ExceptionAssert.Argument.Is<IDataPacket>(o);
|
||||
if (myLastValue == null || dp.addedRows.Count + dp.deletedRows.Count > 0)
|
||||
base.myFireEvent(o);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void myHandleCallbacks(object newValue) {
|
||||
var arrivedPacket = ExceptionAssert.Argument.Is<IDataPacket>(newValue);
|
||||
myLastReceivedRows = arrivedPacket.newRows;
|
||||
var bd = (myLastFiredRows ?? new BlueTableImmutable(arrivedPacket.Schema)).ToDataPacketBuilder();
|
||||
foreach (IBlueRow r in arrivedPacket.deletedRows) {
|
||||
// Don't bother evaluating the filter, just try to remove the row. The latter is
|
||||
// cheaper than the former (it's a noop if this row wasn't in the filtered table).
|
||||
bd.Remove(r.Id());
|
||||
}
|
||||
foreach (IBlueRow r in arrivedPacket.newRows) {
|
||||
if (myFilter.filter(r)) {
|
||||
bd.AddOrUpdate(r);
|
||||
}
|
||||
}
|
||||
var dpOut = bd.ToDataPacket(out myLastFiredRows);
|
||||
myFireEvent(dpOut);
|
||||
}
|
||||
|
||||
public IStreamFilter filter {
|
||||
set {
|
||||
{
|
||||
myFilter = value;
|
||||
if (numberOfSubscribers > 0) {
|
||||
if (myLastReceivedRows != null) {
|
||||
var bd = (myLastFiredRows ?? new BlueTableImmutable(myLastReceivedRows.schema)).ToDataPacketBuilder();
|
||||
foreach (IBlueRow r in myLastReceivedRows) {
|
||||
int id = r.Id();
|
||||
bool includeNow = myFilter.filter(r);
|
||||
bool includeBefore = myLastFiredRows?.containsID(id) ?? false;
|
||||
if (includeNow == includeBefore) {
|
||||
continue;
|
||||
}
|
||||
if (includeNow) {
|
||||
bd.AddOrUpdate(r);
|
||||
} else {
|
||||
bd.Remove(id);
|
||||
}
|
||||
}
|
||||
var dpOut = bd.ToDataPacket(out myLastFiredRows);
|
||||
myFireEvent(dpOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
get {
|
||||
return myFilter;
|
||||
}
|
||||
}
|
||||
|
||||
//public string filterString { set { filter = new BooleanExpressionFilter(value); } }
|
||||
|
||||
public override string ToString() {
|
||||
return GetType().ToString() + " " + myFilterString;
|
||||
}
|
||||
|
||||
private void myHandleFilterChange() {
|
||||
filter = myFilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
namespace bts.BlueOrb;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class FilterTable : IBlueRowCollection {
|
||||
readonly IBlueRowCollection source;
|
||||
readonly HashSet<int> excludedIndices = new();
|
||||
readonly Dictionary<int, (int Index, int NumSkips, bool Included, IBlueRow Row)> rowMap = new();
|
||||
readonly List<int> filteredIndexToId = new();
|
||||
|
||||
public FilterTable(IBlueRowCollection source, Func<IBlueRow, bool> filter) {
|
||||
this.source = source;
|
||||
int idx = 0;
|
||||
int numSkips = 0;
|
||||
foreach (var r in source) {
|
||||
int id = r.Id();
|
||||
bool included = filter(r);
|
||||
rowMap.Add(id, (idx, numSkips, included, r));
|
||||
if (!included) {
|
||||
excludedIndices.Add(idx);
|
||||
numSkips++;
|
||||
} else {
|
||||
filteredIndexToId.Add(id);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] {
|
||||
get {
|
||||
var r = rowMap[id];
|
||||
return r.Included ? r.Row : throw new KeyNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueTableSchema schema => source.schema;
|
||||
|
||||
public int Count => filteredIndexToId.Count;
|
||||
|
||||
public bool containsID(int id) =>
|
||||
rowMap.TryGetValue(id, out var r) && r.Included;
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
int idx = 0;
|
||||
foreach (var r in source) {
|
||||
if (!excludedIndices.Contains(idx)) {
|
||||
yield return r;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) {
|
||||
if (index < 0 || index >= source.Count) {
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
var id = filteredIndexToId[index];
|
||||
return rowMap[id].Row;
|
||||
}
|
||||
|
||||
public int IndexOf(IBlueRow item) =>
|
||||
rowMap.TryGetValue(item.Id(), out var r)
|
||||
&& r.Included
|
||||
&& BlueRowEqualityComparer.Equals(r.Row, item)
|
||||
? r.Index - r.NumSkips
|
||||
: -1;
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
namespace Bts.SharedStreams.StreamFactories;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts;
|
||||
using bts.api.core;
|
||||
using bts.BlueOrb;
|
||||
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
|
||||
public class GroupByApplyStream : ViewStream {
|
||||
readonly ViewStream inputStream;
|
||||
readonly IFunctionEvaluator groupBy;
|
||||
readonly IFunctionEvaluator apply;
|
||||
|
||||
public GroupByApplyStream(ViewStream inputStream, IFunctionEvaluator groupBy, IFunctionEvaluator apply) {
|
||||
this.inputStream = inputStream;
|
||||
this.groupBy = groupBy;
|
||||
this.apply = apply;
|
||||
}
|
||||
|
||||
public static IObservable<TableUpdate<IBlueRow, int>> CreateGroupByApplyTable(ViewStream inputStream, IFunctionEvaluator groupBy, IFunctionEvaluator apply) =>
|
||||
CreateApplyTable(CreateGroupByTable(inputStream, groupBy), apply);
|
||||
|
||||
public static IObservable<TableUpdate<IBlueRow, int>> CreateApplyTable<TGroupKey>(IObservable<TableUpdate<TableUpdateGrouping<IBlueRow, int, TGroupKey>, TGroupKey>> inputStream, Func<TGroupKey, IBlueRowCollection, IBlueRowCollection?> apply) where TGroupKey : IEquatable<TGroupKey> {
|
||||
var groupTables = ImmutableDictionary<TGroupKey, GroupTableBuilder>.Empty;
|
||||
var inputToOutputIds = ImmutableDictionary<int, int>.Empty;
|
||||
var outputToInputIds = ImmutableDictionary<int, int>.Empty;
|
||||
int idCounter = 0;
|
||||
|
||||
return Observable.Create<TableUpdate<IBlueRow, int>>(Subscribe);
|
||||
|
||||
int GetNextId() =>
|
||||
Interlocked.Increment(ref idCounter);
|
||||
|
||||
IDisposable Subscribe(IObserver<TableUpdate<IBlueRow, int>> observer) {
|
||||
int hashCounter = 0;
|
||||
var hashIndex = new Dictionary<TGroupKey, int>();
|
||||
var tableOut = TableUpdate<IBlueRow, int>.mk_empty(r => r.Id());
|
||||
return inputStream.Subscribe(OnNext, OnError, OnCompleted);
|
||||
|
||||
void OnNext(TableUpdate<TableUpdateGrouping<IBlueRow, int, TGroupKey>, TGroupKey> upd) {
|
||||
var bd = tableOut.to_builder();
|
||||
foreach (var group in upd.removed) {
|
||||
var hash = hashIndex[group.group_key];
|
||||
bd.remove(hash);
|
||||
}
|
||||
var groupTablesBd = groupTables.ToBuilder();
|
||||
foreach (var group in upd.added.Concat(upd.changed)) {
|
||||
Log.assert(group.table.state.Count > 0);
|
||||
var hash = hashIndex.GetOrAdd(group.group_key, _ => hashCounter++);
|
||||
var groupRowCollection = new TableUpdateGroupingRowCollection<TGroupKey>(group, group.table.state.Values.First().schema);
|
||||
var applyArgs = new (string?, int?, object?)[] { ("rows", 0, groupRowCollection) };
|
||||
var resRows = apply(group.group_key, groupRowCollection);
|
||||
if (resRows is null) {
|
||||
bd.remove(hash);
|
||||
continue;
|
||||
}
|
||||
UpdateGroupTable(group.group_key, resRows);
|
||||
}
|
||||
groupTables = groupTablesBd.ToImmutable();
|
||||
tableOut = bd.to_table();
|
||||
observer.OnNext(tableOut);
|
||||
|
||||
void UpdateGroupTable(TGroupKey groupKey, IBlueRowCollection groupRows) {
|
||||
var indexedRows = groupTablesBd.GetOrAdd(groupKey, _ => new(GetNextId)).Reset(groupRows);
|
||||
foreach (var r in indexedRows) {
|
||||
bd.add_or_update(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnError(Exception ex) {
|
||||
Log.DataFlow.error($$"""[stream_err.json]{ "typ": "{{nameof(GroupByApplyStream)}}", "inpTyp": {{inputStream.GetType()}}, "err": "{{ex}}" }""");
|
||||
}
|
||||
|
||||
void OnCompleted() {
|
||||
Log.DataFlow.warn($$"""[stream_fin.json]{ "typ": "{{nameof(GroupByApplyStream)}}", "inpTyp": "{{inputStream.GetType()}}" }""");
|
||||
}
|
||||
}
|
||||
|
||||
public static IObservable<TableUpdate<IBlueRow, int>> CreateApplyTable<TGroupKey>(IObservable<TableUpdate<TableUpdateGrouping<IBlueRow, int, TGroupKey>, TGroupKey>> inputStream, IFunctionEvaluator apply) where TGroupKey : IEquatable<TGroupKey> {
|
||||
var groupTables = ImmutableDictionary<TGroupKey, GroupTableBuilder>.Empty;
|
||||
var inputToOutputIds = ImmutableDictionary<int, int>.Empty;
|
||||
var outputToInputIds = ImmutableDictionary<int, int>.Empty;
|
||||
int idCounter = 0;
|
||||
|
||||
return Observable.Create<TableUpdate<IBlueRow, int>>(Subscribe);
|
||||
|
||||
int GetNextId() =>
|
||||
Interlocked.Increment(ref idCounter);
|
||||
|
||||
IDisposable Subscribe(IObserver<TableUpdate<IBlueRow, int>> observer) {
|
||||
int hashCounter = 0;
|
||||
var hashIndex = new Dictionary<TGroupKey, int>();
|
||||
var tableOut = TableUpdate<IBlueRow, int>.mk_empty(r => r.Id());
|
||||
return inputStream.Subscribe(OnNext, OnError, OnCompleted);
|
||||
|
||||
void OnNext(TableUpdate<TableUpdateGrouping<IBlueRow, int, TGroupKey>, TGroupKey> upd) {
|
||||
var bd = tableOut.to_builder();
|
||||
foreach (var group in upd.removed) {
|
||||
var hash = hashIndex[group.group_key];
|
||||
bd.remove(hash);
|
||||
}
|
||||
var groupTablesBd = groupTables.ToBuilder();
|
||||
foreach (var group in upd.added.Concat(upd.changed)) {
|
||||
Log.assert(group.table.state.Count > 0);
|
||||
var hash = hashIndex.GetOrAdd(group.group_key, _ => hashCounter++);
|
||||
var groupRowCollection = new TableUpdateGroupingRowCollection<TGroupKey>(group, group.table.state.Values.First().schema);
|
||||
var applyArgs = new StreamArgument[] { ("rows", 0, groupRowCollection) };
|
||||
var res = apply.Evaluate(string.Empty, applyArgs);
|
||||
if (res is IBlueRow resSingleRow) {
|
||||
UpdateGroupTable(group.group_key, new SingleRowTable(resSingleRow));
|
||||
} else if (res is IBlueRowCollection resRows) {
|
||||
UpdateGroupTable(group.group_key, resRows);
|
||||
} else {
|
||||
throw new InvalidOperationException("Invalid result returned by 'Apply' fn");
|
||||
}
|
||||
}
|
||||
groupTables = groupTablesBd.ToImmutable();
|
||||
tableOut = bd.to_table();
|
||||
observer.OnNext(tableOut);
|
||||
|
||||
void UpdateGroupTable(TGroupKey groupKey, IBlueRowCollection groupRows) {
|
||||
var indexedRows = groupTablesBd.GetOrAdd(groupKey, _ => new(GetNextId)).Reset(groupRows);
|
||||
foreach (var r in indexedRows) {
|
||||
bd.add_or_update(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnError(Exception ex) {
|
||||
Log.DataFlow.error($$"""[stream_err.json]{ "typ": "{{nameof(GroupByApplyStream)}}", "inpTyp": {{inputStream.GetType()}}, "err": "{{ex}}" }""");
|
||||
}
|
||||
|
||||
void OnCompleted() {
|
||||
Log.DataFlow.warn($$"""[stream_fin.json]{ "typ": "{{nameof(GroupByApplyStream)}}", "inpTyp": "{{inputStream.GetType()}}" }""");
|
||||
}
|
||||
}
|
||||
|
||||
public static IObservable<TableUpdate<TableUpdateGrouping<IBlueRow, int, EquatableKeyWrapper>, EquatableKeyWrapper>> CreateGroupByTable(ViewStream inputStream, IFunctionEvaluator groupBy) {
|
||||
return Observable.Create<TableUpdate<TableUpdateGrouping<IBlueRow, int, EquatableKeyWrapper>, EquatableKeyWrapper>>(Subscribe);
|
||||
|
||||
IDisposable Subscribe(IObserver<TableUpdate<TableUpdateGrouping<IBlueRow, int, EquatableKeyWrapper>, EquatableKeyWrapper>> observer) {
|
||||
TableUpdate<TableUpdateGrouping<IBlueRow, int, EquatableKeyWrapper>, EquatableKeyWrapper> tableOut = TableUpdate<TableUpdateGrouping<IBlueRow, int, EquatableKeyWrapper>, EquatableKeyWrapper>.mk_empty(r => r.group_key);
|
||||
return inputStream.AsObservable().AsTables().GroupTable(r => r.Id(), GroupKey).Subscribe(observer);
|
||||
|
||||
EquatableKeyWrapper GroupKey(IBlueRow r) {
|
||||
var groupByArgs = new StreamArgument[] { ("row", 0, r) };
|
||||
var groupKey = new EquatableKeyWrapper(groupBy.Evaluate(string.Empty, groupByArgs) ?? DBNull.Value);
|
||||
return groupKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IObservable<TableUpdate<TableUpdateGrouping<IBlueRow, int, EquatableKeyArrayWrapper>, EquatableKeyArrayWrapper>> CreateGroupByTable(ViewStream inputStream, string[] columns, bool useColumnIndices = true) {
|
||||
Func<IBlueRow, EquatableKeyArrayWrapper> groupBy;
|
||||
if (!useColumnIndices) {
|
||||
groupBy = GroupKeyByName;
|
||||
|
||||
EquatableKeyArrayWrapper GroupKeyByName(IBlueRow r) =>
|
||||
new(Array.ConvertAll(columns, c => r[c]));
|
||||
} else {
|
||||
int[]? columnIndices = null;
|
||||
groupBy = GroupKeyByIndex;
|
||||
|
||||
EquatableKeyArrayWrapper GroupKeyByIndex(IBlueRow r) {
|
||||
columnIndices ??= r.schema.ResolveIndices(columns);
|
||||
return new(Array.ConvertAll(columnIndices, c => r[c]));
|
||||
}
|
||||
}
|
||||
return CreateGroupByTable(inputStream, groupBy);
|
||||
}
|
||||
|
||||
public static IObservable<TableUpdate<TableUpdateGrouping<IBlueRow, int, TKey>, TKey>> CreateGroupByTable<TKey>(ViewStream inputStream, Func<IBlueRow, TKey> groupBy) where TKey : IEquatable<TKey> {
|
||||
return Observable.Create<TableUpdate<TableUpdateGrouping<IBlueRow, int, TKey>, TKey>>(Subscribe);
|
||||
|
||||
IDisposable Subscribe(IObserver<TableUpdate<TableUpdateGrouping<IBlueRow, int, TKey>, TKey>> observer) =>
|
||||
inputStream.AsObservable().AsTables().GroupTable(r => r.Id(), groupBy).Subscribe(observer);
|
||||
}
|
||||
|
||||
class GroupTableBuilder {
|
||||
readonly Func<int> getUniqueId;
|
||||
ImmutableDictionary<int, int> inputToOutputIds = ImmutableDictionary<int, int>.Empty;
|
||||
ImmutableDictionary<int, int> outputToInputIds = ImmutableDictionary<int, int>.Empty;
|
||||
IndexTable? current;
|
||||
|
||||
public GroupTableBuilder(Func<int> getUniqueId) =>
|
||||
this.getUniqueId = getUniqueId;
|
||||
|
||||
public IndexTable? Current => current;
|
||||
|
||||
public IndexTable Reset(IBlueRowCollection rows) {
|
||||
var inputToOutputIdsBd = inputToOutputIds.ToBuilder();
|
||||
var outputToInputIdsBd = outputToInputIds.ToBuilder();
|
||||
foreach (var r in rows) {
|
||||
int inputId = r.Id();
|
||||
if (!inputToOutputIdsBd.TryGetValue(inputId, out var outputId)) {
|
||||
outputId = getUniqueId();
|
||||
inputToOutputIdsBd.Add(inputId, outputId);
|
||||
outputToInputIdsBd.Add(outputId, inputId);
|
||||
}
|
||||
Log.assert(outputToInputIdsBd.TryGetValue(outputId, out var oinputId) && oinputId == inputId);
|
||||
Log.assert(inputToOutputIdsBd.TryGetValue(inputId, out var ioutputId) && ioutputId == outputId);
|
||||
}
|
||||
inputToOutputIds = inputToOutputIdsBd.ToImmutable();
|
||||
outputToInputIds = outputToInputIdsBd.ToImmutable();
|
||||
current = new(rows, outputToInputIds, inputToOutputIds);
|
||||
return current;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
using bts;
|
||||
//using bts.SilverPine;
|
||||
using BCG;
|
||||
using mbts.utils;
|
||||
|
||||
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 is null || out_rows.Count == 0) {
|
||||
continue;
|
||||
}
|
||||
rv ??= new BlueTable(out_rows.ElementAt(0).schema);
|
||||
rv.addRows(out_rows);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public string[]? get_group_by_cols() {
|
||||
return _groupby_cols_func();
|
||||
}
|
||||
}
|
||||
readonly ViewStream? _main_stream;
|
||||
readonly INonIncGroupByEvaluator? _groupby_func;
|
||||
readonly string[]? _groupby_cols;
|
||||
readonly Stopwatch _timer = new();
|
||||
|
||||
BlueRowHasher? _row_hasher;
|
||||
int _n_total_fires = 0;
|
||||
int _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_cols, string standard_group_by_text)
|
||||
: this(parent_str, groupby_cols, standard_group_by_text, String.Empty) { }
|
||||
|
||||
// this is the main constructor that does everything
|
||||
public GroupByStream(ViewStream parent_str, string groupby_cols, 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 = () => {
|
||||
if (String.IsNullOrEmpty(groupby_cols))
|
||||
return null;
|
||||
return groupby_cols.Split(',').Select(x => x.Trim()).ToArray();
|
||||
};
|
||||
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);
|
||||
if (rv == null)
|
||||
return new List<IBlueRow>();
|
||||
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() { Log.notnull(_main_stream).onChange += _main_stream_onchange; }
|
||||
|
||||
protected override void myOnLastSubscriber() { Log.notnull(_main_stream).onChange -= _main_stream_onchange; }
|
||||
|
||||
private void _main_stream_onchange(object nv) {
|
||||
var dp = ExceptionAssert.Argument.Is<IDataPacket>(nv);
|
||||
///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();
|
||||
var total_state = Log.notnull(_groupby_func).evaluate(grouped_rows);
|
||||
if (total_state == null)
|
||||
// mayeb returna n empty table ?
|
||||
return;
|
||||
_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}");
|
||||
}
|
||||
myFireEvent(new DataPacket(total_state, total_state, myLastValue == null ? new BlueTable(total_state.schema) : (myLastValue as DataPacket).newRows));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 2528 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user