Compare commits
160
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84351460b5 | ||
|
|
9a1fee4e83 | ||
|
|
dd55866056 | ||
|
|
8f6e2b8512 | ||
|
|
b9a36f5d51 | ||
|
|
3a3bec5821 | ||
|
|
05a5e9dcf8 | ||
|
|
b1211ed590 | ||
|
|
d9a2ab00f8 | ||
|
|
22ea8a7070 | ||
|
|
1b7543e94b | ||
|
|
c66d8c1f99 | ||
|
|
87d6a97198 | ||
|
|
cf05d07692 | ||
|
|
9ccc4467ba | ||
|
|
9c2223b4da | ||
|
|
b09a39ceb6 | ||
|
|
8ebf437c9e | ||
|
|
160dbb624f | ||
|
|
da945b39c7 | ||
|
|
bfede66c31 | ||
|
|
bc39b8fda9 | ||
|
|
12fadab839 | ||
|
|
bcbfc56e7d | ||
|
|
efd389ea46 | ||
|
|
ce236da67b | ||
|
|
e91fb32207 | ||
|
|
0cf576a055 | ||
|
|
7213b05c9e | ||
|
|
19a6f53cfa | ||
|
|
7a53bf4b01 | ||
|
|
965186874e | ||
|
|
f8704dd083 | ||
|
|
93c2770abe | ||
|
|
f422b752a4 | ||
|
|
d6f7031716 | ||
|
|
5d34bdbecf | ||
|
|
0c96c3bc06 | ||
|
|
1da06732e2 | ||
|
|
641f00b4e0 | ||
|
|
d860573910 | ||
|
|
fa8f623263 | ||
|
|
706d9235ca | ||
|
|
03c99cc3df | ||
|
|
fc050f4bd3 | ||
|
|
39b3490f5a | ||
|
|
a0ef2c3348 | ||
|
|
acb420d4cc | ||
|
|
ab07697985 | ||
|
|
6ad7418931 | ||
|
|
783764fc1f | ||
|
|
5771b19c18 | ||
|
|
ee5b78ed9c | ||
|
|
d609dcd3c2 | ||
|
|
7b266cd4d0 | ||
|
|
de8593af5a | ||
|
|
ab6f6e1790 | ||
|
|
51e38ca793 | ||
|
|
7b2bc4b10c | ||
|
|
05cae5c959 | ||
|
|
aaca8f0f3a | ||
|
|
59a16677d1 | ||
|
|
50e7bba3d7 | ||
|
|
6026ca0c62 | ||
|
|
253512cef8 | ||
|
|
ae050d9401 | ||
|
|
eb0f386328 | ||
|
|
b5aca5637c | ||
|
|
685507eed4 | ||
|
|
6567baa7d5 | ||
|
|
39dc6c24ed | ||
|
|
317a8cee60 | ||
|
|
9bb7beabc2 | ||
|
|
2364c82254 | ||
|
|
b3114f2a62 | ||
|
|
b64a8ba214 | ||
|
|
b257b673fb | ||
|
|
43df2bbdc5 | ||
|
|
5f80492c93 | ||
|
|
5a63b25a8f | ||
|
|
5647beed40 | ||
|
|
d3900e3149 | ||
|
|
221505e243 | ||
|
|
d16c696ecf | ||
|
|
c371fd8e99 | ||
|
|
16fb295a37 | ||
|
|
bb157c768c | ||
|
|
8c9ac51bb6 | ||
|
|
39d04285d0 | ||
|
|
41db558841 | ||
|
|
cdebdd5765 | ||
|
|
bb7a000689 | ||
|
|
d62816ac0b | ||
|
|
964ec5b565 | ||
|
|
46247b6439 | ||
|
|
10e862074c | ||
|
|
9ce0bd1e35 | ||
|
|
6d93cf856f | ||
|
|
fd68164eef | ||
|
|
863efdd53f | ||
|
|
3d94eabab7 | ||
|
|
450ef9985a | ||
|
|
0bf7e209a0 | ||
|
|
b5c666c505 | ||
|
|
198cda76a8 | ||
|
|
dc17774e07 | ||
|
|
c9c33045f4 | ||
|
|
e36b3bf115 | ||
|
|
a6383c08a4 | ||
|
|
ee651061b9 | ||
|
|
2a497b460d | ||
|
|
ac5edfb0ce | ||
|
|
54cf46e926 | ||
|
|
116778a0cc | ||
|
|
f7b835997e | ||
|
|
c920c6f3a9 | ||
|
|
36de4d1578 | ||
|
|
0571cb40a0 | ||
|
|
1ca6acdd23 | ||
|
|
f4f3c881db | ||
|
|
36e150f6c7 | ||
|
|
f98b435e0b | ||
|
|
dce4c5f543 | ||
|
|
d4d696e135 | ||
|
|
bb818d9dcc | ||
|
|
14e838de6a | ||
|
|
6fe35e2692 | ||
|
|
08f9784ed0 | ||
|
|
bde4ee6308 | ||
|
|
03116a2973 | ||
|
|
d0d6d587d7 | ||
|
|
765e45d95a | ||
|
|
cd833ceb36 | ||
|
|
a148a03175 | ||
|
|
338edfd732 | ||
|
|
2a9ca60654 | ||
|
|
03a677df4c | ||
|
|
07b32e4da4 | ||
|
|
3b1b74a1bf | ||
|
|
645a447248 | ||
|
|
4580a1af21 | ||
|
|
85a68a14c6 | ||
|
|
3476bbca02 | ||
|
|
fdb1811f03 | ||
|
|
7db9f9368b | ||
|
|
983eb24584 | ||
|
|
312aa9c669 | ||
|
|
a11b0959bb | ||
|
|
4c6702b506 | ||
|
|
e0e0c408a5 | ||
|
|
db2bd425be | ||
|
|
2af3c6e98d | ||
|
|
74c1ef8dab | ||
|
|
e3bcfa792c | ||
|
|
8f55916fe0 | ||
|
|
9fbf509b30 | ||
|
|
2004b76ebc | ||
|
|
614e4de884 | ||
|
|
0ba34da70e | ||
|
|
826c1164be |
No files matched your search
@@ -25,6 +25,12 @@
|
||||
"commands": [
|
||||
"fake"
|
||||
]
|
||||
},
|
||||
"dotnet-t4": {
|
||||
"version": "3.0.0",
|
||||
"commands": [
|
||||
"t4"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
-16
@@ -207,17 +207,23 @@ dotnet_naming_symbols.parameters.applicable_accessibilities = public,internal,pr
|
||||
dotnet_naming_symbols.private_symbols.applicable_kinds = property,method,field,event,delegate
|
||||
dotnet_naming_symbols.private_symbols.applicable_accessibilities = protected,private
|
||||
|
||||
# local symbols
|
||||
dotnet_naming_symbols.local_symbols.applicable_kinds = local
|
||||
|
||||
# parameter symbols
|
||||
dotnet_naming_symbols.parameter_symbols.applicable_kinds = parameter
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.snake_case.required_prefix =
|
||||
dotnet_naming_style.snake_case.required_suffix =
|
||||
dotnet_naming_style.snake_case.word_separator = _
|
||||
dotnet_naming_style.snake_case.capitalization = all_lower
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.private_snake_case.required_prefix = _
|
||||
dotnet_naming_style.private_snake_case.required_suffix =
|
||||
dotnet_naming_style.private_snake_case.word_separator = _
|
||||
dotnet_naming_style.private_snake_case.capitalization = all_lower
|
||||
dotnet_naming_style.camel_case.required_prefix =
|
||||
dotnet_naming_style.camel_case.required_suffix =
|
||||
dotnet_naming_style.camel_case.word_separator =
|
||||
dotnet_naming_style.camel_case.capitalization = camel_case
|
||||
|
||||
dotnet_naming_style.user_types.required_prefix =
|
||||
dotnet_naming_style.user_types.required_suffix =
|
||||
@@ -229,6 +235,10 @@ dotnet_naming_style.interface.required_suffix =
|
||||
dotnet_naming_style.interface.word_separator =
|
||||
dotnet_naming_style.interface.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.local.capitalization = camel_case
|
||||
|
||||
dotnet_naming_style.parameter.capitalization = camel_case
|
||||
|
||||
# rules
|
||||
dotnet_naming_rule.user_types.symbols = user_types
|
||||
dotnet_naming_rule.user_types.style = user_types
|
||||
@@ -238,14 +248,18 @@ dotnet_naming_rule.interfaces.symbols = interface
|
||||
dotnet_naming_rule.interfaces.style = interface_style
|
||||
dotnet_naming_rule.interfaces.severity = suggestion
|
||||
|
||||
dotnet_naming_rule.public_members_snake_case.symbols = public_symbols
|
||||
dotnet_naming_rule.public_members_snake_case.style = snake_case
|
||||
dotnet_naming_rule.public_members_snake_case.severity = suggestion
|
||||
dotnet_naming_rule.public_members.symbols = public_symbols
|
||||
dotnet_naming_rule.public_members.style = pascal_case
|
||||
dotnet_naming_rule.public_members.severity = suggestion
|
||||
|
||||
dotnet_naming_rule.private_members_snake_case.symbols = private_symbols
|
||||
dotnet_naming_rule.private_members_snake_case.style = private_snake_case
|
||||
dotnet_naming_rule.private_members_snake_case.severity = suggestion
|
||||
dotnet_naming_rule.private_members.symbols = private_symbols
|
||||
dotnet_naming_rule.private_members.style = camel_case
|
||||
dotnet_naming_rule.private_members.severity = suggestion
|
||||
|
||||
dotnet_naming_rule.parameters.symbols = parameters
|
||||
dotnet_naming_rule.parameters.style = snake_case
|
||||
dotnet_naming_rule.variables_are_camel_case.severity = suggestion
|
||||
dotnet_naming_rule.variables_are_camel_case.symbols = local_symbols
|
||||
dotnet_naming_rule.variables_are_camel_case.style = local
|
||||
|
||||
dotnet_naming_rule.parameters.symbols = parameter_symbols
|
||||
dotnet_naming_rule.parameters.style = parameter
|
||||
dotnet_naming_rule.parameters.severity = suggestion
|
||||
Vendored
+181
-22
@@ -14,6 +14,68 @@
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
},
|
||||
{
|
||||
"name": "Api Server",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"windows": {
|
||||
"preLaunchTask": "Build Api Server (Debug)",
|
||||
"program": "spark_api_server.exe",
|
||||
"args": [
|
||||
"run",
|
||||
"--sparkd",
|
||||
"http://127.0.0.1:8000/config"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Api Server (Skip Build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"windows": {
|
||||
"program": "spark_api_server.exe",
|
||||
"args": [
|
||||
"run",
|
||||
"--sparkd",
|
||||
"http://127.0.0.1:8000/config"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Bts.DataStreamWebApp.Server",
|
||||
"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",
|
||||
"env": {
|
||||
"ASPNETCORE_HTTP_PORT": "8080",
|
||||
"ASPNETCORE_HTTPS_PORT": "8443",
|
||||
"ASPNETCORE_ENVIRONMENT": "${input:dataStreamWebAppServerEnvironment}",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy",
|
||||
}
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"env": {
|
||||
"ASPNETCORE_HTTP_PORT": "8080",
|
||||
"ASPNETCORE_HTTPS_PORT": "8443",
|
||||
"ASPNETCORE_ENVIRONMENT": "${input:dataStreamWebAppServerEnvironment}",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy",
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "DataStreamPublisher",
|
||||
"type": "coreclr",
|
||||
@@ -26,11 +88,28 @@
|
||||
"windows": {
|
||||
"program": "DataStreamPublisher.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "DataStreamPublisher (Skip Build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"linux": {
|
||||
"program": "DataStreamPublisher",
|
||||
},
|
||||
"windows": {
|
||||
"program": "DataStreamPublisher.exe",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
@@ -82,16 +161,29 @@
|
||||
"name": "DataStreamQueryAnalyzer",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
//"preLaunchTask": "Build DataStreamQueryAnalyzer (Debug)",
|
||||
"preLaunchTask": "Build DataStreamQueryAnalyzer (Debug)",
|
||||
"program": "",
|
||||
"windows": {
|
||||
"program": "DataStreamQueryAnalyzer.exe",
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"env": {
|
||||
"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"
|
||||
},
|
||||
},
|
||||
@@ -110,11 +202,28 @@
|
||||
"windows": {
|
||||
"program": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "PubSubServer (Skip Build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"linux": {
|
||||
"program": "PubSubServer",
|
||||
},
|
||||
"windows": {
|
||||
"program": "PubSubServer.exe",
|
||||
},
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
@@ -127,6 +236,9 @@
|
||||
"preLaunchTask": "Build Spark (Debug)",
|
||||
"program": "Spark.exe",
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:sparkEnvironment}",
|
||||
}
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
@@ -139,6 +251,9 @@
|
||||
"windows": {
|
||||
"program": "Spark.exe",
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:sparkEnvironment}",
|
||||
}
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
@@ -252,26 +367,60 @@
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"id": "dataStreamPublisherConfig",
|
||||
"id": "dataStreamPublisherEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "Publisher Configuration",
|
||||
"options": [
|
||||
"MarketDataPublisher",
|
||||
"SimpleEchoClient",
|
||||
"SimpleTestDataPublisher",
|
||||
"TestDataPublisher",
|
||||
"Development",
|
||||
"MarketData",
|
||||
"Production",
|
||||
"ProductionAws",
|
||||
"Staging",
|
||||
],
|
||||
"default": "MarketDataPublisher",
|
||||
},
|
||||
{
|
||||
"id": "pubSubServerConfig",
|
||||
"id": "pubSubServerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "PubSub Configuration",
|
||||
"options": [
|
||||
"PubSubServer",
|
||||
"SimpleEchoClient",
|
||||
"Development",
|
||||
"EchoServer",
|
||||
"Production",
|
||||
"ProductionAws",
|
||||
"Staging",
|
||||
],
|
||||
"default": "PubSubServer",
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "dataStreamWebAppServerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "DataStream WebApp Environment",
|
||||
"options": [
|
||||
"Development",
|
||||
"Production",
|
||||
"ProductionAws",
|
||||
"Staging",
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dataStreamQueryAnalyzerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "DataStreamQueryAnalyzer Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
],
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "sparkEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "Spark Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"Local",
|
||||
],
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "sparkConfigServer",
|
||||
@@ -289,5 +438,15 @@
|
||||
"type": "promptString",
|
||||
"description": "Test to run",
|
||||
},
|
||||
{
|
||||
"id": "isSparkApiEnabled",
|
||||
"type": "pickString",
|
||||
"description": "Enable Spark Api (connect to sparkd)",
|
||||
"options": [
|
||||
"True",
|
||||
"False",
|
||||
],
|
||||
"default": "True",
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+255
-49
@@ -121,6 +121,117 @@
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build DataStreamQueryAnalyzer",
|
||||
"group": "build",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "tools/build_data_stream_query_analyzer.cmd",
|
||||
},
|
||||
"args": [
|
||||
"--configuration",
|
||||
"${input:buildConfiguration}",
|
||||
],
|
||||
"icon": {
|
||||
"id": "terminal",
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build DataStreamQueryAnalyzer (Debug)",
|
||||
"group": "build",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "tools/build_data_stream_query_analyzer.cmd",
|
||||
},
|
||||
"args": [
|
||||
"--configuration",
|
||||
"Debug",
|
||||
],
|
||||
"icon": {
|
||||
"id": "terminal",
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build DataStreamQueryAnalyzer (Release)",
|
||||
"group": "build",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "tools/build_data_stream_query_analyzer.cmd",
|
||||
},
|
||||
"args": [
|
||||
"--configuration",
|
||||
"Release",
|
||||
],
|
||||
"icon": {
|
||||
"id": "terminal",
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build DataStream WebApp",
|
||||
"group": "build",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"linux": {
|
||||
"command": "tools/build_data_stream_web_app.sh",
|
||||
},
|
||||
"windows": {
|
||||
"command": "tools/build_data_stream_web_app.cmd",
|
||||
},
|
||||
"args": [
|
||||
"--configuration",
|
||||
"${input:buildConfiguration}",
|
||||
],
|
||||
"icon": {
|
||||
"id": "terminal",
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build DataStream WebApp (Debug)",
|
||||
"group": "build",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"linux": {
|
||||
"command": "tools/build_data_stream_web_app.sh",
|
||||
},
|
||||
"windows": {
|
||||
"command": "tools/build_data_stream_web_app.cmd",
|
||||
},
|
||||
"args": [
|
||||
"--configuration",
|
||||
"Debug",
|
||||
],
|
||||
"icon": {
|
||||
"id": "terminal",
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build DataStream WebApp (Release)",
|
||||
"group": "build",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"linux": {
|
||||
"command": "tools/build_data_stream_web_app.sh",
|
||||
},
|
||||
"windows": {
|
||||
"command": "tools/build_data_stream_web_app.cmd",
|
||||
},
|
||||
"args": [
|
||||
"--configuration",
|
||||
"Release",
|
||||
],
|
||||
"icon": {
|
||||
"id": "terminal",
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build Spark",
|
||||
"group": "build",
|
||||
@@ -303,6 +414,22 @@
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Publish DataStreamWebApp",
|
||||
"group": "build",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"linux": {
|
||||
"command": "tools/publish_data_stream_web_app.sh",
|
||||
},
|
||||
"windows": {
|
||||
"command": "tools/publish_data_stream_web_app.cmd",
|
||||
},
|
||||
"icon": {
|
||||
"id": "terminal",
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Edit DataStream Config",
|
||||
"type": "process",
|
||||
@@ -353,7 +480,7 @@
|
||||
},
|
||||
{
|
||||
"label": "Run DataStreamQueryAnalyzer",
|
||||
"dependsOn": "Build DataStream",
|
||||
"dependsOn": "Build DataStreamQueryAnalyzer",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
@@ -373,7 +500,7 @@
|
||||
},
|
||||
{
|
||||
"label": "Run DataStreamQueryAnalyzer (Debug)",
|
||||
"dependsOn": "Build DataStream (Debug)",
|
||||
"dependsOn": "Build DataStreamQueryAnalyzer (Debug)",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
@@ -393,7 +520,7 @@
|
||||
},
|
||||
{
|
||||
"label": "Run DataStreamQueryAnalyzer (Release)",
|
||||
"dependsOn": "Build DataStream (Release)",
|
||||
"dependsOn": "Build DataStreamQueryAnalyzer (Release)",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
@@ -422,12 +549,11 @@
|
||||
"windows": {
|
||||
"command": "DataStreamPublisher.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0"
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -445,12 +571,11 @@
|
||||
"windows": {
|
||||
"command": "DataStreamPublisher.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0"
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -468,12 +593,94 @@
|
||||
"windows": {
|
||||
"command": "DataStreamPublisher.exe",
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
"color": "terminal.ansiGreen",
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Run DataStream WebApp (Debug)",
|
||||
"dependsOn": "Build DataStream WebApp (Debug)",
|
||||
"command": "",
|
||||
"linux": {
|
||||
"command": "Bts.DataStreamWebApp.Server",
|
||||
},
|
||||
"windows": {
|
||||
"command": "Bts.DataStreamWebApp.Server.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
|
||||
"${workspaceFolder}/src/DataStreamSuite/Bts.DataStreamWebApp.Server/Configurations/DevServer.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0"
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0",
|
||||
"env": {
|
||||
"ASPNETCORE_HTTP_PORT": "8080",
|
||||
"ASPNETCORE_HTTPS_PORT": "8443",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy",
|
||||
}
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
"color": "terminal.ansiGreen",
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Run DataStream WebApp (Release)",
|
||||
"dependsOn": "Build DataStream WebApp (Release)",
|
||||
"command": "",
|
||||
"linux": {
|
||||
"command": "Bts.DataStreamWebApp.Server",
|
||||
},
|
||||
"windows": {
|
||||
"command": "Bts.DataStreamWebApp.Server.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/Bts.DataStreamWebApp.Server/Configurations/DevServer.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0",
|
||||
"env": {
|
||||
"ASPNETCORE_HTTP_PORT": "8080",
|
||||
"ASPNETCORE_HTTPS_PORT": "8443",
|
||||
"ASPNETCORE_ENVIRONMENT": "Production",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy",
|
||||
}
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
"color": "terminal.ansiGreen",
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Run DataStream WebApp (Release | Skip Build)",
|
||||
"command": "",
|
||||
"linux": {
|
||||
"command": "Bts.DataStreamWebApp.Server",
|
||||
},
|
||||
"windows": {
|
||||
"command": "Bts.DataStreamWebApp.Server.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/Bts.DataStreamWebApp.Server/Configurations/DevServer.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0",
|
||||
"env": {
|
||||
"ASPNETCORE_HTTP_PORT": "8080",
|
||||
"ASPNETCORE_HTTPS_PORT": "8443",
|
||||
"ASPNETCORE_ENVIRONMENT": "Production",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy",
|
||||
}
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -491,12 +698,11 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0"
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -514,12 +720,11 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0"
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -536,12 +741,11 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0"
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -559,12 +763,11 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0"
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -581,12 +784,11 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0"
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -885,26 +1087,30 @@
|
||||
"default": "sparkd-debug-clang",
|
||||
},
|
||||
{
|
||||
"id": "dataStreamPublisherConfig",
|
||||
"id": "dataStreamPublisherEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "Publisher Configuration",
|
||||
"options": [
|
||||
"MarketDataPublisher",
|
||||
"SimpleEchoClient",
|
||||
"SimpleTestDataPublisher",
|
||||
"TestDataPublisher",
|
||||
"Development",
|
||||
"MarketData",
|
||||
"Production",
|
||||
"ProductionAws",
|
||||
"Staging",
|
||||
],
|
||||
"default": "MarketDataPublisher",
|
||||
},
|
||||
{
|
||||
"id": "pubSubServerConfig",
|
||||
"id": "pubSubServerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "PubSub Configuration",
|
||||
"options": [
|
||||
"PubSubServer",
|
||||
"SimpleEchoClient",
|
||||
"Development",
|
||||
"EchoServer",
|
||||
"Production",
|
||||
"ProductionAws",
|
||||
"Staging",
|
||||
],
|
||||
"default": "PubSubServer",
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "sparkConfigQuery",
|
||||
|
||||
+3
-4
@@ -21,7 +21,7 @@ set(
|
||||
# SHARED_MEMORY_PREFIX serves as a kind of namespace so multiple applications
|
||||
# can run simultaneously without fighting over the same shm files (e.g., sparkd,
|
||||
# api server, etc.).
|
||||
set(SHARED_MEMORY_PREFIX "bts" CACHE STRING "Prefix to use when creating shared memory files")
|
||||
set(SHARED_MEMORY_PREFIX "\${BTS_SHARED_MEMORY_PREFIX}" CACHE STRING "Prefix to use when creating shared memory files")
|
||||
set(EXTERNALS_BIN "${EXTERNALS_ROOT}/bin")
|
||||
set(EXTERNALS_INCLUDE "${EXTERNALS_ROOT}/include")
|
||||
set(EXTERNALS_LIB "${EXTERNALS_ROOT}/lib/$<CONFIG>")
|
||||
@@ -40,9 +40,8 @@ include_directories(BEFORE SYSTEM ${EXTERNALS_INCLUDE} ${EXTERNALS_ROOT}/include
|
||||
link_directories(${EXTERNALS_LIB})
|
||||
|
||||
add_compile_definitions(SHARED_MEMORY_PREFIX="${SHARED_MEMORY_PREFIX}")
|
||||
add_compile_definitions(APP_DATA_DIR="${APP_DATA_DIR}")
|
||||
if(DEFINED APP_DATA_DIR_OVERRIDE)
|
||||
add_compile_definitions(APP_DATA_DIR_OVERRIDE="${APP_DATA_DIR_OVERRIDE}")
|
||||
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)
|
||||
|
||||
+6
-22
@@ -20,8 +20,6 @@
|
||||
"SPARK_CMAKE_CXX_FLAGS": "/MP /WX /wd4250 /wd4251 /wd4244 /wd4267 /wd4355 /wd4275 /wd4345 /bigobj /EHsc /DCURL_STATICLIB /D_WINSOCK_DEPRECATED_NO_WARNINGS /D__TBB_NO_IMPLICIT_LINKAGE /DBOOST_ALL_NO_LIB /std:c++20 /D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"APP_DATA_DIR": "${dollar}{APPDATA}/bts",
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARK_DATA_DIR}",
|
||||
"CMAKE_CXX_FLAGS": "$env{SPARK_CMAKE_CXX_FLAGS}",
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "$env{SPARK_CMAKE_CXX_FLAGS} /MTd",
|
||||
"CMAKE_CXX_FLAGS_RELEASE": "$env{SPARK_CMAKE_CXX_FLAGS} /MT",
|
||||
@@ -36,8 +34,7 @@
|
||||
"EXPORT_MD_CONSUMER": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
},
|
||||
"SHARED_MEMORY_PREFIX": "spark"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -53,8 +50,6 @@
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"platform": "",
|
||||
"APP_DATA_DIR": "${dollar}{HOME}/sparkdata",
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARKD_DATA_DIR}",
|
||||
"CMAKE_BUILD_WITH_INSTALL_RPATH": {
|
||||
"type": "BOOL",
|
||||
"value": "OFF"
|
||||
@@ -77,8 +72,7 @@
|
||||
"BUILD_ADMIN_WEB_APP": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
},
|
||||
"SHARED_MEMORY_PREFIX": "sparkd"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -159,11 +153,7 @@
|
||||
{
|
||||
"name": "spark-api-server-windows",
|
||||
"inherits": "spark",
|
||||
"displayName": "Spark Api Server (Windows)",
|
||||
"cacheVariables": {
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARK_API_SERVER_DATA_DIR}",
|
||||
"SHARED_MEMORY_PREFIX": "spark_api_server"
|
||||
}
|
||||
"displayName": "Spark Api Server (Windows)"
|
||||
},
|
||||
|
||||
{
|
||||
@@ -172,7 +162,6 @@
|
||||
"displayName": "Spark Api Server (Linux)",
|
||||
"generator": "Ninja Multi-Config",
|
||||
"cacheVariables": {
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARK_API_SERVER_DATA_DIR}",
|
||||
"BUILD_ADMIN_WEB_APP": {
|
||||
"type": "BOOL",
|
||||
"value": "OFF"
|
||||
@@ -191,7 +180,7 @@
|
||||
"value": "ON"
|
||||
},
|
||||
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net8.0",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/Spark.Api.Server/$<CONFIG>/bin/net8.0",
|
||||
"EXPORT_MD_CONSUMER": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
@@ -229,10 +218,8 @@
|
||||
"description": "Data Stream utils ported over from Edge",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"APP_DATA_DIR": "${dollar}{APPDATA}/bts/DataStream",
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{DATA_STREAM_DATA_DIR}",
|
||||
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf;spark/config/profiles/data_stream/*.conf",
|
||||
"SHARED_MEMORY_PREFIX": "data_stream"
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net8.0;${sourceDir}/build/$<CONFIG>/bin/net8.0-windows"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -248,8 +235,6 @@
|
||||
"inherits": "sparkd",
|
||||
"generator": "Ninja Multi-Config",
|
||||
"cacheVariables": {
|
||||
"APP_DATA_DIR": "${dollar}{HOME}/.local/share/DataStream",
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{DATA_STREAM_DATA_DIR}",
|
||||
"BUILD_ADMIN_WEB_APP": {
|
||||
"type": "BOOL",
|
||||
"value": "OFF"
|
||||
@@ -271,8 +256,7 @@
|
||||
"EXPORT_MD_CONSUMER": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
},
|
||||
"SHARED_MEMORY_PREFIX": "data_stream"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
+69
-51
@@ -29,36 +29,43 @@ function(Protobuf_Generate_Cpp)
|
||||
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"
|
||||
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}
|
||||
${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)
|
||||
VERBATIM
|
||||
)
|
||||
endforeach()
|
||||
|
||||
set_source_files_properties(${${_ARGS_CXX_SOURCES}} ${${_ARGS_CXX_HEADERS}} PROPERTIES GENERATED TRUE)
|
||||
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")
|
||||
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"
|
||||
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)
|
||||
set(${_ARGS_CXX_SOURCES} ${${_ARGS_CXX_SOURCES}} PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_HEADERS} ${${_ARGS_CXX_HEADERS}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(Service_Compiler_Generate_Cpp)
|
||||
@@ -92,40 +99,51 @@ function(Service_Compiler_Generate_Cpp)
|
||||
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
|
||||
${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"
|
||||
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}
|
||||
${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)
|
||||
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"
|
||||
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}
|
||||
@@ -133,32 +151,32 @@ function(Service_Compiler_Generate_Cpp)
|
||||
--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}
|
||||
DEPENDS
|
||||
${ABS_FIL}
|
||||
${TEMPLATES}
|
||||
${_plugin_py}
|
||||
COMMENT "Running C++ service compiler on ${FIL}"
|
||||
VERBATIM)
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
endforeach()
|
||||
|
||||
# remove some warnings from protobuf generated files
|
||||
if(WIN32)
|
||||
set_source_files_properties(${${_ARGS_CXX_SOURCES}} PROPERTIES COMPILE_FLAGS
|
||||
"/wd4309 /wd4838")
|
||||
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"
|
||||
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)
|
||||
|
||||
set(${_ARGS_CXX_SOURCES} ${${_ARGS_CXX_SOURCES}} PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_HEADERS} ${${_ARGS_CXX_HEADERS}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -109,6 +109,55 @@ services:
|
||||
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}"
|
||||
@@ -0,0 +1,39 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y pkg-config \
|
||||
&& apt-get install -y locales \
|
||||
&& apt-get install -y ca-certificates \
|
||||
&& apt-get install -y libssh2-1-dev \
|
||||
&& apt-get install -y software-properties-common \
|
||||
&& 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,6 +0,0 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "6.0.200",
|
||||
"rollForward": "latestMajor"
|
||||
}
|
||||
}
|
||||
+164
-143
@@ -1,143 +1,164 @@
|
||||
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
|
||||
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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {422D1620-0166-4C26-9A81-CA8A2EB1AB58}
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
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
|
||||
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
|
||||
@@ -8,7 +8,6 @@
|
||||
public int Integer;
|
||||
public double Real;
|
||||
public string Identifier;
|
||||
public DateTime DateTime;
|
||||
public ImmutableList<IArithmeticExpression> Arguments;
|
||||
public ImmutableList<Assignment> Assignments;
|
||||
public IArithmeticExpression Argument;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace BCG
|
||||
@@ -10,6 +12,7 @@ namespace BCG
|
||||
rk.SetValue (name, value.ToString ());
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static double getValue (RegistryKey rk, string name)
|
||||
{
|
||||
object v = rk.GetValue (name);
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
namespace Bts.BooleanExpressions;
|
||||
|
||||
using bts;
|
||||
|
||||
class BooleanExpression : IBooleanExpression {
|
||||
readonly Func<IDictionary<string, object?>, bool> evaluate;
|
||||
|
||||
public BooleanExpression(Func<IDictionary<string, object?>, bool> evaluate) =>
|
||||
this.evaluate = evaluate;
|
||||
|
||||
public bool Evaluate(IDictionary<string, object?> env) {
|
||||
try {
|
||||
return evaluate(env);
|
||||
} catch (Exception ex) {
|
||||
Log.assert(false, $"BooleanExpression.Evaluate failed: {ex}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
public bool Evaluate(IDictionary<string, object?> env) =>
|
||||
evaluate(env);
|
||||
}
|
||||
@@ -41,17 +41,11 @@ Identifier {Letter}({Letter}*[0-9]*_*)*
|
||||
OpenParenthesis \(
|
||||
CloseParenthesis \)
|
||||
Comma ,
|
||||
Negate '!'
|
||||
MapsTo ':'
|
||||
IsOfType '/'
|
||||
|
||||
%%
|
||||
|
||||
{StringConstant} {
|
||||
yylval.String = yytext.Substring(1, yytext.Length - 2).Replace(@"\'", "'");
|
||||
return (int)Token.STRING_CONSTANT;
|
||||
}
|
||||
|
||||
{BooleanConstant} {
|
||||
yylval.Boolean = yytext.ToLower() switch {
|
||||
"true" => true,
|
||||
@@ -62,6 +56,11 @@ IsOfType '/'
|
||||
return (int)Token.BOOLEAN_CONSTANT;
|
||||
}
|
||||
|
||||
{StringConstant} {
|
||||
yylval.String = yytext.Substring(1, yytext.Length - 2).Replace(@"\'", "'");
|
||||
return (int)Token.STRING_CONSTANT;
|
||||
}
|
||||
|
||||
{NullConstant} {
|
||||
yylval.Null = DBNull.Value;
|
||||
return (int)Token.NULL_CONSTANT;
|
||||
@@ -94,10 +93,6 @@ IsOfType '/'
|
||||
return (int)Token.COMMA;
|
||||
}
|
||||
|
||||
{Negate} {
|
||||
return (int)Token.NEGATE;
|
||||
}
|
||||
|
||||
{MapsTo} {
|
||||
return (int)Token.MAPS_TO;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
VITE_DATASTREAM_WEBSOCKET_URL=wss://localhost:8443/ws
|
||||
@@ -0,0 +1 @@
|
||||
VITE_DATASTREAM_WEBSOCKET_URL=wss://localhost:8443/ws
|
||||
@@ -0,0 +1,20 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react/jsx-runtime',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
|
||||
settings: { react: { version: '18.3.1' } },
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/0.5.128-alpha">
|
||||
<PropertyGroup>
|
||||
<StartupCommand>npm run dev</StartupCommand>
|
||||
<JavaScriptTestRoot>src\</JavaScriptTestRoot>
|
||||
<JavaScriptTestFramework>Jest</JavaScriptTestFramework>
|
||||
<!-- Allows the build (or compile) script located on package.json to run on Build -->
|
||||
<ShouldRunBuildScript>true</ShouldRunBuildScript>
|
||||
<!-- Folder where production build objects will be placed -->
|
||||
<PublishAssetsDirectory>$(MSBuildProjectDirectory)\distill</PublishAssetsDirectory>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,8 @@
|
||||
# React + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/ico" href="/logo.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>BTS Cloud Streams</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
<disabledPackageSources>
|
||||
<clear />
|
||||
</disabledPackageSources>
|
||||
</configuration>
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "bts.datastreamwebapp.client",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/material": "^18.0.4",
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@fontsource/noto-sans": "^5.0.22",
|
||||
"@material/data-table": "^15.0.0-canary.7f224ddd4.0",
|
||||
"@mui/icons-material": "^5.15.20",
|
||||
"@mui/material": "^5.15.20",
|
||||
"@mui/x-data-grid": "^7.7.1",
|
||||
"bulma": "^1.0.1",
|
||||
"classnames": "^2.5.1",
|
||||
"react": "^18.3.1",
|
||||
"react-data-grid": "^7.0.0-beta.44",
|
||||
"react-data-table-component": "^7.6.2",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-json-view-lite": "^1.4.0",
|
||||
"react-pro-sidebar": "^1.1.0",
|
||||
"react-use-websocket": "^4.8.1",
|
||||
"rpc-websockets": "^7.11.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-react": "^7.34.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.7",
|
||||
"react-mui-sidebar": "^1.3.5",
|
||||
"vite": "^5.2.13"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 107 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,40 @@
|
||||
import { Sidebar, Menu, MenuItem, Submenu, Logo } from "react-mui-sidebar";
|
||||
import './App.css';
|
||||
|
||||
const AnimatedSideBar = () => {
|
||||
return (
|
||||
<Sidebar className={"sidebar-container"} width={"270px"}>
|
||||
<Logo img="https://adminmart.com/wp-content/uploads/2024/03/logo-admin-mart-news.png">
|
||||
AdminMart
|
||||
</Logo>
|
||||
<Menu subHeading="HOME">
|
||||
<MenuItem link="/" badge="true">
|
||||
Modern
|
||||
</MenuItem>
|
||||
<MenuItem>eCommerce</MenuItem>
|
||||
<MenuItem>Analytical</MenuItem>
|
||||
</Menu>
|
||||
<Menu subHeading="APPS">
|
||||
<MenuItem>Chat</MenuItem>
|
||||
<MenuItem>Calendar</MenuItem>
|
||||
</Menu>
|
||||
<Menu subHeading="OTHERS">
|
||||
<Submenu title="Menu Level">
|
||||
<MenuItem>Post</MenuItem>
|
||||
<MenuItem>Details</MenuItem>
|
||||
<Submenu title="Level 2">
|
||||
<MenuItem>new</MenuItem>
|
||||
<MenuItem>Hello</MenuItem>
|
||||
</Submenu>
|
||||
</Submenu>
|
||||
|
||||
<MenuItem>Chip</MenuItem>
|
||||
<MenuItem target="_blank" link="google.com">
|
||||
External Link
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Sidebar>
|
||||
);
|
||||
};
|
||||
|
||||
export default AnimatedSideBar;
|
||||
@@ -0,0 +1,101 @@
|
||||
@use "@material/checkbox";
|
||||
@use "@material/icon-button";
|
||||
@use "@material/data-table/data-table";
|
||||
|
||||
.root-div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.main-content-div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.title-div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.container-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.container-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
box.query-input-form {
|
||||
/* p: 2, display: "flex", flexFlow: "column", alignItems: "stretch" */
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
/* li.ps-menuitem-root:hover {
|
||||
background-color: #ff9922;
|
||||
} */
|
||||
|
||||
.container-row-centered {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
h1#main-header {
|
||||
padding: 4px 8px 4px 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td:hover {
|
||||
background-color: cadetblue;
|
||||
}
|
||||
|
||||
td#cell-decimal {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
td#cell-integer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
td#cell-string {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td#cell-date-time {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Sidebar.css */
|
||||
/* .sidebar-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
background-color: #333;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar.closed {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.sidebar.open {
|
||||
width: 250px;
|
||||
} */
|
||||
@@ -0,0 +1,173 @@
|
||||
import { ThemeProvider, CssBaseline, GlobalStyles } from '@mui/material';
|
||||
import QueryStatusView from './QueryStatusView';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
import QueryControl from './QueryControl';
|
||||
import DataTable from './DataTable';
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import useWebSocket, { ReadyState } from 'react-use-websocket';
|
||||
import Sidebar from './SideBar';
|
||||
import getTheme from './Theme';
|
||||
|
||||
import '@fontsource/noto-sans';
|
||||
import './App.css';
|
||||
import './SideBar.css';
|
||||
|
||||
const webSocketUrl = import.meta.env.VITE_DATASTREAM_WEBSOCKET_URL;
|
||||
// Always use the same subscription id (1), because we only show 1 table at a time.
|
||||
// The server will automatically dispose the previous subscription and start a new one
|
||||
// if we're currently subscribed to another query.
|
||||
const subscriptionId = "1";
|
||||
|
||||
var rpcReqIdCounter = 1;
|
||||
|
||||
function subscribeReq(query) {
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
id: rpcReqIdCounter++,
|
||||
method: "subscribe",
|
||||
params: {
|
||||
subscription_id: subscriptionId,
|
||||
query: query
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function unsubscribeReq() {
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
id: rpcReqIdCounter++,
|
||||
method: "unsubscribe",
|
||||
params: {
|
||||
subscription_id: subscriptionId,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
|
||||
const theme = getTheme({ mode: prefersDarkMode ? 'dark' : 'light' });
|
||||
const globalStyles = {
|
||||
':root': {
|
||||
'--primary-color': theme.palette.primary.main,
|
||||
'--primary-dark-color': theme.palette.primary.dark,
|
||||
'--secondary-color': theme.palette.secondary.main,
|
||||
'--secondary-dark-color': theme.palette.secondary.dark,
|
||||
'--background-color': theme.palette.background.default,
|
||||
},
|
||||
};
|
||||
const [blueTable, setBlueTable] = useState({ columns: null, rows: null });
|
||||
const [queryError, setQueryError] = useState(null);
|
||||
const [queryState, setQueryState] = useState("Unsubscribed");
|
||||
const queryStateDetails = useMemo(() => {
|
||||
if (queryState == "Unsubscribed") {
|
||||
return "Enter query above, then click the play button to subscribe";
|
||||
}
|
||||
if (queryState == "Subscribed") {
|
||||
return null;
|
||||
}
|
||||
}, [queryState]);
|
||||
const [sidebarIsOpen, setSidebarIsOpen] = useState(false);
|
||||
const [cannedQuery, setCannedQuery] = useState(null);
|
||||
|
||||
const onCannedQueryClicked = (cannedQuery) => {
|
||||
console.info(`Executing canned query: ${JSON.stringify(cannedQuery)}`);
|
||||
const queryText = cannedQuery.query.join("\n");
|
||||
setCannedQuery({ queryText: queryText, clickTime: Date.now() });
|
||||
subscribe(queryText);
|
||||
};
|
||||
|
||||
const { sendJsonMessage, getWebSocket, readyState } = useWebSocket(
|
||||
webSocketUrl,
|
||||
{
|
||||
onOpen: (e) => console.info(`WebSocket open. ${JSON.stringify(e)}`),
|
||||
onClose: (e) => console.info(`WebSocket closed. ${JSON.stringify(e)}`),
|
||||
onError: (e) => console.error(`WebSocket error: ${JSON.stringify(e)}`),
|
||||
shouldReconnect: () => true,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
console.info(`WebSocket readyState: ${readyState}`)
|
||||
if (readyState != ReadyState.OPEN) {
|
||||
return;
|
||||
}
|
||||
const ws = getWebSocket();
|
||||
ws.onmessage = e => {
|
||||
console.info(`Received message: ${e.data}`);
|
||||
const msg = JSON.parse(e.data);
|
||||
setQueryError(msg.error);
|
||||
if (msg.error != null) {
|
||||
setQueryState("Error");
|
||||
} else if (msg.id != null) {
|
||||
setQueryState(msg.result.status);
|
||||
} else {
|
||||
console.assert(msg.params.subscription_id == subscriptionId);
|
||||
console.info(`Received rows: ${msg.params.table.all}`);
|
||||
setBlueTable({ columns: msg.params.table.columns, rows: msg.params.table.all });
|
||||
}
|
||||
};
|
||||
}, [getWebSocket, readyState]);
|
||||
|
||||
const subscribe = (query) => {
|
||||
const req = subscribeReq(query);
|
||||
console.info(`Subscribing: ${JSON.stringify(subscribeReq(query))}`);
|
||||
sendJsonMessage(req);
|
||||
};
|
||||
|
||||
const unsubscribe = () => {
|
||||
const req = unsubscribeReq();
|
||||
console.info(`Unsubscribing: ${JSON.stringify(req)}`);
|
||||
sendJsonMessage(req);
|
||||
};
|
||||
|
||||
const onOpened = () => {
|
||||
setSidebarIsOpen(true);
|
||||
};
|
||||
|
||||
const onClosed = () => {
|
||||
setSidebarIsOpen(false);
|
||||
};
|
||||
|
||||
const sidebarWidth = sidebarIsOpen ? '250px' : '65px';
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<GlobalStyles styles={globalStyles} />
|
||||
<div className='root-div'>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
flexWrap: 'nowrap',
|
||||
width: sidebarWidth,
|
||||
transition: 'width 0.3s ease',
|
||||
}}>
|
||||
<Sidebar onSelection={onCannedQueryClicked} onOpened={onOpened} onClosed={onClosed} />
|
||||
</div>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
left: sidebarWidth,
|
||||
width: '100%',
|
||||
transition: 'width 0.3s ease',
|
||||
}}>
|
||||
<div style={{ width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'flex-start', margin: theme.spacing(2, 0, 0, 0) }}>
|
||||
<div style={{ width: '90%', rightMargin: '100px' }}>
|
||||
<QueryControl
|
||||
queryState={queryState}
|
||||
queryText={cannedQuery?.queryText}
|
||||
queryTextResetTime={cannedQuery?.clickTime}
|
||||
subscribe={subscribe}
|
||||
unsubscribe={unsubscribe} />
|
||||
</div>
|
||||
<div style={{ width: '90%', rightMargin: '100px' }}>
|
||||
<QueryStatusView queryState={queryState} details={queryStateDetails} error={queryError} />
|
||||
<DataTable columns={blueTable?.columns ?? []} rows={blueTable?.rows ?? []} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,53 @@
|
||||
@use "@material/checkbox";
|
||||
@use "@material/icon-button";
|
||||
@use "@material/data-table/data-table";
|
||||
|
||||
.data-grid-container {
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
.data-grid {
|
||||
max-height: 1000px;
|
||||
}
|
||||
|
||||
div[role=columnheader] {
|
||||
border-top: 0px;
|
||||
border-bottom: 0px;
|
||||
background-color: var(--primary-dark-color);
|
||||
}
|
||||
|
||||
/* div[role=columnheader] {
|
||||
border-top: 0px;
|
||||
border-bottom: 0px;
|
||||
background-color: var(--primary-dark-color);
|
||||
}
|
||||
|
||||
.rdg-row {
|
||||
border: 0px;
|
||||
border-top: 0px;
|
||||
border-bottom: 0px;
|
||||
background-color: rgba(var(--primary-dark-color), 0.8);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.rdg-row-odd {
|
||||
border: 0px;
|
||||
border-top: 0px;
|
||||
border-bottom: 0px;
|
||||
background-color: var(--primary-dark-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.rdg-cell {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
|
||||
.rdg-cell.even {
|
||||
border-bottom: 5px;
|
||||
}
|
||||
|
||||
.rdg-cell.odd {
|
||||
border-bottom: 5px;
|
||||
} */
|
||||
@@ -0,0 +1,32 @@
|
||||
@use "@material/checkbox";
|
||||
@use "@material/icon-button";
|
||||
@use "@material/data-table/data-table";
|
||||
|
||||
th {
|
||||
font-size: large;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
td:hover {
|
||||
background-color: cadetblue;
|
||||
}
|
||||
|
||||
td#cell-decimal {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
td#cell-integer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
td#cell-string {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td#cell-date-time {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { DataGrid } from '@mui/x-data-grid';
|
||||
import './DataGrid.css';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
export default function DataTable({ columns, rows }) {
|
||||
const theme = useTheme();
|
||||
const [columnWidths, setColumnWidths] = useState({});
|
||||
|
||||
const handleColumnResize = (params) => {
|
||||
const newWidth = params.width;
|
||||
setColumnWidths((prevWidths) => ({
|
||||
...prevWidths,
|
||||
[params.colDef.field]: params.width,
|
||||
}));
|
||||
};
|
||||
|
||||
const getGridColDef = useMemo(() => {
|
||||
return col => {
|
||||
return {
|
||||
field: col.name,
|
||||
headerName: col.name,
|
||||
width: columnWidths[col.name],
|
||||
};
|
||||
};
|
||||
}, [columnWidths]);
|
||||
|
||||
return (
|
||||
<DataGrid
|
||||
className='data-grid-container'
|
||||
autosizeOnMount={false}
|
||||
columns={columns?.map(getGridColDef) ?? []}
|
||||
onColumnResize={handleColumnResize}
|
||||
rows={rows ?? []}
|
||||
sx={{
|
||||
margin: theme.spacing(2, 0, 0, 0),
|
||||
borderColor: 'primary.main',
|
||||
backgroundColor: 'primary.dark',
|
||||
color: 'text.primary',
|
||||
'& .MuiDataGrid-columnHeader': {
|
||||
color: 'primary.main',
|
||||
fontWeight: 700,
|
||||
backgroundColor: 'primary.dark'
|
||||
},
|
||||
'& .MuiDataGrid-filler': {
|
||||
color: 'primary.main',
|
||||
fontWeight: 700,
|
||||
backgroundColor: 'primary.dark'
|
||||
},
|
||||
'& .MuiDataGrid-cell': {
|
||||
color: 'text.primary',
|
||||
},
|
||||
'& .MuiDataGrid-cell:hover': {
|
||||
color: 'primary.main',
|
||||
},
|
||||
'& .MuiDataGrid-row': {
|
||||
'--DataGrid-rowBorderColor': 'secondary.dark'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
DataTable.propTypes = {
|
||||
columns: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
rows: PropTypes.arrayOf(PropTypes.array).isRequired,
|
||||
apiRef: PropTypes.object,
|
||||
};
|
||||
@@ -0,0 +1,119 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import DataTable from './DataTable';
|
||||
import { useRef, useState, useEffect } from 'react';
|
||||
import { useGridApiRef } from '@mui/x-data-grid';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
||||
import StopIcon from '@mui/icons-material/Stop';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
|
||||
const QueryControl = (props) => {
|
||||
const { queryState, queryText, queryTextResetTime, subscribe, unsubscribe } = props;
|
||||
// const theme = useTheme();
|
||||
let textInput = useRef();
|
||||
const [queryTextChangeTime, setQueryTextChangeTime] = useState(null);
|
||||
useEffect(() => {
|
||||
if (queryText == null || textInput.current == null) {
|
||||
return;
|
||||
}
|
||||
// Init text field (unless a non-empty string is already present, or the user has modified
|
||||
// the query - we don't want to overwrite their changes).
|
||||
if (queryTextChangeTime == null || queryTextResetTime > queryTextChangeTime) {
|
||||
console.info(`Initializing query text: ${queryText}`)
|
||||
textInput.current.value = queryText;
|
||||
}
|
||||
}, [queryText, queryTextChangeTime, queryTextResetTime]);
|
||||
const onClearClick = () => {
|
||||
textInput.current.value = '';
|
||||
};
|
||||
|
||||
const onRunClick = () => {
|
||||
subscribe(textInput.current.value);
|
||||
};
|
||||
|
||||
const onStopClick = () => {
|
||||
unsubscribe();
|
||||
};
|
||||
|
||||
const onKeyDown = (e) => {
|
||||
// Detect keyboard shortcuts.
|
||||
// Ctrl+Enter : Run
|
||||
if (e.ctrlKey && e.key === 'Enter') {
|
||||
onRunClick();
|
||||
}
|
||||
};
|
||||
|
||||
const onChange = (e) => {
|
||||
// So we know not to overwrite the changes with the canned query on re-render
|
||||
setQueryTextChangeTime(Date.now());
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "flex", flexFlow: "column" }}>
|
||||
<Paper elevation={3} sx={{ color: 'primary.main' }}>
|
||||
<Box sx={{ p: 2 }}>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
rows={10}
|
||||
variant="outlined"
|
||||
onChange={onChange}
|
||||
onKeyDown={onKeyDown}
|
||||
inputRef={textInput}
|
||||
placeholder="Enter Query..."
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ p: 2, borderTop: 1 }}>
|
||||
<Grid container spacing={2} justifyContent="flex-start">
|
||||
<Grid item xs>
|
||||
<Tooltip title="Clear Query Text">
|
||||
<Button onClick={onClearClick} sx={{ padding: '11px', color: 'text.dark' }}>
|
||||
Clear
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Tooltip title="Run (Ctrl+Enter)">
|
||||
<Button onClick={onRunClick} sx={{
|
||||
color: `queryStartButton.${queryState}.color`,
|
||||
bgcolor: `queryStartButton.${queryState}.backgroundColor`,
|
||||
padding: '11px'
|
||||
}}>
|
||||
<PlayArrowIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Tooltip title="Stop">
|
||||
<Button onClick={onStopClick} sx={{
|
||||
color: `queryStopButton.${queryState}.color`,
|
||||
bgcolor: `queryStopButton.${queryState}.backgroundColor`,
|
||||
padding: '11px'
|
||||
}}>
|
||||
<StopIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
QueryControl.propTypes = {
|
||||
columns: PropTypes.array,
|
||||
rows: PropTypes.array,
|
||||
isRunning: PropTypes.bool,
|
||||
queryText: PropTypes.string,
|
||||
queryTextResetTime: PropTypes.number,
|
||||
queryState: PropTypes.string,
|
||||
subscribe: PropTypes.func,
|
||||
unsubscribe: PropTypes.func,
|
||||
};
|
||||
|
||||
export default QueryControl;
|
||||
@@ -0,0 +1,73 @@
|
||||
import { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Box, Typography, Collapse } from '@mui/material';
|
||||
import Alert from '@mui/material/Alert';
|
||||
import AlertTitle from '@mui/material/AlertTitle';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { alpha } from '@mui/system';
|
||||
|
||||
const QueryStatusView = ({ queryState, details, error }) => {
|
||||
const theme = useTheme();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
let header = queryState;
|
||||
let headerContent = null;
|
||||
let detailElements = [];
|
||||
let severity = queryState == "Subscribed" ? "success" : "info";
|
||||
let cursor = details == null ? "default" : "pointer";
|
||||
if (error != null) {
|
||||
severity = "error";
|
||||
cursor = "pointer";
|
||||
header = `Error Code: ${error.code}`;
|
||||
headerContent = error.message;
|
||||
detailElements.push(<Typography variant="body1">{error.data.error_message}</Typography>);
|
||||
detailElements.push(<Typography variant="subtitle1">Stack Trace:</Typography>);
|
||||
(error.data.stack_trace ?? []).forEach(line => detailElements.push(
|
||||
<Typography variant="body2" component="pre" sx={{ whiteSpace: 'pre-wrap' }}>
|
||||
{line}
|
||||
</Typography>));
|
||||
} else if (details != null) {
|
||||
detailElements.push(<Typography variant="body1">{details}</Typography>);
|
||||
}
|
||||
return (
|
||||
<Box sx={{ margin: theme.spacing(2, 0, 0, 0) }}>
|
||||
<Alert
|
||||
severity={severity}
|
||||
onClick={() => setOpen(!open)}
|
||||
sx={{
|
||||
margin: theme.spacing(2, 0, 0, 0),
|
||||
cursor: cursor,
|
||||
}}>
|
||||
<AlertTitle>{header}</AlertTitle>
|
||||
{headerContent}
|
||||
</Alert>
|
||||
{detailElements.length == 0
|
||||
? null
|
||||
: <Collapse in={open}>
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: alpha(theme.palette[severity].light, 0.75),
|
||||
color: theme.palette[severity].contrastText,
|
||||
padding: theme.spacing(2),
|
||||
marginTop: theme.spacing(0),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
}}
|
||||
>
|
||||
{detailElements}
|
||||
</Box>
|
||||
</Collapse>}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
QueryStatusView.propTypes = {
|
||||
queryState: PropTypes.string,
|
||||
details: PropTypes.string,
|
||||
error: PropTypes.shape({
|
||||
code: PropTypes.number,
|
||||
message: PropTypes.string,
|
||||
data: PropTypes.object,
|
||||
})
|
||||
};
|
||||
|
||||
export default QueryStatusView;
|
||||
@@ -0,0 +1,27 @@
|
||||
import 'react-data-grid/lib/styles.css';
|
||||
import PropTypes from 'prop-types';
|
||||
import DataGrid from 'react-data-grid';
|
||||
import './DataGrid.css';
|
||||
|
||||
function getGridColDef(col) {
|
||||
return {
|
||||
key: col.name,
|
||||
name: col.name,
|
||||
};
|
||||
}
|
||||
|
||||
export default function ReactDataGrid({columns, rows}) {
|
||||
return (
|
||||
<DataGrid className={"data-grid"} rows={rows} columns={columns.map(getGridColDef)} />
|
||||
);
|
||||
}
|
||||
|
||||
ReactDataGrid.propTypes = {
|
||||
columns: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
rows: PropTypes.arrayOf(PropTypes.array).isRequired,
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
/* Sidebar.css */
|
||||
.app-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar.open {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar.closed {
|
||||
width: 0%;
|
||||
}
|
||||
|
||||
.sidebar-toggle-button {
|
||||
border: 0px;
|
||||
border-radius: 50%;
|
||||
box-shadow: rgba(9, 30, 66, 0.08) 0px 0px 0px 1px, rgba(9, 30, 66, 0.08) 0px 2px 4px 1px;
|
||||
color: var(--primary-color);
|
||||
cursor: pointer;
|
||||
height: 24px;
|
||||
opacity: 1;
|
||||
outline: 0px;
|
||||
padding: 0px;
|
||||
background-color: transparent;
|
||||
transition: background-color 100ms linear 0s, color 100ms linear 0s, opacity 300ms cubic-bezier(0.2, 0, 0, 1) 0s, transform 300ms cubic-bezier(0.2, 0, 0, 1) 0s;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.sidebar-toggle-button:hover {
|
||||
transition: background-color 100ms linear 0s, color 100ms linear 0s, opacity 300ms cubic-bezier(0.2, 0, 0, 1) 0s, transform 300ms cubic-bezier(0.2, 0, 0, 1) 0s;
|
||||
}
|
||||
|
||||
.main-content.open {
|
||||
width: 165px;
|
||||
transition: width 0.3s ease;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.main-content.closed {
|
||||
width: 0%;
|
||||
/* min-width: 25px; */
|
||||
transition: width 0.3s ease;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.sidebar-menu-item {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sidebar-menu-item.open {
|
||||
width: 100%;
|
||||
/* justify-content: flex-start; */
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar-menu-item.closed {
|
||||
width: 0%;
|
||||
min-width: 0px;
|
||||
/* justify-content: flex-start; */
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar-menu-item-content.open {
|
||||
width: 100%;
|
||||
/* justify-content: flex-start; */
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar-menu-item-content.closed {
|
||||
width: 0px;
|
||||
/* justify-content: flex-start; */
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
/* Ensure span can shrink */
|
||||
.button-text {
|
||||
display: block; /* Make span a block element */
|
||||
width: 100%; /* Ensure it takes the full width of its parent */
|
||||
overflow: hidden; /* Hide any overflow content */
|
||||
white-space: nowrap; /* Prevent text wrapping */
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
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 ChevronRightRounded from '@mui/icons-material/ChevronRightRounded';
|
||||
import FileCopyIcon from '@mui/icons-material/FileCopy';
|
||||
import './SideBar.css';
|
||||
|
||||
const Sidebar = ({ onSelection, onOpened, onClosed }) => {
|
||||
const theme = useTheme();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [cannedQueries, setCannedQueries] = useState([]);
|
||||
const Icon = isOpen ? ChevronLeftRounded : ChevronRightRounded;
|
||||
|
||||
const toggleIsOpen = () => {
|
||||
if (isOpen) {
|
||||
setIsOpen(false);
|
||||
if (onClosed != null) {
|
||||
onClosed();
|
||||
}
|
||||
} else {
|
||||
setIsOpen(true);
|
||||
if (onOpened != null) {
|
||||
onOpened();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onMenuItemClick = (event, cannedQuery) => {
|
||||
console.info(`menu item clicked: ${cannedQuery.name}`);
|
||||
onSelection(cannedQuery);
|
||||
};
|
||||
|
||||
// const onMenuItemClick = async (event, cannedQuery) => {
|
||||
// try {
|
||||
// await navigator.clipboard.writeText(cannedQuery.query.join("\n"));
|
||||
// alert(`Copied ${cannedQuery.name} to clipboard`);
|
||||
// } catch (err) {
|
||||
// console.error('Failed to copy query text: ', err);
|
||||
// }
|
||||
// };
|
||||
|
||||
useEffect(() => {
|
||||
const fetchCannedQueries = async () => {
|
||||
try {
|
||||
const response = await fetch('api/cannedqueries');
|
||||
const data = await response.json();
|
||||
setCannedQueries(data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching WebSocket config:', error);
|
||||
}
|
||||
};
|
||||
fetchCannedQueries();
|
||||
}, []);
|
||||
|
||||
const mainContentClass = `main-content ${isOpen ? 'open' : 'closed'}`;
|
||||
const menuItemClass = `sidebar-menu-item ${isOpen ? 'open' : 'closed'}`;
|
||||
const menuItemContentClass = `sidebar-menu-item-content ${isOpen ? 'open' : 'closed'}`;
|
||||
const toggleButtonTitle = `${isOpen ? 'Hide' : 'Show'} Common Queries`;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={"sidebar"}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flexStart',
|
||||
alignItems: 'flexStart',
|
||||
margin: theme.spacing(2, 0, 0, 0)
|
||||
}}
|
||||
>
|
||||
<div className={mainContentClass}>
|
||||
{cannedQueries.map(cq =>
|
||||
<Button key={cq.name} className={menuItemClass} onClick={(event) => onMenuItemClick(event, cq)}>
|
||||
<div className={menuItemContentClass}>
|
||||
<span className='button-text'>{cq.name}</span>
|
||||
</div>
|
||||
</Button>)
|
||||
}
|
||||
{/* {cannedQueries.map(cq =>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<FileCopyIcon />}
|
||||
onClick={onMenuItemClick}
|
||||
>
|
||||
<div className={menuItemContentClass}>
|
||||
<span className='button-text'>{cq.name}</span>
|
||||
</div>
|
||||
</Button>)} */}
|
||||
</div>
|
||||
<Tooltip title={toggleButtonTitle}>
|
||||
<Button onClick={toggleIsOpen}>
|
||||
<Icon className="w-5 h-5" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
|
||||
Sidebar.propTypes = {
|
||||
onSelection: PropTypes.func,
|
||||
onOpened: PropTypes.func,
|
||||
onClosed: PropTypes.func,
|
||||
};
|
||||
@@ -0,0 +1,112 @@
|
||||
import { createTheme } from '@mui/material/styles';
|
||||
import PropTypes from 'prop-types';
|
||||
import '@fontsource/noto-sans';
|
||||
import './App.css';
|
||||
|
||||
const getLightPalette = () => {
|
||||
return {
|
||||
mode: 'light',
|
||||
primary: {
|
||||
light: '#6573c3',
|
||||
main: '#3f51b5',
|
||||
dark: '#2c387e',
|
||||
contrastText: '#ffffff',
|
||||
},
|
||||
secondary: {
|
||||
light: '#f73378',
|
||||
main: '#f50057',
|
||||
dark: '#ab003c',
|
||||
contrastText: '#ffffff',
|
||||
},
|
||||
text: {
|
||||
primary: '#000000c4',
|
||||
secondary: '#00000086',
|
||||
disabled: '#0000005b',
|
||||
hint: '#0000005b',
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const getDarkPalette = () => {
|
||||
return {
|
||||
mode: 'dark',
|
||||
primary: {
|
||||
light: '#bcc5ff',
|
||||
main: '#33baf9',
|
||||
dark: '#202334',
|
||||
contrastText: '#78a2ac',
|
||||
},
|
||||
secondary: {
|
||||
light: '#9fd0b8',
|
||||
main: '#5eb289',
|
||||
dark: '#ffffff12',
|
||||
contrastText: '#c8d4f7',
|
||||
},
|
||||
action: {
|
||||
hoverOpacity: 0.08
|
||||
},
|
||||
text: {
|
||||
primary: '#eaf8f8',
|
||||
dark: '#eaf8f8a0'
|
||||
},
|
||||
queryStartButton: {
|
||||
Subscribed: {
|
||||
color: '#33baf9',
|
||||
backgroundColor: '#ffffff40',
|
||||
},
|
||||
Unsubscribed: {
|
||||
color: '#ffffff40',
|
||||
backgroundColor: '#ffffff00',
|
||||
}
|
||||
},
|
||||
queryStopButton: {
|
||||
Subscribed: {
|
||||
color: '#ff4444a0',
|
||||
backgroundColor: '#ffffff40',
|
||||
},
|
||||
Unsubscribed: {
|
||||
color: '#ff444450',
|
||||
backgroundColor: '#ffffff00',
|
||||
}
|
||||
},
|
||||
error: {
|
||||
light: '#e57373',
|
||||
main: '#f44336',
|
||||
dark: '#d32f2f',
|
||||
contrastText: '#fff',
|
||||
},
|
||||
warning: {
|
||||
light: '#ffb74d',
|
||||
main: '#ff9800',
|
||||
dark: '#f57c00',
|
||||
contrastText: '#000',
|
||||
},
|
||||
info: {
|
||||
light: '#64b5f6',
|
||||
main: '#2196f3',
|
||||
dark: '#303030',
|
||||
contrastText: '#fff',
|
||||
},
|
||||
success: {
|
||||
light: '#81c784',
|
||||
main: '#4caf50',
|
||||
dark: '#388e3c',
|
||||
contrastText: '#000',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const getTheme = ({ mode }) => {
|
||||
return createTheme({
|
||||
typography: {
|
||||
fontFamily: '"Helvetica"'
|
||||
},
|
||||
palette: mode == 'dark' ? getDarkPalette() : getLightPalette()
|
||||
});
|
||||
};
|
||||
|
||||
export default getTheme;
|
||||
|
||||
getTheme.propTypes = {
|
||||
mode: PropTypes.string.isRequired,
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,51 @@
|
||||
.dark-high-contrast {
|
||||
--md-sys-color-primary: rgb(251 250 255);
|
||||
--md-sys-color-surface-tint: rgb(165 200 255);
|
||||
--md-sys-color-on-primary: rgb(0 0 0);
|
||||
--md-sys-color-primary-container: rgb(173 204 255);
|
||||
--md-sys-color-on-primary-container: rgb(0 0 0);
|
||||
--md-sys-color-secondary: rgb(250 250 255);
|
||||
--md-sys-color-on-secondary: rgb(0 0 0);
|
||||
--md-sys-color-secondary-container: rgb(159 208 255);
|
||||
--md-sys-color-on-secondary-container: rgb(0 0 0);
|
||||
--md-sys-color-tertiary: rgb(255 249 251);
|
||||
--md-sys-color-on-tertiary: rgb(0 0 0);
|
||||
--md-sys-color-tertiary-container: rgb(222 193 231);
|
||||
--md-sys-color-on-tertiary-container: rgb(0 0 0);
|
||||
--md-sys-color-error: rgb(255 249 249);
|
||||
--md-sys-color-on-error: rgb(0 0 0);
|
||||
--md-sys-color-error-container: rgb(255 186 177);
|
||||
--md-sys-color-on-error-container: rgb(0 0 0);
|
||||
--md-sys-color-background: rgb(17 19 24);
|
||||
--md-sys-color-on-background: rgb(225 226 233);
|
||||
--md-sys-color-surface: rgb(17 19 24);
|
||||
--md-sys-color-on-surface: rgb(255 255 255);
|
||||
--md-sys-color-surface-variant: rgb(67 71 78);
|
||||
--md-sys-color-on-surface-variant: rgb(251 250 255);
|
||||
--md-sys-color-outline: rgb(200 202 212);
|
||||
--md-sys-color-outline-variant: rgb(200 202 212);
|
||||
--md-sys-color-shadow: rgb(0 0 0);
|
||||
--md-sys-color-scrim: rgb(0 0 0);
|
||||
--md-sys-color-inverse-surface: rgb(225 226 233);
|
||||
--md-sys-color-inverse-on-surface: rgb(0 0 0);
|
||||
--md-sys-color-inverse-primary: rgb(0 42 83);
|
||||
--md-sys-color-primary-fixed: rgb(219 231 255);
|
||||
--md-sys-color-on-primary-fixed: rgb(0 0 0);
|
||||
--md-sys-color-primary-fixed-dim: rgb(173 204 255);
|
||||
--md-sys-color-on-primary-fixed-variant: rgb(0 22 49);
|
||||
--md-sys-color-secondary-fixed: rgb(214 233 255);
|
||||
--md-sys-color-on-secondary-fixed: rgb(0 0 0);
|
||||
--md-sys-color-secondary-fixed-dim: rgb(159 208 255);
|
||||
--md-sys-color-on-secondary-fixed-variant: rgb(0 24 42);
|
||||
--md-sys-color-tertiary-fixed: rgb(249 222 255);
|
||||
--md-sys-color-on-tertiary-fixed: rgb(0 0 0);
|
||||
--md-sys-color-tertiary-fixed-dim: rgb(222 193 231);
|
||||
--md-sys-color-on-tertiary-fixed-variant: rgb(33 14 42);
|
||||
--md-sys-color-surface-dim: rgb(17 19 24);
|
||||
--md-sys-color-surface-bright: rgb(55 57 62);
|
||||
--md-sys-color-surface-container-lowest: rgb(12 14 19);
|
||||
--md-sys-color-surface-container-low: rgb(25 28 32);
|
||||
--md-sys-color-surface-container: rgb(29 32 36);
|
||||
--md-sys-color-surface-container-high: rgb(40 42 47);
|
||||
--md-sys-color-surface-container-highest: rgb(50 53 58);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
.dark-medium-contrast {
|
||||
--md-sys-color-primary: rgb(173 204 255);
|
||||
--md-sys-color-surface-tint: rgb(165 200 255);
|
||||
--md-sys-color-on-primary: rgb(0 22 49);
|
||||
--md-sys-color-primary-container: rgb(112 146 198);
|
||||
--md-sys-color-on-primary-container: rgb(0 0 0);
|
||||
--md-sys-color-secondary: rgb(159 208 255);
|
||||
--md-sys-color-on-secondary: rgb(0 24 42);
|
||||
--md-sys-color-secondary-container: rgb(100 149 193);
|
||||
--md-sys-color-on-secondary-container: rgb(0 0 0);
|
||||
--md-sys-color-tertiary: rgb(222 193 231);
|
||||
--md-sys-color-on-tertiary: rgb(33 14 42);
|
||||
--md-sys-color-tertiary-container: rgb(162 136 171);
|
||||
--md-sys-color-on-tertiary-container: rgb(0 0 0);
|
||||
--md-sys-color-error: rgb(255 186 177);
|
||||
--md-sys-color-on-error: rgb(55 0 1);
|
||||
--md-sys-color-error-container: rgb(255 84 73);
|
||||
--md-sys-color-on-error-container: rgb(0 0 0);
|
||||
--md-sys-color-background: rgb(17 19 24);
|
||||
--md-sys-color-on-background: rgb(225 226 233);
|
||||
--md-sys-color-surface: rgb(17 19 24);
|
||||
--md-sys-color-on-surface: rgb(251 250 255);
|
||||
--md-sys-color-surface-variant: rgb(67 71 78);
|
||||
--md-sys-color-on-surface-variant: rgb(200 202 212);
|
||||
--md-sys-color-outline: rgb(160 163 171);
|
||||
--md-sys-color-outline-variant: rgb(128 131 139);
|
||||
--md-sys-color-shadow: rgb(0 0 0);
|
||||
--md-sys-color-scrim: rgb(0 0 0);
|
||||
--md-sys-color-inverse-surface: rgb(225 226 233);
|
||||
--md-sys-color-inverse-on-surface: rgb(40 42 47);
|
||||
--md-sys-color-inverse-primary: rgb(35 73 120);
|
||||
--md-sys-color-primary-fixed: rgb(212 227 255);
|
||||
--md-sys-color-on-primary-fixed: rgb(0 17 40);
|
||||
--md-sys-color-primary-fixed-dim: rgb(165 200 255);
|
||||
--md-sys-color-on-primary-fixed-variant: rgb(10 55 100);
|
||||
--md-sys-color-secondary-fixed: rgb(206 229 255);
|
||||
--md-sys-color-on-secondary-fixed: rgb(0 18 34);
|
||||
--md-sys-color-secondary-fixed-dim: rgb(154 203 250);
|
||||
--md-sys-color-on-secondary-fixed-variant: rgb(0 57 91);
|
||||
--md-sys-color-tertiary-fixed: rgb(247 216 255);
|
||||
--md-sys-color-on-tertiary-fixed: rgb(28 9 37);
|
||||
--md-sys-color-tertiary-fixed-dim: rgb(218 189 226);
|
||||
--md-sys-color-on-tertiary-fixed-variant: rgb(67 46 76);
|
||||
--md-sys-color-surface-dim: rgb(17 19 24);
|
||||
--md-sys-color-surface-bright: rgb(55 57 62);
|
||||
--md-sys-color-surface-container-lowest: rgb(12 14 19);
|
||||
--md-sys-color-surface-container-low: rgb(25 28 32);
|
||||
--md-sys-color-surface-container: rgb(29 32 36);
|
||||
--md-sys-color-surface-container-high: rgb(40 42 47);
|
||||
--md-sys-color-surface-container-highest: rgb(50 53 58);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
.dark {
|
||||
--md-sys-color-primary: rgb(165 200 255);
|
||||
--md-sys-color-surface-tint: rgb(165 200 255);
|
||||
--md-sys-color-on-primary: rgb(0 49 94);
|
||||
--md-sys-color-primary-container: rgb(34 72 118);
|
||||
--md-sys-color-on-primary-container: rgb(212 227 255);
|
||||
--md-sys-color-secondary: rgb(154 203 250);
|
||||
--md-sys-color-on-secondary: rgb(0 51 83);
|
||||
--md-sys-color-secondary-container: rgb(12 74 114);
|
||||
--md-sys-color-on-secondary-container: rgb(206 229 255);
|
||||
--md-sys-color-tertiary: rgb(218 189 226);
|
||||
--md-sys-color-on-tertiary: rgb(61 41 70);
|
||||
--md-sys-color-tertiary-container: rgb(85 63 93);
|
||||
--md-sys-color-on-tertiary-container: rgb(247 216 255);
|
||||
--md-sys-color-error: rgb(255 180 171);
|
||||
--md-sys-color-on-error: rgb(105 0 5);
|
||||
--md-sys-color-error-container: rgb(147 0 10);
|
||||
--md-sys-color-on-error-container: rgb(255 218 214);
|
||||
--md-sys-color-background: rgb(17 19 24);
|
||||
--md-sys-color-on-background: rgb(225 226 233);
|
||||
--md-sys-color-surface: rgb(17 19 24);
|
||||
--md-sys-color-on-surface: rgb(225 226 233);
|
||||
--md-sys-color-surface-variant: rgb(67 71 78);
|
||||
--md-sys-color-on-surface-variant: rgb(195 198 207);
|
||||
--md-sys-color-outline: rgb(141 145 153);
|
||||
--md-sys-color-outline-variant: rgb(67 71 78);
|
||||
--md-sys-color-shadow: rgb(0 0 0);
|
||||
--md-sys-color-scrim: rgb(0 0 0);
|
||||
--md-sys-color-inverse-surface: rgb(225 226 233);
|
||||
--md-sys-color-inverse-on-surface: rgb(46 48 53);
|
||||
--md-sys-color-inverse-primary: rgb(60 96 144);
|
||||
--md-sys-color-primary-fixed: rgb(212 227 255);
|
||||
--md-sys-color-on-primary-fixed: rgb(0 28 58);
|
||||
--md-sys-color-primary-fixed-dim: rgb(165 200 255);
|
||||
--md-sys-color-on-primary-fixed-variant: rgb(34 72 118);
|
||||
--md-sys-color-secondary-fixed: rgb(206 229 255);
|
||||
--md-sys-color-on-secondary-fixed: rgb(0 29 50);
|
||||
--md-sys-color-secondary-fixed-dim: rgb(154 203 250);
|
||||
--md-sys-color-on-secondary-fixed-variant: rgb(12 74 114);
|
||||
--md-sys-color-tertiary-fixed: rgb(247 216 255);
|
||||
--md-sys-color-on-tertiary-fixed: rgb(39 20 48);
|
||||
--md-sys-color-tertiary-fixed-dim: rgb(218 189 226);
|
||||
--md-sys-color-on-tertiary-fixed-variant: rgb(85 63 93);
|
||||
--md-sys-color-surface-dim: rgb(17 19 24);
|
||||
--md-sys-color-surface-bright: rgb(55 57 62);
|
||||
--md-sys-color-surface-container-lowest: rgb(12 14 19);
|
||||
--md-sys-color-surface-container-low: rgb(25 28 32);
|
||||
--md-sys-color-surface-container: rgb(29 32 36);
|
||||
--md-sys-color-surface-container-high: rgb(40 42 47);
|
||||
--md-sys-color-surface-container-highest: rgb(50 53 58);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
.light-high-contrast {
|
||||
--md-sys-color-primary: rgb(0 34 70);
|
||||
--md-sys-color-surface-tint: rgb(60 96 144);
|
||||
--md-sys-color-on-primary: rgb(255 255 255);
|
||||
--md-sys-color-primary-container: rgb(29 68 114);
|
||||
--md-sys-color-on-primary-container: rgb(255 255 255);
|
||||
--md-sys-color-secondary: rgb(0 36 61);
|
||||
--md-sys-color-on-secondary: rgb(255 255 255);
|
||||
--md-sys-color-secondary-container: rgb(3 70 110);
|
||||
--md-sys-color-on-secondary-container: rgb(255 255 255);
|
||||
--md-sys-color-tertiary: rgb(46 26 55);
|
||||
--md-sys-color-on-tertiary: rgb(255 255 255);
|
||||
--md-sys-color-tertiary-container: rgb(81 59 89);
|
||||
--md-sys-color-on-tertiary-container: rgb(255 255 255);
|
||||
--md-sys-color-error: rgb(78 0 2);
|
||||
--md-sys-color-on-error: rgb(255 255 255);
|
||||
--md-sys-color-error-container: rgb(140 0 9);
|
||||
--md-sys-color-on-error-container: rgb(255 255 255);
|
||||
--md-sys-color-background: rgb(249 249 255);
|
||||
--md-sys-color-on-background: rgb(25 28 32);
|
||||
--md-sys-color-surface: rgb(249 249 255);
|
||||
--md-sys-color-on-surface: rgb(0 0 0);
|
||||
--md-sys-color-surface-variant: rgb(224 226 236);
|
||||
--md-sys-color-on-surface-variant: rgb(32 36 43);
|
||||
--md-sys-color-outline: rgb(63 67 74);
|
||||
--md-sys-color-outline-variant: rgb(63 67 74);
|
||||
--md-sys-color-shadow: rgb(0 0 0);
|
||||
--md-sys-color-scrim: rgb(0 0 0);
|
||||
--md-sys-color-inverse-surface: rgb(46 48 53);
|
||||
--md-sys-color-inverse-on-surface: rgb(255 255 255);
|
||||
--md-sys-color-inverse-primary: rgb(228 236 255);
|
||||
--md-sys-color-primary-fixed: rgb(29 68 114);
|
||||
--md-sys-color-on-primary-fixed: rgb(255 255 255);
|
||||
--md-sys-color-primary-fixed-dim: rgb(0 45 88);
|
||||
--md-sys-color-on-primary-fixed-variant: rgb(255 255 255);
|
||||
--md-sys-color-secondary-fixed: rgb(3 70 110);
|
||||
--md-sys-color-on-secondary-fixed: rgb(255 255 255);
|
||||
--md-sys-color-secondary-fixed-dim: rgb(0 47 77);
|
||||
--md-sys-color-on-secondary-fixed-variant: rgb(255 255 255);
|
||||
--md-sys-color-tertiary-fixed: rgb(81 59 89);
|
||||
--md-sys-color-on-tertiary-fixed: rgb(255 255 255);
|
||||
--md-sys-color-tertiary-fixed-dim: rgb(57 37 66);
|
||||
--md-sys-color-on-tertiary-fixed-variant: rgb(255 255 255);
|
||||
--md-sys-color-surface-dim: rgb(217 218 224);
|
||||
--md-sys-color-surface-bright: rgb(249 249 255);
|
||||
--md-sys-color-surface-container-lowest: rgb(255 255 255);
|
||||
--md-sys-color-surface-container-low: rgb(243 243 250);
|
||||
--md-sys-color-surface-container: rgb(237 237 244);
|
||||
--md-sys-color-surface-container-high: rgb(231 232 238);
|
||||
--md-sys-color-surface-container-highest: rgb(225 226 233);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
.light-medium-contrast {
|
||||
--md-sys-color-primary: rgb(29 68 114);
|
||||
--md-sys-color-surface-tint: rgb(60 96 144);
|
||||
--md-sys-color-on-primary: rgb(255 255 255);
|
||||
--md-sys-color-primary-container: rgb(83 118 167);
|
||||
--md-sys-color-on-primary-container: rgb(255 255 255);
|
||||
--md-sys-color-secondary: rgb(3 70 110);
|
||||
--md-sys-color-on-secondary: rgb(255 255 255);
|
||||
--md-sys-color-secondary-container: rgb(71 121 163);
|
||||
--md-sys-color-on-secondary-container: rgb(255 255 255);
|
||||
--md-sys-color-tertiary: rgb(81 59 89);
|
||||
--md-sys-color-on-tertiary: rgb(255 255 255);
|
||||
--md-sys-color-tertiary-container: rgb(133 108 141);
|
||||
--md-sys-color-on-tertiary-container: rgb(255 255 255);
|
||||
--md-sys-color-error: rgb(140 0 9);
|
||||
--md-sys-color-on-error: rgb(255 255 255);
|
||||
--md-sys-color-error-container: rgb(218 52 46);
|
||||
--md-sys-color-on-error-container: rgb(255 255 255);
|
||||
--md-sys-color-background: rgb(249 249 255);
|
||||
--md-sys-color-on-background: rgb(25 28 32);
|
||||
--md-sys-color-surface: rgb(249 249 255);
|
||||
--md-sys-color-on-surface: rgb(25 28 32);
|
||||
--md-sys-color-surface-variant: rgb(224 226 236);
|
||||
--md-sys-color-on-surface-variant: rgb(63 67 74);
|
||||
--md-sys-color-outline: rgb(91 95 103);
|
||||
--md-sys-color-outline-variant: rgb(119 123 131);
|
||||
--md-sys-color-shadow: rgb(0 0 0);
|
||||
--md-sys-color-scrim: rgb(0 0 0);
|
||||
--md-sys-color-inverse-surface: rgb(46 48 53);
|
||||
--md-sys-color-inverse-on-surface: rgb(240 240 247);
|
||||
--md-sys-color-inverse-primary: rgb(165 200 255);
|
||||
--md-sys-color-primary-fixed: rgb(83 118 167);
|
||||
--md-sys-color-on-primary-fixed: rgb(255 255 255);
|
||||
--md-sys-color-primary-fixed-dim: rgb(58 93 141);
|
||||
--md-sys-color-on-primary-fixed-variant: rgb(255 255 255);
|
||||
--md-sys-color-secondary-fixed: rgb(71 121 163);
|
||||
--md-sys-color-on-secondary-fixed: rgb(255 255 255);
|
||||
--md-sys-color-secondary-fixed-dim: rgb(43 96 137);
|
||||
--md-sys-color-on-secondary-fixed-variant: rgb(255 255 255);
|
||||
--md-sys-color-tertiary-fixed: rgb(133 108 141);
|
||||
--md-sys-color-on-tertiary-fixed: rgb(255 255 255);
|
||||
--md-sys-color-tertiary-fixed-dim: rgb(107 84 116);
|
||||
--md-sys-color-on-tertiary-fixed-variant: rgb(255 255 255);
|
||||
--md-sys-color-surface-dim: rgb(217 218 224);
|
||||
--md-sys-color-surface-bright: rgb(249 249 255);
|
||||
--md-sys-color-surface-container-lowest: rgb(255 255 255);
|
||||
--md-sys-color-surface-container-low: rgb(243 243 250);
|
||||
--md-sys-color-surface-container: rgb(237 237 244);
|
||||
--md-sys-color-surface-container-high: rgb(231 232 238);
|
||||
--md-sys-color-surface-container-highest: rgb(225 226 233);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
.light {
|
||||
--md-sys-color-primary: rgb(60 96 144);
|
||||
--md-sys-color-surface-tint: rgb(60 96 144);
|
||||
--md-sys-color-on-primary: rgb(255 255 255);
|
||||
--md-sys-color-primary-container: rgb(212 227 255);
|
||||
--md-sys-color-on-primary-container: rgb(0 28 58);
|
||||
--md-sys-color-secondary: rgb(46 98 140);
|
||||
--md-sys-color-on-secondary: rgb(255 255 255);
|
||||
--md-sys-color-secondary-container: rgb(206 229 255);
|
||||
--md-sys-color-on-secondary-container: rgb(0 29 50);
|
||||
--md-sys-color-tertiary: rgb(110 86 118);
|
||||
--md-sys-color-on-tertiary: rgb(255 255 255);
|
||||
--md-sys-color-tertiary-container: rgb(247 216 255);
|
||||
--md-sys-color-on-tertiary-container: rgb(39 20 48);
|
||||
--md-sys-color-error: rgb(186 26 26);
|
||||
--md-sys-color-on-error: rgb(255 255 255);
|
||||
--md-sys-color-error-container: rgb(255 218 214);
|
||||
--md-sys-color-on-error-container: rgb(65 0 2);
|
||||
--md-sys-color-background: rgb(249 249 255);
|
||||
--md-sys-color-on-background: rgb(25 28 32);
|
||||
--md-sys-color-surface: rgb(249 249 255);
|
||||
--md-sys-color-on-surface: rgb(25 28 32);
|
||||
--md-sys-color-surface-variant: rgb(224 226 236);
|
||||
--md-sys-color-on-surface-variant: rgb(67 71 78);
|
||||
--md-sys-color-outline: rgb(116 119 127);
|
||||
--md-sys-color-outline-variant: rgb(195 198 207);
|
||||
--md-sys-color-shadow: rgb(0 0 0);
|
||||
--md-sys-color-scrim: rgb(0 0 0);
|
||||
--md-sys-color-inverse-surface: rgb(46 48 53);
|
||||
--md-sys-color-inverse-on-surface: rgb(240 240 247);
|
||||
--md-sys-color-inverse-primary: rgb(165 200 255);
|
||||
--md-sys-color-primary-fixed: rgb(212 227 255);
|
||||
--md-sys-color-on-primary-fixed: rgb(0 28 58);
|
||||
--md-sys-color-primary-fixed-dim: rgb(165 200 255);
|
||||
--md-sys-color-on-primary-fixed-variant: rgb(34 72 118);
|
||||
--md-sys-color-secondary-fixed: rgb(206 229 255);
|
||||
--md-sys-color-on-secondary-fixed: rgb(0 29 50);
|
||||
--md-sys-color-secondary-fixed-dim: rgb(154 203 250);
|
||||
--md-sys-color-on-secondary-fixed-variant: rgb(12 74 114);
|
||||
--md-sys-color-tertiary-fixed: rgb(247 216 255);
|
||||
--md-sys-color-on-tertiary-fixed: rgb(39 20 48);
|
||||
--md-sys-color-tertiary-fixed-dim: rgb(218 189 226);
|
||||
--md-sys-color-on-tertiary-fixed-variant: rgb(85 63 93);
|
||||
--md-sys-color-surface-dim: rgb(217 218 224);
|
||||
--md-sys-color-surface-bright: rgb(249 249 255);
|
||||
--md-sys-color-surface-container-lowest: rgb(255 255 255);
|
||||
--md-sys-color-surface-container-low: rgb(243 243 250);
|
||||
--md-sys-color-surface-container: rgb(237 237 244);
|
||||
--md-sys-color-surface-container-high: rgb(231 232 238);
|
||||
--md-sys-color-surface-container-highest: rgb(225 226 233);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
button#query-button {
|
||||
height: 5em;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
button#play-button {
|
||||
padding: '10px 20px';
|
||||
font-size: '16px';
|
||||
cursor: 'pointer';
|
||||
background-color: '#28a745';
|
||||
color: '#fff';
|
||||
border: 'none';
|
||||
border-radius: '5px';
|
||||
};
|
||||
|
||||
button#pause-button {
|
||||
background-color: #ffc107;
|
||||
}
|
||||
|
||||
button#stop-button {
|
||||
background-color: #dc3545;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
p#footer {
|
||||
float: none;
|
||||
clear: both;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
table#query-output {
|
||||
float: none;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
textarea#query-input {
|
||||
height: 5em;
|
||||
width: 50em;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<App />
|
||||
)
|
||||
@@ -0,0 +1,80 @@
|
||||
import { fileURLToPath, URL } from 'node:url';
|
||||
import { defineConfig } from 'vite';
|
||||
import plugin from '@vitejs/plugin-react';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import child_process from 'child_process';
|
||||
import process, { env } from 'process';
|
||||
|
||||
const baseFolder =
|
||||
process.env.APPDATA !== undefined && process.env.APPDATA !== ''
|
||||
? `${process.env.APPDATA}/ASP.NET/https`
|
||||
: `${process.env.HOME}/.aspnet/https`;
|
||||
|
||||
const certificateName = "bts.datastreamwebapp.client";
|
||||
const certFilePath = path.join(baseFolder, `${certificateName}.pem`);
|
||||
const keyFilePath = path.join(baseFolder, `${certificateName}.key`);
|
||||
|
||||
if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) {
|
||||
if (0 !== child_process.spawnSync('dotnet', [
|
||||
'dev-certs',
|
||||
'https',
|
||||
'--export-path',
|
||||
certFilePath,
|
||||
'--format',
|
||||
'Pem',
|
||||
'--no-password',
|
||||
], { stdio: 'inherit', }).status) {
|
||||
throw new Error("Could not create certificate.");
|
||||
}
|
||||
}
|
||||
|
||||
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 }) => {
|
||||
return {
|
||||
plugins: [plugin()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
},
|
||||
build: {
|
||||
minify: false,
|
||||
sourcemap: true,
|
||||
outDir: `../../../build/Bts.DataStreamWebApp.Client/${mode}/dist`
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'^/api': {
|
||||
target,
|
||||
secure: false,
|
||||
configure: (proxy) => {
|
||||
proxy.on('error', (err) => {
|
||||
console.log('proxy error', err);
|
||||
});
|
||||
proxy.on('proxyReq', (proxyReq, req) => {
|
||||
console.log(`Forwarding ${proxyReq.method} ${proxyReq.protocol}//${proxyReq.host}${proxyReq.path} to ${req.socket.remoteAddress}${req.url}`);
|
||||
});
|
||||
proxy.on('proxyRes', (proxyRes, req, res) => {
|
||||
console.log(`Forwarding response ${req.socket.localAddress} to ${res.socket.remoteAddress}. Status=${proxyRes.statusCode}`);
|
||||
});
|
||||
},
|
||||
},
|
||||
'^/ws': {
|
||||
target,
|
||||
secure: false
|
||||
}
|
||||
},
|
||||
port: 5173,
|
||||
https: {
|
||||
key: fs.readFileSync(keyFilePath),
|
||||
cert: fs.readFileSync(certFilePath),
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<SpaRoot>..\Bts.DataStreamWebApp.Client</SpaRoot>
|
||||
<SpaProxyLaunchCommand>npm run dev</SpaProxyLaunchCommand>
|
||||
<SpaProxyServerUrl>https://localhost:5173</SpaProxyServerUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<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="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Bts.DataStreamWebApp.Client\Bts.DataStreamWebApp.Client.esproj">
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\DataStream\DataStream.csproj" />
|
||||
<ProjectReference Include="..\SharedStreams\SharedStreams.csproj" />
|
||||
<ProjectReference Include="..\..\client\spark_api\spark_api.csproj" />
|
||||
<ProjectReference Include="..\..\client\spark_core\spark_core.csproj" />
|
||||
<ProjectReference Include="..\..\client\spark_websocket\spark_websocket.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ConfigurationProfile Include="appsettings.Development.json" />
|
||||
<ConfigurationProfile Include="appsettings.Production.json" />
|
||||
<ConfigurationProfile Include="appsettings.ProductionAws.json" />
|
||||
<ConfigurationProfile Include="appsettings.Staging.json" />
|
||||
<ConfigurationProfile Include="appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Bts.DataStreamWebApp.Server;
|
||||
|
||||
public class CannedQueriesConfig {
|
||||
public List<CannedQuery>? Items { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Bts.DataStreamWebApp.Server;
|
||||
|
||||
public class CannedQuery {
|
||||
public string? Name { get; set; }
|
||||
public List<string>? Query { get; set; }
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
namespace Bts.DataStreamWebApp.Server;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class CannedQueriesController : ControllerBase {
|
||||
readonly IConfiguration config;
|
||||
|
||||
public CannedQueriesController(IConfiguration config) =>
|
||||
this.config = config;
|
||||
|
||||
[HttpGet(Name = "GetCannedQueries")]
|
||||
public IEnumerable<CannedQuery>? Get() {
|
||||
var cannedQueries = config.GetSection("CannedQueries").Get<List<CannedQuery>>()?.ToArray() ?? Array.Empty<CannedQuery>();
|
||||
return cannedQueries;
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// using Bts.DataStreamWebApp.Server;
|
||||
|
||||
// using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
// [ApiController]
|
||||
// [Route("api/[controller]")]
|
||||
// public class ConfigController : ControllerBase {
|
||||
// private readonly IConfiguration _configuration;
|
||||
|
||||
// public ConfigController(IConfiguration configuration) {
|
||||
// _configuration = configuration;
|
||||
// }
|
||||
|
||||
// [HttpGet("websocket")]
|
||||
// public ActionResult<DataStreamWebSocketConfig> GetWebSocketConfig() {
|
||||
// var endpoint = $"{_configuration["Kestrel:Endpoints:Http:Url"]}/ws";
|
||||
// var webSocketConfig = new DataStreamWebSocketConfig {
|
||||
// Endpoint = endpoint // or Https based on your setup
|
||||
// };
|
||||
// return Ok(webSocketConfig);
|
||||
// }
|
||||
// }
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
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);
|
||||
var streamFactoryList = streamFactories.ToList();
|
||||
streamFactory = streamFactoryList.Count == 1
|
||||
? streamFactoryList[0]
|
||||
: new CompositeDataStreamFactory(streamFactoryList);
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
namespace Bts.DataStreamWebApp.Server.Controllers;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.websocket_core.json_rpc;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.DataStreamWebApp.Server.Messages;
|
||||
|
||||
using System;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
class DataStreamSubscription : IDisposable, IHostedService {
|
||||
public readonly ViewStream ViewStream;
|
||||
public DataPacket? LastFired;
|
||||
|
||||
readonly ILogger logger;
|
||||
readonly WebSocket webSocket;
|
||||
|
||||
public DataStreamSubscription(string id, JsonRpcId requestId, ViewStream viewStream, WebSocket webSocket, ILogger logger) {
|
||||
ViewStream = viewStream;
|
||||
RequestId = requestId;
|
||||
Id = id;
|
||||
this.webSocket = webSocket;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
public JsonRpcId RequestId { get; }
|
||||
public SubscriptionStatus Status { get; private set; }
|
||||
|
||||
public void Start() {
|
||||
if (Status == SubscriptionStatus.Subscribed) {
|
||||
logger.LogWarning("Ignoring redundant call to 'Start'. Id = {Id} Status = {Status}", Id, Status);
|
||||
return;
|
||||
}
|
||||
logger.LogInformation("Subscribing to ViewStream. SubscriptionId = {SubscriptionId}", Id);
|
||||
Status = SubscriptionStatus.Subscribed;
|
||||
ViewStream.onChange += onChange;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken) {
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
Start();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Clear() {
|
||||
if (LastFired is null) {
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
logger.LogInformation("Clearing subscription (firing DataPacket to delete all rows). Id = {Id} Status = {Status}", Id, Status);
|
||||
return sendDataPacket("clear", new(new BlueTable(LastFired.schema), new BlueTable(LastFired.schema), LastFired.newRows));
|
||||
}
|
||||
|
||||
public void Stop() {
|
||||
if (Status == SubscriptionStatus.Unsubscribed) {
|
||||
logger.LogWarning("Ignoring redundant call to 'Stop'. Id = {Id} Status = {Status}", Id, Status);
|
||||
return;
|
||||
}
|
||||
logger.LogInformation("Unsubscribing from ViewStream. SubscriptionId = {SubscriptionId}", Id);
|
||||
Status = SubscriptionStatus.Unsubscribed;
|
||||
ViewStream.onChange -= onChange;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken) {
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
Stop();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose() =>
|
||||
Stop();
|
||||
|
||||
async void onChange(object newValue) {
|
||||
if (newValue is not DataPacket dp) {
|
||||
logger.LogError("Expected DataPacket in stream callback (actually received {}).", newValue?.GetType());
|
||||
return;
|
||||
}
|
||||
if (webSocket.State != WebSocketState.Open) {
|
||||
logger.LogError(
|
||||
"Unsubscribing from stream early because WebSocket state = {WebSocketState}", webSocket.State);
|
||||
Dispose();
|
||||
return;
|
||||
}
|
||||
await sendDataPacket("subscribe", dp);
|
||||
}
|
||||
|
||||
async Task sendDataPacket(string method, DataPacket dp) {
|
||||
var serializerOpts = new JsonSerializerOptions {
|
||||
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals
|
||||
};
|
||||
serializerOpts.Converters.Add(new DataPacketJsonConverter() {
|
||||
IncludeCurrent = true,
|
||||
UseObjectRows = true,
|
||||
});
|
||||
var res = JsonRpcRequest.CreateNotification(method, new DataStreamSubscriptionUpdate() {
|
||||
SubscriptionId = Id,
|
||||
Table = dp
|
||||
});
|
||||
var str = serialize(res, serializerOpts);
|
||||
if (str is null) {
|
||||
logger.LogError("Unsubscribing from stream early because we failed to serialize an outgoing DataPacket");
|
||||
Dispose();
|
||||
return;
|
||||
}
|
||||
logger.LogInformation(
|
||||
"Sending DataPacket. NumRows = {NumRows} NumCols = {NumCols} MessageLength = {MessageLength}",
|
||||
dp.newRows.Count,
|
||||
dp.schema.columnNames.Length,
|
||||
str.Length);
|
||||
var bytes = Encoding.UTF8.GetBytes(str);
|
||||
try {
|
||||
await webSocket.SendAsync(bytes, WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
LastFired = dp;
|
||||
} catch (WebSocketException ex) {
|
||||
logger.LogError($"sendDataPacket failed on webSocket.SendAsync: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
string? serialize<T>(T message, JsonSerializerOptions? opts) {
|
||||
opts ??= JsonSerializerOptions.Default;
|
||||
try {
|
||||
return JsonSerializer.Serialize(message, opts);
|
||||
} catch (Exception ex) {
|
||||
logger.LogError("Failed to serialize message of type {MessageType}: {Exception}", typeof(T), ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Bts.DataStreamWebApp.Server;
|
||||
|
||||
using BCG;
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
public class DataStreamSubscriptionUpdate {
|
||||
[JsonPropertyName("subscription_id")]
|
||||
public string? SubscriptionId { get; set; }
|
||||
|
||||
[JsonPropertyName("table")]
|
||||
public DataPacket? Table { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
namespace Bts.DataStreamWebApp.Server;
|
||||
|
||||
using Bts.PubSub;
|
||||
|
||||
using CommandLine;
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
class DataStreamWebAppServerConfig {
|
||||
/// <summary>
|
||||
/// The login user for sparkd
|
||||
/// </summary>
|
||||
[JsonPropertyName("user")]
|
||||
[Option("user", HelpText = "The sparkd login user")]
|
||||
public string? User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The login password for sparkd
|
||||
/// </summary>
|
||||
[JsonPropertyName("password")]
|
||||
[Option("pass", HelpText = "The sparkd login password")]
|
||||
public string? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The config server url for sparkd
|
||||
/// </summary>
|
||||
[JsonPropertyName("sparkd")]
|
||||
[Option("sparkd", HelpText = "The sparkd config server")]
|
||||
public string? Sparkd { get; set; }
|
||||
|
||||
[JsonPropertyName("pubsub")]
|
||||
public PubSubConfig? PubSub { get; set; }
|
||||
|
||||
[Option("content-root-path")]
|
||||
[JsonPropertyName("content_root_path")]
|
||||
public string? ContentRootPath { get; set; }
|
||||
|
||||
[Option("web-root-path")]
|
||||
[JsonPropertyName("web_root_path")]
|
||||
public string? WebRootPath { get; set; }
|
||||
|
||||
[Option("environment-name")]
|
||||
[JsonPropertyName("environment_name")]
|
||||
public string? EnvironmentName { get; set; }
|
||||
|
||||
public DirectoryBrowserOptions? DirectoryBrowser { get; set; }
|
||||
|
||||
[Option(
|
||||
"config",
|
||||
MetaValue = "PATH",
|
||||
HelpText = "Path to json file representing these options (DataStreamPublisherConfig)")]
|
||||
[JsonIgnore]
|
||||
public string? ConfigFile { get; set; }
|
||||
|
||||
public static DataStreamWebAppServerConfig Default() =>
|
||||
new() {
|
||||
User = "bts",
|
||||
PubSub = PubSubConfig.Default(),
|
||||
};
|
||||
|
||||
public void MergeWith(DataStreamWebAppServerConfig other) {
|
||||
User ??= other.User;
|
||||
Password ??= other.Password;
|
||||
PubSub ??= other.PubSub;
|
||||
Sparkd ??= other.Sparkd;
|
||||
ContentRootPath ??= other.ContentRootPath;
|
||||
WebRootPath ??= other.WebRootPath;
|
||||
ConfigFile ??= other.ConfigFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges options with those defined in `ConfigFile` (does not overwrite
|
||||
/// non-null existing values).
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// JsonSerializer.Deserialize returns null
|
||||
/// </exception>
|
||||
public void MergeWithConfigFile() {
|
||||
if (ConfigFile is null) {
|
||||
return;
|
||||
}
|
||||
var cfgString = File.ReadAllText(ConfigFile);
|
||||
var parsedCfg = JsonSerializer.Deserialize<DataStreamWebAppServerConfig>(cfgString) ??
|
||||
throw new InvalidOperationException($"Failed to parse json from {ConfigFile}");
|
||||
MergeWith(parsedCfg);
|
||||
ConfigFile = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Bts.DataStreamWebApp.Server;
|
||||
|
||||
public class DataStreamWebSocketConfig {
|
||||
public string? Endpoint { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
namespace Bts.DataStreamWebApp.Server.Controllers;
|
||||
|
||||
using bts.websocket_core.json_rpc;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.DataStreamWebApp.Server.Messages;
|
||||
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
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) {
|
||||
this.webSocket = webSocket;
|
||||
this.streamFactory = streamFactory;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task<int> Run(CancellationToken cancellationToken) {
|
||||
logger.LogInformation("DataStreamWebSocketServer running");
|
||||
await foreach (var req in JsonRpcRequestAsyncEnumerable.Create(webSocket, logger, cancellationToken)) {
|
||||
await (req.Method switch {
|
||||
"subscribe" => onSubscribe(req, cancellationToken),
|
||||
"unsubscribe" => onUnsubscribe(req.Deserialize<UnsubscribeRequest>(), cancellationToken),
|
||||
_ => Task.CompletedTask,
|
||||
});
|
||||
}
|
||||
logger.LogInformation("DataStreamWebSocketServer stopped");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes internal subscriptions. To additionally notify the client of the subscription status
|
||||
/// change(s), use <see cref="DisposeAsync"/>.
|
||||
/// </summary>
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
disposeSubscriptions();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes internal subscriptions (like <see cref="Dispose"/>), then sends 'subscription status change'
|
||||
/// notifications to the client (unlike <see cref="Dispose"/>).
|
||||
/// </summary>
|
||||
public async ValueTask DisposeAsync() {
|
||||
GC.SuppressFinalize(this);
|
||||
var finalSubs = subscriptions.Values.Select(s => (s.RequestId, s.Id)).ToList();
|
||||
disposeSubscriptions();
|
||||
// Send a 'subscription status change' msg to the client for each one.
|
||||
foreach (var (requestId, id) in finalSubs) {
|
||||
await sendSubscriptionStatus(requestId, id, "unsubscribe", SubscriptionStatus.Unsubscribed, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
async Task onSubscribe(JsonRpcRequest<JsonNode> req, CancellationToken cancellationToken) {
|
||||
ArgumentNullException.ThrowIfNull(req.Id);
|
||||
ArgumentException.ThrowIfNullOrEmpty(req.Method);
|
||||
if (!SubscribeRequest.Parse(req, out var subReq, out var parseErr, out var 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 });
|
||||
await send(rpcError, cancellationToken);
|
||||
return;
|
||||
}
|
||||
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)) {
|
||||
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 });
|
||||
await send(rpcError, cancellationToken);
|
||||
return;
|
||||
}
|
||||
if (subscriptions.TryGetValue(subId, out var oldSub)) {
|
||||
logger.LogInformation("Disposing existing subscription with id {SubscriptionId}", subId);
|
||||
oldSub.Dispose();
|
||||
}
|
||||
var sub = new DataStreamSubscription(subId, req.Id.Value, vs, webSocket, logger);
|
||||
subscriptions[subId] = sub;
|
||||
await sendSubscriptionStatus(req.Id.Value, subId, req.Method, SubscriptionStatus.Subscribed, cancellationToken);
|
||||
vs.ErrorChanged += OnStreamError;
|
||||
await sub.StartAsync(cancellationToken);
|
||||
|
||||
async void OnStreamError(Exception exception) {
|
||||
logger.LogError("Error in ViewStream (disposing subscription): {Exception}", exception);
|
||||
subscriptions.Remove(sub.Id);
|
||||
sub.Dispose();
|
||||
var error = new SubscriptionError() {
|
||||
ErrorMessage = "Error in ViewStream (disposing subscription)"
|
||||
};
|
||||
if (exception is not null) {
|
||||
error.ErrorMessage += ". " + exception.Message;
|
||||
error.StackTrace = exception.StackTrace?.Split("\n")?.ToList();
|
||||
}
|
||||
var rpcError = JsonRpcResponse.CreateError<SubscriptionError>(
|
||||
req.Id, new() { Code = (long)ErrorCode.ViewStreamError, Message = "Error in ViewStream (disposing subscription)", Data = error });
|
||||
await send(rpcError, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
async Task onUnsubscribe(JsonRpcRequest<UnsubscribeRequest> req, CancellationToken cancellationToken) {
|
||||
ArgumentNullException.ThrowIfNull(req.Id);
|
||||
ArgumentException.ThrowIfNullOrEmpty(req.Method);
|
||||
var subId = req.Params?.SubscriptionId ?? string.Empty;
|
||||
if (!disposeSubscription(subId)) {
|
||||
logger.LogInformation("Unable to dispose subscription. Subscription with id {Id} not found.", subId);
|
||||
}
|
||||
await sendSubscriptionStatus(req.Id.Value, subId, "unsubscribe", SubscriptionStatus.Unsubscribed, cancellationToken);
|
||||
}
|
||||
|
||||
bool disposeSubscription(string subId) {
|
||||
if (!subscriptions.TryGetValue(subId, out var sub)) {
|
||||
return false;
|
||||
}
|
||||
logger.LogInformation("Disposing subscription with id {Id}", subId);
|
||||
sub.Dispose();
|
||||
subscriptions.Remove(subId);
|
||||
return true;
|
||||
}
|
||||
|
||||
Task sendSubscriptionStatus(JsonRpcId reqId, string subId, string method, SubscriptionStatus status, CancellationToken cancellationToken) {
|
||||
logger.LogInformation("Sending {Method} ack. SubscriptionId = {SubscriptionId}", method, subId);
|
||||
var response = JsonRpcResponse.Create(reqId, new SubscriptionStatusMessage() {
|
||||
SubscriptionId = subId,
|
||||
Status = status,
|
||||
});
|
||||
return send(response, cancellationToken);
|
||||
}
|
||||
|
||||
Task send<T>(T message, CancellationToken cancellationToken) {
|
||||
if (message is null) {
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
var str = JsonSerializer.Serialize(message);
|
||||
var bytes = Encoding.UTF8.GetBytes(str);
|
||||
logger.LogTrace("Sending data. Length = {Length}", bytes.Length);
|
||||
return webSocket.SendAsync(bytes, WebSocketMessageType.Text, true, cancellationToken);
|
||||
}
|
||||
|
||||
void disposeSubscriptions() {
|
||||
logger.LogInformation("Disposing DataStreamWebSocketServer subscriptions. Count: {Count}", subscriptions.Count);
|
||||
subscriptions.Values.DisposeAll();
|
||||
subscriptions.Clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM bluetradingsystems/linux_dotnet7
|
||||
|
||||
ARG SOURCE_DIR="build/Release/bin/net7.0/linux-x64/publish"
|
||||
ARG WEB_ROOT="build/Bts.DataStreamWebApp.Client/production/dist"
|
||||
ARG CONF_FILE="src/DataStreamSuite/Bts.DataStreamWebApp.Server/spark.conf"
|
||||
|
||||
RUN dotnet dev-certs https --trust
|
||||
COPY --chown=bts:bts "${SOURCE_DIR}" "bin"
|
||||
COPY --chown=bts:bts "${WEB_ROOT}" "bin/wwwroot"
|
||||
COPY --chown=bts:bts "${CONF_FILE}" ".local/share/DataStream/conf/spark.conf"
|
||||
WORKDIR "/home/bts/bin"
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Bts.DataStreamWebApp.Server;
|
||||
|
||||
public class CannedQueriesResponse {
|
||||
public List<CannedQuery>? Items { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Bts.DataStreamWebApp.Server.Messages;
|
||||
|
||||
enum ErrorCode {
|
||||
None = 0,
|
||||
InvalidSubscriptionRequest,
|
||||
ViewStreamError,
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
namespace Bts.DataStreamWebApp.Server.Messages;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.websocket_core.json_rpc;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.DataStreamExpressions;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
public class SubscribeRequest {
|
||||
[JsonPropertyName("query")]
|
||||
public string? Query { get; set; }
|
||||
|
||||
[JsonPropertyName("subscription_id")]
|
||||
public string? SubscriptionId { get; set; }
|
||||
|
||||
internal static bool Parse(JsonRpcRequest<JsonNode> req, [NotNullWhen(true)]out SubscribeRequest? subscription, [NotNullWhen(false)]out SubscriptionError? error, out ErrorCode errorCode) {
|
||||
subscription = null;
|
||||
errorCode = ErrorCode.None;
|
||||
var paramsJsonObj = req.Params?.AsObject();
|
||||
error = null;
|
||||
if (paramsJsonObj is null) {
|
||||
errorCode = ErrorCode.InvalidSubscriptionRequest;
|
||||
error = new() { ErrorMessage = "'params' object not found" };
|
||||
return false;
|
||||
}
|
||||
subscription = paramsJsonObj.Deserialize<SubscribeRequest>();
|
||||
if (subscription is null) {
|
||||
errorCode = ErrorCode.InvalidSubscriptionRequest;
|
||||
error = new() { ErrorMessage = "'params' object invalid" };
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal bool ParseQuery(
|
||||
IDataStreamFactory streamFactory,
|
||||
[NotNullWhen(true)] out ViewStream? stream,
|
||||
[NotNullWhen(false)] out SubscriptionError? error,
|
||||
out ErrorCode errorCode
|
||||
) {
|
||||
stream = null;
|
||||
errorCode = ErrorCode.None;
|
||||
error = null;
|
||||
if (Query is null) {
|
||||
errorCode = ErrorCode.InvalidSubscriptionRequest;
|
||||
error = new() { ErrorMessage = "'params.query' field not found (expected a string)" };
|
||||
return false;
|
||||
}
|
||||
var exp = DataStreamExpressionsInterpreter.Evaluate(Query);
|
||||
if (exp is null) {
|
||||
errorCode = ErrorCode.InvalidSubscriptionRequest;
|
||||
error = new() { ErrorMessage = "'params.query' expression has invalid syntax" };
|
||||
return false;
|
||||
}
|
||||
Exception? exception = null;
|
||||
try {
|
||||
stream = exp.getView(new Dictionary<string, StatementExpression>(0), streamFactory);
|
||||
} catch (Exception ex) {
|
||||
exception = ex;
|
||||
}
|
||||
if (stream is null) {
|
||||
errorCode = ErrorCode.InvalidSubscriptionRequest;
|
||||
error = new() { ErrorMessage = "Failed to create ViewStream from 'params.query' expression (check for typos in arguments/typenames)" };
|
||||
if (exception is not null) {
|
||||
error.ErrorMessage += ". " + exception.Message;
|
||||
error.StackTrace = exception.StackTrace?.Split("\n")?.ToList();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Bts.DataStreamWebApp.Server.Messages;
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
public class SubscriptionError {
|
||||
[JsonPropertyName("error_message")]
|
||||
public string? ErrorMessage { get; set; }
|
||||
|
||||
[JsonPropertyName("stack_trace")]
|
||||
public List<string>? StackTrace { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace Bts.DataStreamWebApp.Server.Messages;
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
enum SubscriptionStatus {
|
||||
None,
|
||||
Subscribed,
|
||||
Unsubscribed,
|
||||
}
|
||||
|
||||
class SubscriptionStatusMessage {
|
||||
[JsonPropertyName("subscription_id")]
|
||||
public string? SubscriptionId { get; set; }
|
||||
|
||||
[JsonPropertyName("status")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public SubscriptionStatus Status { get; set; } = SubscriptionStatus.None;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Bts.DataStreamWebApp.Server.Messages;
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
public class UnsubscribeRequest {
|
||||
[JsonPropertyName("subscription_id")]
|
||||
public string? SubscriptionId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using Bts.DataStreamCore.Services;
|
||||
using Bts.PubSub.Services;
|
||||
using Bts.SharedStreams.Services;
|
||||
|
||||
using Spark.Api.Services;
|
||||
using Spark.Core.Services;
|
||||
|
||||
using System.Reactive.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(new WebApplicationOptions {
|
||||
Args = args,
|
||||
ApplicationName = "Bts.DataStreamWebApp.Server",
|
||||
});
|
||||
ConfigureApp(builder.Configuration, builder.Environment.EnvironmentName);
|
||||
ConfigureServices(builder.Services, builder.Configuration);
|
||||
|
||||
var app = builder.Build();
|
||||
var wsOpts = new WebSocketOptions {
|
||||
KeepAliveInterval = TimeSpan.FromMinutes(2)
|
||||
};
|
||||
if (app.Environment.IsDevelopment()) {
|
||||
app.UseDirectoryBrowser("/browse");
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
app.UseHttpsRedirection();
|
||||
app.UseWebSockets(wsOpts);
|
||||
app.UseDefaultFiles();
|
||||
app.UseStaticFiles();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
try {
|
||||
Console.Write($"Starting Application");
|
||||
app.Run();
|
||||
Console.Write($"Application exited gracefully.");
|
||||
} catch (Exception ex) {
|
||||
Console.Error.Write($"Application crashed: {ex}");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
static void ConfigureApp(ConfigurationManager configBuilder, string environment) {
|
||||
// We prefix appsettings with the exe name because multiple exes will usually be in the build dir
|
||||
// (this way, each exe can still load its own appsettings files from the current directory).
|
||||
var exeName = Assembly.GetCallingAssembly().GetName().Name;
|
||||
AddJsonFile($"{exeName}.appsettings.json");
|
||||
AddJsonFile($"{exeName}.appsettings.{environment}.json");
|
||||
|
||||
var cfg = configBuilder.GetSection("config")?.Value;
|
||||
if (!SetBasePath(cfg)) {
|
||||
AddJsonFile(cfg);
|
||||
}
|
||||
|
||||
bool SetBasePath(string? path) {
|
||||
if (!Directory.Exists(path)) {
|
||||
return false;
|
||||
}
|
||||
configBuilder.SetBasePath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddJsonFile(string? path) {
|
||||
if (!File.Exists(path)) {
|
||||
return false;
|
||||
}
|
||||
configBuilder.AddJsonFile(path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void ConfigureServices(IServiceCollection services, IConfiguration config) {
|
||||
services.AddDirectoryBrowser()
|
||||
.AddControllers().Services
|
||||
.AddEndpointsApiExplorer()
|
||||
.AddSwaggerGen();
|
||||
services.AddSpaStaticFiles();
|
||||
services.AddSpark(config.GetSection("Spark"))
|
||||
.AddSparkApi(config.GetSection("SparkApi"))
|
||||
.AddMasterWorker(config.GetSection("MasterWorker"))
|
||||
.AddViewStreamDatabase()
|
||||
.AddPrimitiveStreams(config.GetSection("PrimitiveStreams"))
|
||||
.AddMarketDataStreams()
|
||||
.AddNaturalLanguageStreams(config.GetSection("NaturalLanguageStream"))
|
||||
.AddCompositeDataStreamFactory()
|
||||
.AddPubSubClient(config.GetSection("PubSub"));
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:8080",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_HTTP_PORT": "8080",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy",
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:8080;https://localhost:8443",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_HTTP_PORT": "8080",
|
||||
"ASPNETCORE_HTTPS_PORT": "8443",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy",
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"PubSub": {
|
||||
"Routing": {
|
||||
"PublisherRoutes": [
|
||||
{
|
||||
"Name": "default",
|
||||
"ServerAddress": "bts-cloud://localhost:22019",
|
||||
"TagRegExp": ".*"
|
||||
}
|
||||
],
|
||||
"SubscriberRoutes": [
|
||||
{
|
||||
"Name": "default",
|
||||
"ServerAddress": "bts-cloud://localhost:22019",
|
||||
"TagRegExp": ".*"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"CannedQueries": [
|
||||
{
|
||||
"Name": "BBO",
|
||||
"Query": [
|
||||
"bbo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Trades",
|
||||
"Query": [
|
||||
"timesales"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Instruments",
|
||||
"Query": [
|
||||
"instruments"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Books",
|
||||
"Query": [
|
||||
"books"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Benzinga News",
|
||||
"Query": [
|
||||
"benzinga_news"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"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)"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Spark": {
|
||||
"ConfigServer": "http://sparkd:8000/config"
|
||||
},
|
||||
"SparkApi": {
|
||||
"IsEnabled": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"MasterWorker": {
|
||||
"Interval": "00:00:00.1"
|
||||
},
|
||||
"ViewStreamDatabase": {
|
||||
"Interval": "00:00:00.1"
|
||||
},
|
||||
"Spark": {
|
||||
"ConfigServer": "http://172.30.2.181:8000/config"
|
||||
},
|
||||
"SparkApi": {
|
||||
"Credentials": {
|
||||
"User": "bts",
|
||||
"Password": ""
|
||||
},
|
||||
"EnableAdmin": true,
|
||||
"EnableOrders": true,
|
||||
"EnablePosition": true
|
||||
},
|
||||
"PubSub": {
|
||||
"HeartbeatInterval": 15000,
|
||||
"MissingHeartbeatsBeforeGc": 50,
|
||||
"ServerPort": 22019,
|
||||
"Routing": {
|
||||
"PublisherRoutes": [
|
||||
{
|
||||
"Name": "default",
|
||||
"ServerAddress": "bts-cloud://172.30.2.181:22019",
|
||||
"TagRegExp": ".*"
|
||||
}
|
||||
],
|
||||
"SubscriberRoutes": [
|
||||
{
|
||||
"Name": "default",
|
||||
"ServerAddress": "bts-cloud://172.30.2.181:22019",
|
||||
"TagRegExp": ".*"
|
||||
}
|
||||
]
|
||||
},
|
||||
"TagTypeToAssemblyMap": {
|
||||
"Entries": [
|
||||
{
|
||||
"HandlerClass": "BCG.PubSubServerTagHandler",
|
||||
"Assembly": "DataStreamCore.dll"
|
||||
}
|
||||
]
|
||||
},
|
||||
"TagHandlerFactory": {
|
||||
"Handlers": [
|
||||
{
|
||||
"TagType": "DataStream",
|
||||
"Assembly": "DataStreamCore",
|
||||
"Class": "bts.PubsubServerStreamTagHandler"
|
||||
},
|
||||
{
|
||||
"TagType": "System_Sub",
|
||||
"Assembly": "PubSub",
|
||||
"Class": "BCG.SystemSubscriptionMapPublisher"
|
||||
},
|
||||
{
|
||||
"TagType": "System_Stats",
|
||||
"Assembly": "PubSub",
|
||||
"Class": "BCG.SystemStatsPublisher"
|
||||
},
|
||||
{
|
||||
"TagType": ".*",
|
||||
"Assembly": "DataStreamCore",
|
||||
"Class": "bts.PubsubServerGenericDataHandler"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Kestrel": {
|
||||
"Endpoints": {
|
||||
"Http": {
|
||||
"Url": "http://172.30.2.181:8080"
|
||||
},
|
||||
"Https": {
|
||||
"Url": "https://172.30.2.181:8443"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CannedQueries": [
|
||||
{
|
||||
"Name": "BBO",
|
||||
"Query": [
|
||||
"bbo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Trades",
|
||||
"Query": [
|
||||
"timesales"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Instruments",
|
||||
"Query": [
|
||||
"instruments"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Books",
|
||||
"Query": [
|
||||
"books"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Benzinga News",
|
||||
"Query": [
|
||||
"benzinga_news"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"CannedQueries": [
|
||||
{
|
||||
"Name": "BBO",
|
||||
"Query": [
|
||||
"bbo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Trades",
|
||||
"Query": [
|
||||
"timesales"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Instruments",
|
||||
"Query": [
|
||||
"instruments"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Books",
|
||||
"Query": [
|
||||
"books"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Benzinga News",
|
||||
"Query": [
|
||||
"benzinga_news"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Spark": {
|
||||
"ConfigServer": "http://sparkd:8000/config"
|
||||
},
|
||||
"SparkApi": {
|
||||
"IsEnabled": true,
|
||||
"Credentials": {
|
||||
"User": "bts",
|
||||
"Password": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,443 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Kestrel": {
|
||||
"Endpoints": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MasterWorker": {
|
||||
"Interval": "00:00:00.1"
|
||||
},
|
||||
"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": {
|
||||
"User": "bts",
|
||||
"Password": ""
|
||||
}
|
||||
},
|
||||
"PubSub": {
|
||||
"HeartbeatInterval": 15000,
|
||||
"MissingHeartbeatsBeforeGc": 50,
|
||||
"ServerPort": 22019,
|
||||
"Routing": {
|
||||
"PublisherRoutes": [
|
||||
{
|
||||
"Name": "default",
|
||||
"ServerAddress": "bts-cloud://pubsub:22019",
|
||||
"TagRegExp": ".*"
|
||||
}
|
||||
],
|
||||
"SubscriberRoutes": [
|
||||
{
|
||||
"Name": "default",
|
||||
"ServerAddress": "bts-cloud://pubsub:22019",
|
||||
"TagRegExp": ".*"
|
||||
}
|
||||
]
|
||||
},
|
||||
"TagTypeToAssemblyMap": {
|
||||
"Entries": [
|
||||
{
|
||||
"HandlerClass": "BCG.PubSubServerTagHandler",
|
||||
"Assembly": "DataStreamCore.dll"
|
||||
}
|
||||
]
|
||||
},
|
||||
"TagHandlerFactory": {
|
||||
"Handlers": [
|
||||
{
|
||||
"TagType": "DataStream",
|
||||
"Assembly": "DataStreamCore",
|
||||
"Class": "bts.PubsubServerStreamTagHandler"
|
||||
},
|
||||
{
|
||||
"TagType": "System_Sub",
|
||||
"Assembly": "PubSub",
|
||||
"Class": "BCG.SystemSubscriptionMapPublisher"
|
||||
},
|
||||
{
|
||||
"TagType": "System_Stats",
|
||||
"Assembly": "PubSub",
|
||||
"Class": "BCG.SystemStatsPublisher"
|
||||
},
|
||||
{
|
||||
"TagType": ".*",
|
||||
"Assembly": "DataStreamCore",
|
||||
"Class": "bts.PubsubServerGenericDataHandler"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
Logging {
|
||||
value {
|
||||
console {
|
||||
default_level: "Info"
|
||||
}
|
||||
syslog {
|
||||
default_level: "Info"
|
||||
}
|
||||
file {
|
||||
default_level: "Info"
|
||||
}
|
||||
initial_queue_size: 120001
|
||||
max_queue_growth: 4
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title></title>
|
||||
<style>
|
||||
table {
|
||||
border: 0
|
||||
}
|
||||
|
||||
.commslog-data {
|
||||
font-family: Consolas, Courier New, Courier, monospace;
|
||||
}
|
||||
|
||||
.commslog-server {
|
||||
background-color: red;
|
||||
color: white
|
||||
}
|
||||
|
||||
.commslog-client {
|
||||
background-color: green;
|
||||
color: white
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>ALT WebSocket Sample Application</h1>
|
||||
<p id="stateLabel">Ready to connect...</p>
|
||||
<div>
|
||||
<label for="connectionUrl">WebSocket Server URL:</label>
|
||||
<input id="connectionUrl" />
|
||||
<button id="connectButton" type="submit">Connect</button>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>
|
||||
<label for="sendMessage">Message to send:</label>
|
||||
<input id="sendMessage" disabled />
|
||||
<button id="sendButton" type="submit" disabled>Send</button>
|
||||
<button id="closeButton" disabled>Close Socket</button>
|
||||
</div>
|
||||
|
||||
<h2>Communication Log</h2>
|
||||
<table style="width: 800px">
|
||||
<thead>
|
||||
<tr>
|
||||
<td style="width: 100px">From</td>
|
||||
<td style="width: 100px">To</td>
|
||||
<td>Data</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="commsLog">
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
var connectionUrl = document.getElementById("connectionUrl");
|
||||
var connectButton = document.getElementById("connectButton");
|
||||
var stateLabel = document.getElementById("stateLabel");
|
||||
var sendMessage = document.getElementById("sendMessage");
|
||||
var sendButton = document.getElementById("sendButton");
|
||||
var commsLog = document.getElementById("commsLog");
|
||||
var closeButton = document.getElementById("closeButton");
|
||||
var socket;
|
||||
|
||||
var scheme = document.location.protocol === "https:" ? "wss" : "ws";
|
||||
var port = document.location.port ? (":" + document.location.port) : "";
|
||||
|
||||
connectionUrl.value = scheme + "://" + document.location.hostname + port + "/ws" ;
|
||||
|
||||
function updateState() {
|
||||
function disable() {
|
||||
sendMessage.disabled = true;
|
||||
sendButton.disabled = true;
|
||||
closeButton.disabled = true;
|
||||
}
|
||||
function enable() {
|
||||
sendMessage.disabled = false;
|
||||
sendButton.disabled = false;
|
||||
closeButton.disabled = false;
|
||||
}
|
||||
|
||||
connectionUrl.disabled = true;
|
||||
connectButton.disabled = true;
|
||||
|
||||
if (!socket) {
|
||||
disable();
|
||||
} else {
|
||||
switch (socket.readyState) {
|
||||
case WebSocket.CLOSED:
|
||||
stateLabel.innerHTML = "Closed";
|
||||
disable();
|
||||
connectionUrl.disabled = false;
|
||||
connectButton.disabled = false;
|
||||
break;
|
||||
case WebSocket.CLOSING:
|
||||
stateLabel.innerHTML = "Closing...";
|
||||
disable();
|
||||
break;
|
||||
case WebSocket.CONNECTING:
|
||||
stateLabel.innerHTML = "Connecting...";
|
||||
disable();
|
||||
break;
|
||||
case WebSocket.OPEN:
|
||||
stateLabel.innerHTML = "Open";
|
||||
enable();
|
||||
break;
|
||||
default:
|
||||
stateLabel.innerHTML = "Unknown WebSocket State: " + htmlEscape(socket.readyState);
|
||||
disable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closeButton.onclick = function () {
|
||||
if (!socket || socket.readyState !== WebSocket.OPEN) {
|
||||
alert("socket not connected");
|
||||
}
|
||||
socket.close(1000, "Closing from client");
|
||||
};
|
||||
|
||||
sendButton.onclick = function () {
|
||||
if (!socket || socket.readyState !== WebSocket.OPEN) {
|
||||
alert("socket not connected");
|
||||
}
|
||||
var data = sendMessage.value;
|
||||
socket.send(data);
|
||||
commsLog.innerHTML += '<tr>' +
|
||||
'<td class="commslog-client">Client</td>' +
|
||||
'<td class="commslog-server">Server</td>' +
|
||||
'<td class="commslog-data">' + htmlEscape(data) + '</td></tr>';
|
||||
};
|
||||
|
||||
connectButton.onclick = function() {
|
||||
stateLabel.innerHTML = "Connecting";
|
||||
socket = new WebSocket(connectionUrl.value);
|
||||
socket.onopen = function (event) {
|
||||
updateState();
|
||||
commsLog.innerHTML += '<tr>' +
|
||||
'<td colspan="3" class="commslog-data">Connection opened</td>' +
|
||||
'</tr>';
|
||||
};
|
||||
socket.onclose = function (event) {
|
||||
updateState();
|
||||
commsLog.innerHTML += '<tr>' +
|
||||
'<td colspan="3" class="commslog-data">Connection closed. Code: ' + htmlEscape(event.code) + '. Reason: ' + htmlEscape(event.reason) + '</td>' +
|
||||
'</tr>';
|
||||
};
|
||||
socket.onerror = updateState;
|
||||
socket.onmessage = function (event) {
|
||||
commsLog.innerHTML += '<tr>' +
|
||||
'<td class="commslog-server">Server</td>' +
|
||||
'<td class="commslog-client">Client</td>' +
|
||||
'<td class="commslog-data">' + htmlEscape(event.data) + '</td></tr>';
|
||||
};
|
||||
};
|
||||
|
||||
function htmlEscape(str) {
|
||||
return str.toString()
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,176 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title></title>
|
||||
<style>
|
||||
table {
|
||||
border: 0
|
||||
}
|
||||
|
||||
.commslog-data {
|
||||
font-family: Consolas, Courier New, Courier, monospace;
|
||||
}
|
||||
|
||||
.commslog-server {
|
||||
background-color: red;
|
||||
color: white
|
||||
}
|
||||
|
||||
.commslog-client {
|
||||
background-color: green;
|
||||
color: white
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>DataStreams via WebSocket</h1>
|
||||
<p id="stateLabel">Ready to connect...</p>
|
||||
<div>
|
||||
<label for="connectionUrl">WebSocket Server URL:</label>
|
||||
<input id="connectionUrl" />
|
||||
<button id="connectButton" type="submit">Connect</button>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>
|
||||
<label for="sendMessage">Query:</label>
|
||||
<input id="sendMessage" disabled />
|
||||
<button id="sendButton" type="submit" disabled>Send</button>
|
||||
<button id="closeButton" disabled>Close Socket</button>
|
||||
</div>
|
||||
|
||||
<h2>Communication Log</h2>
|
||||
<table style="width: 800px">
|
||||
<thead>
|
||||
<tr>
|
||||
<td style="width: 100px">From</td>
|
||||
<td style="width: 100px">To</td>
|
||||
<td>Data</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="commsLog">
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
var connectionUrl = document.getElementById("connectionUrl");
|
||||
var connectButton = document.getElementById("connectButton");
|
||||
var stateLabel = document.getElementById("stateLabel");
|
||||
var sendMessage = document.getElementById("sendMessage");
|
||||
var sendButton = document.getElementById("sendButton");
|
||||
var commsLog = document.getElementById("commsLog");
|
||||
var closeButton = document.getElementById("closeButton");
|
||||
var socket;
|
||||
|
||||
var scheme = document.location.protocol === "https:" ? "wss" : "ws";
|
||||
var port = document.location.port ? (":" + document.location.port) : "";
|
||||
|
||||
connectionUrl.value = scheme + "://" + document.location.hostname + port + "/ws" ;
|
||||
|
||||
function updateState() {
|
||||
function disable() {
|
||||
sendMessage.disabled = true;
|
||||
sendButton.disabled = true;
|
||||
closeButton.disabled = true;
|
||||
}
|
||||
function enable() {
|
||||
sendMessage.disabled = false;
|
||||
sendButton.disabled = false;
|
||||
closeButton.disabled = false;
|
||||
}
|
||||
|
||||
connectionUrl.disabled = true;
|
||||
connectButton.disabled = true;
|
||||
|
||||
if (!socket) {
|
||||
disable();
|
||||
} else {
|
||||
switch (socket.readyState) {
|
||||
case WebSocket.CLOSED:
|
||||
stateLabel.innerHTML = "Closed";
|
||||
disable();
|
||||
connectionUrl.disabled = false;
|
||||
connectButton.disabled = false;
|
||||
break;
|
||||
case WebSocket.CLOSING:
|
||||
stateLabel.innerHTML = "Closing...";
|
||||
disable();
|
||||
break;
|
||||
case WebSocket.CONNECTING:
|
||||
stateLabel.innerHTML = "Connecting...";
|
||||
disable();
|
||||
break;
|
||||
case WebSocket.OPEN:
|
||||
stateLabel.innerHTML = "Open";
|
||||
enable();
|
||||
break;
|
||||
default:
|
||||
stateLabel.innerHTML = "Unknown WebSocket State: " + htmlEscape(socket.readyState);
|
||||
disable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closeButton.onclick = function () {
|
||||
if (!socket || socket.readyState !== WebSocket.OPEN) {
|
||||
alert("socket not connected");
|
||||
}
|
||||
socket.close(1000, "Closing from client");
|
||||
};
|
||||
|
||||
sendButton.onclick = function () {
|
||||
if (!socket || socket.readyState !== WebSocket.OPEN) {
|
||||
alert("socket not connected");
|
||||
}
|
||||
const rpcReq = {
|
||||
jsonrpc: "2.0",
|
||||
method: "subscribe",
|
||||
params: {
|
||||
query: sendMessage.value,
|
||||
},
|
||||
id: 1,
|
||||
};
|
||||
const rpcReqStr = JSON.stringify(rpcReq);
|
||||
socket.send(rpcReqStr);
|
||||
commsLog.innerHTML += '<tr>' +
|
||||
'<td class="commslog-client">Client</td>' +
|
||||
'<td class="commslog-server">Server</td>' +
|
||||
'<td class="commslog-data">' + htmlEscape(rpcReqStr) + '</td></tr>';
|
||||
};
|
||||
|
||||
connectButton.onclick = function() {
|
||||
stateLabel.innerHTML = "Connecting";
|
||||
socket = new WebSocket(connectionUrl.value);
|
||||
socket.onopen = function (event) {
|
||||
updateState();
|
||||
commsLog.innerHTML += '<tr>' +
|
||||
'<td colspan="3" class="commslog-data">Connection opened</td>' +
|
||||
'</tr>';
|
||||
};
|
||||
socket.onclose = function (event) {
|
||||
updateState();
|
||||
commsLog.innerHTML += '<tr>' +
|
||||
'<td colspan="3" class="commslog-data">Connection closed. Code: ' + htmlEscape(event.code) + '. Reason: ' + htmlEscape(event.reason) + '</td>' +
|
||||
'</tr>';
|
||||
};
|
||||
socket.onerror = updateState;
|
||||
socket.onmessage = function (event) {
|
||||
commsLog.innerHTML += '<tr>' +
|
||||
'<td class="commslog-server">Server</td>' +
|
||||
'<td class="commslog-client">Client</td>' +
|
||||
'<td class="commslog-data">' + htmlEscape(event.data) + '</td></tr>';
|
||||
};
|
||||
};
|
||||
|
||||
function htmlEscape(str) {
|
||||
return str.toString()
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,59 @@
|
||||
namespace Bts.Extensions.Hosting;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
public static class HostBuilderExtensions {
|
||||
public static IHostBuilder CreateBtsBuilder(string[] args) {
|
||||
// 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) =>
|
||||
ConfigureApp(configBuilder, context.HostingEnvironment.EnvironmentName, exeName));
|
||||
}
|
||||
|
||||
public static void ConfigureApp(IConfigurationBuilder configBuilder, string? environment = null, string? prefix = null) {
|
||||
var baseFileName = prefix is null ? "appsettings" : $"{prefix}.appsettings";
|
||||
AddJsonFile($"{baseFileName}.json");
|
||||
if (environment is not null) {
|
||||
AddJsonFile($"{baseFileName}.{environment}.json");
|
||||
}
|
||||
|
||||
var cfg = configBuilder.Build().GetSection("config")?.Value;
|
||||
if (!SetBasePath(cfg)) {
|
||||
AddJsonFile(cfg);
|
||||
}
|
||||
|
||||
bool SetBasePath(string? path) {
|
||||
if (!Directory.Exists(path)) {
|
||||
return false;
|
||||
}
|
||||
configBuilder.SetBasePath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddJsonFile(string? path) {
|
||||
if (!File.Exists(path)) {
|
||||
return false;
|
||||
}
|
||||
configBuilder.AddJsonFile(path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetCallingAssemblyName() =>
|
||||
new StackTrace()
|
||||
.GetFrame(2)
|
||||
?.GetMethod()
|
||||
?.Module
|
||||
?.Assembly
|
||||
?.GetName()
|
||||
?.Name
|
||||
?? throw new InvalidOperationException("Failed to determine name of calling assembly (calling method is null)");
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace Bts.Net;
|
||||
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
/// <summary>
|
||||
/// Provides facilities to compare hosts for equality.
|
||||
/// <para>
|
||||
/// This class doesn't implement IEqualityComparer because a consistent hash code cannot be
|
||||
/// guarenteed for equivalent host strings. The equals impl relies on Dns.GetHostAddresses, which
|
||||
/// is non-determinstic (implementations that depends on mutable properties face a similar problem).
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class HostComparer {
|
||||
public static bool Equals(string? x, string? y) {
|
||||
if (x is null) {
|
||||
return y is null;
|
||||
}
|
||||
if (y is null) {
|
||||
return false;
|
||||
}
|
||||
return Dns.GetHostAddresses(x).Intersect(
|
||||
Dns.GetHostAddresses(y), IpAddressComparer.Instance).Any();
|
||||
}
|
||||
|
||||
public static bool Equals(IPHostEntry x, IPHostEntry y) =>
|
||||
x.AddressList.Intersect(y.AddressList, IpAddressComparer.Instance).Any();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Bts.Net;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
|
||||
/// <summary>
|
||||
/// Compares ip addresses. Unlike the default comparer, v4 and equivalent v6 addresses are
|
||||
/// considered equal.
|
||||
/// </summary>
|
||||
public class IpAddressComparer : IEqualityComparer<IPAddress> {
|
||||
public static IEqualityComparer<IPAddress> Instance { get; } = new IpAddressComparer();
|
||||
|
||||
public bool Equals(IPAddress? x, IPAddress? y) {
|
||||
if (x is null) {
|
||||
return y is null;
|
||||
}
|
||||
if (y is null) {
|
||||
return false;
|
||||
}
|
||||
return x.Equals(y) ||
|
||||
(x.IsIPv4MappedToIPv6 && x.MapToIPv4().Equals(y)) ||
|
||||
(y.IsIPv4MappedToIPv6 && y.MapToIPv4().Equals(x));
|
||||
}
|
||||
|
||||
public int GetHashCode([DisallowNull] IPAddress address) =>
|
||||
address.IsIPv4MappedToIPv6
|
||||
// Return consistent hash code for v4 and equivalent v6
|
||||
? address.MapToIPv4().GetHashCode()
|
||||
: address.GetHashCode();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace Bts.Net;
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
public class IpHostEntryJsonConverter : JsonConverter<IPHostEntry> {
|
||||
public override IPHostEntry? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, IPHostEntry value, JsonSerializerOptions options) {
|
||||
writer.WriteStartObject();
|
||||
// HostName
|
||||
writer.WriteString(nameof(value.HostName), value.HostName);
|
||||
// Aliases
|
||||
writer.WritePropertyName("Aliases");
|
||||
writer.WriteStartArray();
|
||||
foreach (var alias in value.Aliases) {
|
||||
writer.WriteStringValue(alias);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
// Addresses
|
||||
writer.WritePropertyName("Addresses");
|
||||
writer.WriteStartArray();
|
||||
foreach (var address in value.AddressList) {
|
||||
writer.WriteStringValue(address.ToString());
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace Bts.Net;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
/// <summary>
|
||||
/// This class seriailzes IpHostEntry to json (string). A common buffer is used to reduce memory
|
||||
/// allocations on repeated calls to <see cref="Serialize"/>. For that reason, this class is NOT
|
||||
/// thread safe.
|
||||
/// </summary>
|
||||
public class IpHostEntryJsonSerializer {
|
||||
readonly MemoryStream buffer = new();
|
||||
readonly IpHostEntryJsonConverter converter;
|
||||
|
||||
public IpHostEntryJsonSerializer(IpHostEntryJsonConverter? converter = null) =>
|
||||
this.converter = converter ?? new() { };
|
||||
|
||||
public string? Serialize(IPHostEntry dp, JsonSerializerOptions? opts = null) {
|
||||
opts ??= JsonSerializerOptions.Default;
|
||||
buffer.Position = 0;
|
||||
buffer.SetLength(0);
|
||||
using (var jsonWriter = new Utf8JsonWriter(buffer)) {
|
||||
converter.Write(jsonWriter, dp, opts);
|
||||
}
|
||||
var bytes = buffer.GetBuffer();
|
||||
var span = new ArraySegment<byte>(bytes, 0, (int)buffer.Length);
|
||||
return Encoding.UTF8.GetString(span);
|
||||
}
|
||||
|
||||
public void Serialize(IPHostEntry dp, Utf8JsonWriter jsonWriter, JsonSerializerOptions? opts = null) {
|
||||
opts ??= JsonSerializerOptions.Default;
|
||||
buffer.Position = 0;
|
||||
buffer.SetLength(0);
|
||||
converter.Write(jsonWriter, dp, opts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
namespace Bts.Net;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
public static partial class IpUtils {
|
||||
static readonly Regex ipv4Regex = new(string.Join('.', @"(((0|1)\d)|(2\d)|\d)?\d"));
|
||||
|
||||
// public static void ParseUri(string str, out string? scheme, out string? host, out string? port, out string? path, out string? queryParams) {
|
||||
// if (Uri.TryCreate(str, UriKind.Absolute, out var uri)) {
|
||||
// }
|
||||
// }
|
||||
|
||||
// public static bool AreEndpointsEqual(Uri? x, Uri? y) {
|
||||
// if (x is null) {
|
||||
// return y is null;
|
||||
// }
|
||||
// if (y is null) {
|
||||
// return false;
|
||||
// }
|
||||
// if (x.IsAbsoluteUri != y.IsAbsoluteUri) {
|
||||
// return false;
|
||||
// }
|
||||
// if (x.IsAbsoluteUri) {
|
||||
// if (x.Scheme != y.Scheme) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// string? xHost = null;
|
||||
// }
|
||||
|
||||
// static string ResolveHostIpv4(Uri uri) {
|
||||
// // switch (uri.HostNameType) {
|
||||
// // case UriHostNameType.IPv4:
|
||||
// // return uri.Host;
|
||||
// // case UriHostNameType.Dns:
|
||||
// // break;
|
||||
// // case UriHostNameType.IPv6:
|
||||
// // var addresses = Dns.GetHostAddresses(uri.Host);
|
||||
// // foreach (var address in addresses) {
|
||||
// // if (address.IsIPv4MappedToIPv6) {
|
||||
// // return address.MapToIPv4().Address;
|
||||
// // }
|
||||
// // }
|
||||
// // break;
|
||||
// // }
|
||||
// var hostAddresses = Dns.GetHostAddresses(uri.Host);
|
||||
// foreach (IPAddress address in hostAddresses) {
|
||||
// if (address.Equals(remoteEndPoint.Address) ||
|
||||
// (address.IsIPv4MappedToIPv6 && address.MapToIPv4().Equals(remoteEndPoint.Address)) ||
|
||||
// (remoteEndPoint.Address.IsIPv4MappedToIPv6 && remoteEndPoint.Address.MapToIPv4().Equals(address))) {
|
||||
// isMatch = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// public static bool AreEndpointsEqual(string? x, string? y) {
|
||||
// if (x == y) {
|
||||
// return true;
|
||||
// }
|
||||
// if (x is null) {
|
||||
// return y is null;
|
||||
// }
|
||||
// if (y is null) {
|
||||
// return false;
|
||||
// }
|
||||
// var xUri = new Uri(x);
|
||||
// var yUri = new Uri(y);
|
||||
// // return xUri.Equals(yUri);
|
||||
// }
|
||||
|
||||
public static bool IsIpv4(string host) {
|
||||
host = removeSchemaFromUrl(host);
|
||||
host = removePortFromUrl(host);
|
||||
return ipv4Regex.IsMatch(host);
|
||||
}
|
||||
|
||||
static string removeSchemaFromUrl(string url) {
|
||||
var i = url.IndexOf("://");
|
||||
return i < 0 ? url : url.Substring(i + 3);
|
||||
}
|
||||
|
||||
static string removePortFromUrl(string url) {
|
||||
var match = MyRegex().Match(url);
|
||||
return match.Success
|
||||
? string.Concat(url.AsSpan(0, match.Index), url.AsSpan(match.Index + match.Length))
|
||||
: url;
|
||||
}
|
||||
|
||||
[GeneratedRegex(":\\d{1,4}")]
|
||||
private static partial Regex MyRegex();
|
||||
}
|
||||
@@ -7,14 +7,11 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
|
||||
<PackageReference Include="YaccLexTools" Version="1.2.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DataStreamCore\DataStreamCore.csproj" />
|
||||
<ProjectReference Include="..\ExpressionCore\ExpressionCore.csproj" />
|
||||
<ProjectReference Include="..\..\client\spark_core\spark_core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Label="ColumnMapExpression">
|
||||
|
||||
@@ -14,14 +14,11 @@ namespace BCG {
|
||||
myVS = vs;
|
||||
}
|
||||
|
||||
public CountStream(string tableName)
|
||||
: this(new TableStream(tableName)) { }
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
myVS.onChange += new ChangeDelegate(myHandleChanges);
|
||||
myVS.onChange += myHandleChanges;
|
||||
}
|
||||
protected override void myOnLastSubscriber() {
|
||||
myVS.onChange -= new ChangeDelegate(myHandleChanges);
|
||||
myVS.onChange -= myHandleChanges;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -78,11 +78,12 @@ namespace bts.BlueOrb {
|
||||
#endregion
|
||||
|
||||
#region overridden methods
|
||||
protected override void myOnFirstSubscriber() { myParentStream.onChange += new ChangeDelegate(myHandleCallbacks); }
|
||||
protected override void myOnFirstSubscriber() =>
|
||||
myParentStream.onChange += myHandleCallbacks;
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
myLastFiredRows = null;
|
||||
myParentStream.onChange -= new ChangeDelegate(myHandleCallbacks);
|
||||
myParentStream.onChange -= myHandleCallbacks;
|
||||
}
|
||||
|
||||
protected override void myFireEvent(object o) {
|
||||
|
||||
@@ -16,10 +16,10 @@ namespace bts.BlueOrb {
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
_stream.onChange += new ChangeDelegate(_onstream_change);
|
||||
_stream.onChange += _onstream_change;
|
||||
}
|
||||
protected override void myOnLastSubscriber() {
|
||||
_stream.onChange -= new ChangeDelegate(_onstream_change);
|
||||
_stream.onChange -= _onstream_change;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,12 +12,11 @@ using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
public static class DataStreamExtensions {
|
||||
public static ViewStream AsViewStream(this IObservable<DataPacket> source) =>
|
||||
public static ViewStream AsViewStream(this IObservable<IDataPacket> source) =>
|
||||
source as ViewStream ?? new ObservableViewStream(source);
|
||||
|
||||
public static ViewStream AsViewStream<T>(this IObservable<IDataPacket<T>> source, string? name = null, ILogger? logger = null) where T : IBlueRow =>
|
||||
@@ -89,6 +88,25 @@ public static class DataStreamExtensions {
|
||||
.Where(t => t.Dp.addedRows.Any() || t.Dp.deletedRows.Any())
|
||||
.Select(t => t.Dp);
|
||||
|
||||
public static IObservable<IDataPacket<BlueRowAdapter<T>>> AsDataPackets<T, TKey>(this IObservable<TableUpdate<T, TKey>> source, BlueTableSchemaAdapter<T> schema) where TKey : IEquatable<TKey> {
|
||||
return Observable.Create<IDataPacket<BlueRowAdapter<T>>>(Subscribe);
|
||||
|
||||
IDisposable Subscribe(IObserver<IDataPacket<BlueRowAdapter<T>>> o) {
|
||||
var adapter = new BlueTableImmutableAdapter<T>(schema);
|
||||
IDataPacket<BlueRowAdapter<T>> initDataPacket = DataPacket<BlueRowAdapter<T>>.Empty(schema);
|
||||
return source.Scan((Adapter: adapter, DataPacket: initDataPacket), OnUpdate).Select(res => res.DataPacket).Subscribe(o);
|
||||
|
||||
(BlueTableImmutableAdapter<T> Adapter, IDataPacket<BlueRowAdapter<T>> DataPacket) OnUpdate(
|
||||
(BlueTableImmutableAdapter<T> Adapter, IDataPacket<BlueRowAdapter<T>> DataPacket) state, TableUpdate<T, TKey> tableUpdate) {
|
||||
var bd = state.Adapter.ToDataPacketBuilder();
|
||||
bd.Update(tableUpdate);
|
||||
var dp = bd.ToDataPacket();
|
||||
var tableAdapter = bd.ToImmutable();
|
||||
return (bd.ToImmutable(), dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ViewStream AsViewStream<T>(this IObservable<TableUpdate<T, int>> source, IBlueTableSchema schema) where T : IBlueRow =>
|
||||
source.AsDataPackets(schema).AsViewStream();
|
||||
|
||||
|
||||
@@ -3,24 +3,24 @@ namespace bts.SilverPine {
|
||||
using BCG;
|
||||
using System.Collections.Generic;
|
||||
using Bts.DataStreamExpressions;
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
// All this does is take in a dsl expression, parse it and fire the data that come out of running it.
|
||||
// So for example, if an expresison is passed
|
||||
[DataStreamUserRespresentation("dsl")]
|
||||
public class DSLStream : ViewStream {
|
||||
private readonly string _dsl;
|
||||
public DSLStream(string dsl) {
|
||||
public DSLStream(string dsl, IDataStreamFactory streamFactory) {
|
||||
Log.Gen.info($"DSLStream.cons dsl: {dsl}");
|
||||
_dsl = dsl;
|
||||
ViewStream rs = build_stream(dsl);
|
||||
rs = rs ?? new LiteralStream("error", $"msg:invalid dsl \"{dsl}\"");
|
||||
var rs = build_stream(streamFactory, dsl) ?? new LiteralStream("error", $"msg:invalid dsl");
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
|
||||
static ViewStream? build_stream(string stream_expression) {
|
||||
static ViewStream? build_stream(IDataStreamFactory streamFactory, string stream_expression) {
|
||||
try {
|
||||
var exp = DataStreamExpressionsInterpreter.Evaluate(stream_expression);
|
||||
var rv = exp.getView(new Dictionary<string, StatementExpression>(0));
|
||||
var rv = exp.getView(new Dictionary<string, StatementExpression>(0), streamFactory);
|
||||
return rv;
|
||||
|
||||
} catch (Exception ex) {
|
||||
@@ -29,4 +29,4 @@ namespace bts.SilverPine {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,13 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
using System;
|
||||
|
||||
public class ObservableViewStream : ViewStream, IObservable<DataPacket>, IDisposable {
|
||||
readonly IObservable<DataPacket> source;
|
||||
public class ObservableViewStream : ViewStream, IObservable<IDataPacket>, IDisposable {
|
||||
readonly IObservable<IDataPacket> source;
|
||||
readonly string? name;
|
||||
readonly ILogger? logger;
|
||||
IDisposable? subscription;
|
||||
|
||||
public ObservableViewStream(IObservable<DataPacket> source, string? name = null, ILogger? logger = null) {
|
||||
public ObservableViewStream(IObservable<IDataPacket> source, string? name = null, ILogger? logger = null) {
|
||||
this.source = source;
|
||||
this.name = name;
|
||||
this.logger = logger;
|
||||
@@ -45,6 +45,6 @@ public class ObservableViewStream : ViewStream, IObservable<DataPacket>, IDispos
|
||||
subscription = null;
|
||||
}
|
||||
|
||||
IDisposable IObservable<DataPacket>.Subscribe(IObserver<DataPacket> observer) =>
|
||||
IDisposable IObservable<IDataPacket>.Subscribe(IObserver<IDataPacket> observer) =>
|
||||
source.Subscribe(observer);
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Bts.DataStreamExpressions;
|
||||
using BCG.Utilities.General;
|
||||
using bts;
|
||||
|
||||
namespace BCG {
|
||||
// listens to the requests posted on "cloud_streams" request table, and
|
||||
// if unfulfilled starts a ViewPubsliher
|
||||
public class RemoteQueryManager : IWorker {
|
||||
public class StreamPubUnit {
|
||||
public string name;
|
||||
public string stream_expression;
|
||||
public ViewStream stream;
|
||||
public bool persist;
|
||||
public ViewPublisher view_publisher;
|
||||
|
||||
public StreamPubUnit(string name_, string stream_expression_, ViewStream stream_, bool persist_, ViewPublisher view_publisher_) {
|
||||
name = name_;
|
||||
stream_expression = stream_expression_;
|
||||
stream = stream_;
|
||||
persist = persist_;
|
||||
view_publisher = view_publisher_;
|
||||
}
|
||||
}
|
||||
static ViewStream? build_stream(string stream_expression)
|
||||
{
|
||||
try
|
||||
{
|
||||
var exp = DataStreamExpressionsInterpreter.Evaluate(stream_expression);
|
||||
var rv = exp.getView(new Dictionary<string, StatementExpression>(0));
|
||||
return rv;
|
||||
|
||||
} catch (Exception ex) {
|
||||
bts.Log.assert(false, $"Could not build stream: {stream_expression} ex: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private IDictionary<string, StreamPubUnit>
|
||||
_stream_pub_map = new Dictionary<string, StreamPubUnit>();
|
||||
private ViewStream _stream = new TableStream("cloud_streams");
|
||||
private PubTableBroker _broker = new PubTableBroker();
|
||||
private ManagedSubscriber _sub = ManagedSubscriber.instance;
|
||||
|
||||
|
||||
public RemoteQueryManager() {
|
||||
_stream.onChange += _on_str;
|
||||
_sub.subscribe("RemoteRequest", (string tag, byte[] data) => {
|
||||
RemoteRequest req = RemoteRequest.construct_from_bytes(data);
|
||||
_spawn_remote_stream(req.published_table_name, req.stream_expression, false);
|
||||
});
|
||||
}
|
||||
private void _on_str(object obj)
|
||||
{
|
||||
if (obj is not DataPacket dp) {
|
||||
return;
|
||||
}
|
||||
foreach (IBlueRow r in dp.newRows)
|
||||
{
|
||||
string name = r.get<string>("name");
|
||||
bool persist = r.get<bool>("persist");
|
||||
string stream_exp = r.get<string>("stream_exp");
|
||||
if (!_stream_pub_map.ContainsKey(name)) {
|
||||
_spawn_remote_stream(name, stream_exp, persist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _spawn_remote_stream(string name, string stream_expression, bool persist) {
|
||||
bts.Log.Gen.info($"CloudStreamManager.assign name: {name} stream_expression: {stream_expression}");
|
||||
ViewStream stream = build_stream(stream_expression);
|
||||
_expose_to_ws(name, stream);
|
||||
if (persist) {
|
||||
stream = new PersistorStream(stream, name, "C:\\Temp\\", 1000000); // 10MBs
|
||||
}
|
||||
ViewPublisher view_pub = new ViewPublisher(name, _broker, stream);
|
||||
StreamPubUnit u = new StreamPubUnit(name, stream_expression, stream, persist, view_pub);
|
||||
_stream_pub_map.Add(name, u);
|
||||
}
|
||||
|
||||
private void _expose_to_ws(string name, ViewStream stream) {
|
||||
// TODO: john
|
||||
}
|
||||
|
||||
public void doWork() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.DataStreamExpressions;
|
||||
using Bts.PubSub;
|
||||
|
||||
using bts;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BCG {
|
||||
// listens to the requests posted on "cloud_streams" request table, and
|
||||
// if unfulfilled starts a ViewPubsliher
|
||||
public class RemoteQueryManager : IHostedService {
|
||||
public class StreamPubUnit {
|
||||
public string name;
|
||||
public string stream_expression;
|
||||
public ViewStream stream;
|
||||
public bool persist;
|
||||
public ViewPublisher view_publisher;
|
||||
|
||||
public StreamPubUnit(string name_, string stream_expression_, ViewStream stream_, bool persist_, ViewPublisher view_publisher_) {
|
||||
name = name_;
|
||||
stream_expression = stream_expression_;
|
||||
stream = stream_;
|
||||
persist = persist_;
|
||||
view_publisher = view_publisher_;
|
||||
}
|
||||
}
|
||||
static ViewStream? build_stream(IDataStreamFactory streamFactory, string stream_expression)
|
||||
{
|
||||
try
|
||||
{
|
||||
var exp = DataStreamExpressionsInterpreter.Evaluate(stream_expression);
|
||||
var rv = exp.getView(new Dictionary<string, StatementExpression>(0), streamFactory);
|
||||
return rv;
|
||||
|
||||
} catch (Exception ex) {
|
||||
bts.Log.assert(false, $"Could not build stream: {stream_expression} ex: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private IDictionary<string, StreamPubUnit>
|
||||
_stream_pub_map = new Dictionary<string, StreamPubUnit>();
|
||||
readonly IPubTableBroker _broker;
|
||||
readonly IManagedSubscriber _sub;
|
||||
readonly IDataStreamFactory streamFactory;
|
||||
readonly object syncRoot = new();
|
||||
IDisposable? cloudStreamsSub;
|
||||
IDisposable? remoteRequestsSub;
|
||||
bool isDisposed;
|
||||
|
||||
|
||||
public RemoteQueryManager(IManagedSubscriber managedSubscriber, IPubTableBroker pubTableBroker, IEnumerable<IDataStreamFactory> streamFactories) {
|
||||
_sub = managedSubscriber;
|
||||
_broker = pubTableBroker;
|
||||
var streamFactoryList = streamFactories.ToList();
|
||||
streamFactory = streamFactoryList.Count == 1
|
||||
? streamFactoryList[0]
|
||||
: new CompositeDataStreamFactory(streamFactoryList);
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken) {
|
||||
lock (syncRoot) {
|
||||
Log.assert(!isDisposed);
|
||||
Log.isnull(cloudStreamsSub);
|
||||
Log.isnull(remoteRequestsSub);
|
||||
var cloudStream = streamFactory.Create("table", new (string?, int?, object?)[] { ("name", 0, "cloud_streams") })
|
||||
?? throw new Exception("Failed to create TableStream 'cloud_stream'");
|
||||
cloudStreamsSub = cloudStream.AsObservable().Subscribe(_on_str);
|
||||
remoteRequestsSub = _sub.Observe("RemoteRequest").Subscribe(data => {
|
||||
RemoteRequest req = RemoteRequest.construct_from_bytes(data);
|
||||
_spawn_remote_stream(req.published_table_name, req.stream_expression, false);
|
||||
});
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken) {
|
||||
lock (syncRoot) {
|
||||
if (!isDisposed) {
|
||||
isDisposed = true;
|
||||
Disposable.dispose(ref cloudStreamsSub);
|
||||
Disposable.dispose(ref remoteRequestsSub);
|
||||
}
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void _on_str(DataPacket dp)
|
||||
{
|
||||
foreach (IBlueRow r in dp.newRows)
|
||||
{
|
||||
string name = r.get<string>("name");
|
||||
bool persist = r.get<bool>("persist");
|
||||
string stream_exp = r.get<string>("stream_exp");
|
||||
if (!_stream_pub_map.ContainsKey(name)) {
|
||||
_spawn_remote_stream(name, stream_exp, persist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _spawn_remote_stream(string name, string stream_expression, bool persist) {
|
||||
bts.Log.Gen.info($"CloudStreamManager.assign name: {name} stream_expression: {stream_expression}");
|
||||
var stream = build_stream(streamFactory, stream_expression);
|
||||
if (stream is null) {
|
||||
Log.DataFlow.error($"Failed to spawn remote stream. name: {name}; expression: {stream_expression}");
|
||||
return;
|
||||
}
|
||||
_expose_to_ws(name, stream);
|
||||
if (persist) {
|
||||
stream = new PersistorStream(stream, name, "C:\\Temp\\", 1000000); // 10MBs
|
||||
}
|
||||
ViewPublisher view_pub = new ViewPublisher(name, _broker, stream);
|
||||
StreamPubUnit u = new StreamPubUnit(name, stream_expression, stream, persist, view_pub);
|
||||
_stream_pub_map.Add(name, u);
|
||||
}
|
||||
|
||||
private void _expose_to_ws(string name, ViewStream stream) {
|
||||
// TODO: john
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,29 @@ using BCG;
|
||||
|
||||
using bts;
|
||||
|
||||
using Bts.DataStreamCore.StreamFactories;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
|
||||
namespace BCG {
|
||||
// this is a stream so we can run it from the DSQA (since dsqa can only load streams)
|
||||
[DataStreamUserRespresentation("remoteQuery")]
|
||||
/// <summary>
|
||||
/// This is a stream so we can run it from the DSQA (since dsqa can only load streams).
|
||||
/// <para>
|
||||
/// Note: It's hidden because this stream is now created by an IDataStreamFactory
|
||||
/// (see RemoteQueryStreamFactory.cs for details)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[DataStreamUserRespresentation(false)]
|
||||
public class RemoteQueryStream : ViewStream {
|
||||
private readonly string _name, _stream_exp;
|
||||
readonly TableStreamFactory tableStreamFactory;
|
||||
private PublisherCore _publisher_core = new PublisherCore();
|
||||
private ViewStream _source_str;
|
||||
IDisposable? subscription;
|
||||
|
||||
public RemoteQueryStream(params string[] lines) {
|
||||
public RemoteQueryStream(TableStreamFactory tableStreamFactory, params string[] lines) {
|
||||
this.tableStreamFactory = tableStreamFactory;
|
||||
_stream_exp = get_expression(lines);
|
||||
_name = Guid.NewGuid().ToString();
|
||||
_name = $"remotereq_{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString()}";
|
||||
@@ -21,17 +33,17 @@ namespace BCG {
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
Log.isnull(subscription);
|
||||
RemoteRequest rem_req = new RemoteRequest(_stream_exp, _name);
|
||||
byte[] rem_req_bytes = rem_req.serialize();
|
||||
_publisher_core.publish("System", "RemoteRequest", rem_req_bytes);
|
||||
_source_str = new TableStream(_name);
|
||||
_source_str.onChange += new ChangeDelegate(_handle_data);
|
||||
var sourceStream = tableStreamFactory.Create(_name);
|
||||
sourceStream.onChange += _handle_data;
|
||||
subscription = Disposable.Create(() => sourceStream.onChange -= _handle_data);
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
//maybe there should be a way to turn remote requests off ?
|
||||
_source_str.onChange -= new ChangeDelegate(_handle_data);
|
||||
}
|
||||
protected override void myOnLastSubscriber() =>
|
||||
Disposable.dispose(ref subscription);
|
||||
|
||||
static string get_expression(params string[] lines) {
|
||||
for (int i = 0; i < lines.Length; i++) {
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
[DataStreamUserRespresentation("CountStream")]
|
||||
[DataStreamUserRespresentation("oldCount")]
|
||||
public class CountStream : ViewStream {
|
||||
private DataPacket myLastFiredDataPacket;
|
||||
private IBlueTableSchema mySchema = new BlueTableSchema("count",
|
||||
@@ -15,16 +15,11 @@ namespace bts.BlueOrb {
|
||||
myVS = vs;
|
||||
}
|
||||
|
||||
public CountStream(string tableName)
|
||||
: this(new TableStream(tableName)) { }
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
myVS.onChange += new ChangeDelegate(myHandleChanges);
|
||||
}
|
||||
protected override void myOnLastSubscriber() {
|
||||
myVS.onChange -= new ChangeDelegate(myHandleChanges);
|
||||
}
|
||||
protected override void myOnFirstSubscriber () =>
|
||||
myVS.onChange += myHandleChanges;
|
||||
|
||||
protected override void myOnLastSubscriber () =>
|
||||
myVS.onChange -= myHandleChanges;
|
||||
|
||||
private void myHandleChanges(object newValue) {
|
||||
myFireEvent(
|
||||
|
||||
Loaded 100 of 677 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user