diff --git a/.cargo/config.toml b/.cargo/config.toml
index a2e6bac554..19338323e5 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -1,3 +1,6 @@
+[build]
+rustflags = [ "--cfg", "tokio_unstable"]
+
[target.x86_64-unknown-linux-gnu]
rustflags = [
"-C", "link-arg=-fuse-ld=lld",
diff --git a/.ci/docker-compose.test-integration.yml b/.ci/docker-compose.test-integration.yml
index 4dc468e80c..766b904cd4 100644
--- a/.ci/docker-compose.test-integration.yml
+++ b/.ci/docker-compose.test-integration.yml
@@ -29,7 +29,7 @@ services:
- "PGPASSWORD=bugbear"
- "POSTGRES_USER=si_test"
- "POSTGRES_DB=si_test"
- - "POSTGRES_MULTIPLE_DBS=si_test_dal,si_test_sdf_server"
+ - "POSTGRES_MULTIPLE_DBS=si_test_content_store,si_test_dal,si_test_sdf_server"
command:
- "-c"
- "fsync=off"
diff --git a/Cargo.lock b/Cargo.lock
index 5990de4603..20771a4023 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
-version = "0.7.7"
+version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"
+checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
dependencies = [
"getrandom 0.2.12",
"once_cell",
@@ -30,9 +30,9 @@ dependencies = [
[[package]]
name = "ahash"
-version = "0.8.7"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
+checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff"
dependencies = [
"cfg-if",
"getrandom 0.2.12",
@@ -214,7 +214,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -236,7 +236,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -247,7 +247,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -272,6 +272,15 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "atomic-polyfill"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
+dependencies = [
+ "critical-section",
+]
+
[[package]]
name = "atomic-write-file"
version = "0.1.2"
@@ -412,7 +421,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -601,7 +610,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
"syn_derive",
]
@@ -646,9 +655,9 @@ dependencies = [
[[package]]
name = "bumpalo"
-version = "3.14.0"
+version = "3.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f"
[[package]]
name = "bytecheck"
@@ -729,9 +738,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "chrono"
-version = "0.4.33"
+version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb"
+checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
dependencies = [
"android-tzdata",
"iana-time-zone",
@@ -771,9 +780,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.0"
+version = "4.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f"
+checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da"
dependencies = [
"clap_builder",
"clap_derive",
@@ -781,9 +790,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.0"
+version = "4.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99"
+checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb"
dependencies = [
"anstream",
"anstyle",
@@ -801,7 +810,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -821,6 +830,12 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "cobs"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15"
+
[[package]]
name = "color-eyre"
version = "0.6.2"
@@ -1003,6 +1018,28 @@ dependencies = [
"url",
]
+[[package]]
+name = "content-store"
+version = "0.1.0"
+dependencies = [
+ "async-trait",
+ "blake3",
+ "bytes 1.5.0",
+ "chrono",
+ "color-eyre",
+ "postcard",
+ "postgres-types",
+ "refinery",
+ "remain",
+ "serde",
+ "serde_json",
+ "si-cbor",
+ "si-data-pg",
+ "telemetry",
+ "thiserror",
+ "uuid",
+]
+
[[package]]
name = "convert_case"
version = "0.4.0"
@@ -1092,13 +1129,19 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
[[package]]
name = "crc32fast"
-version = "1.3.2"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [
"cfg-if",
]
+[[package]]
+name = "critical-section"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
+
[[package]]
name = "crossbeam-channel"
version = "0.5.11"
@@ -1238,7 +1281,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -1342,6 +1385,7 @@ dependencies = [
"buck2-resources",
"chrono",
"ciborium",
+ "content-store",
"convert_case 0.6.0",
"council-server",
"dal-test",
@@ -1359,9 +1403,13 @@ dependencies = [
"once_cell",
"paste",
"petgraph",
+ "postcard",
"postgres-types",
"pretty_assertions_sorted",
"rand 0.8.5",
+ "rebaser-client",
+ "rebaser-core",
+ "rebaser-server",
"refinery",
"regex",
"remain",
@@ -1369,6 +1417,7 @@ dependencies = [
"serde-aux",
"serde_json",
"serde_with 3.6.1",
+ "si-cbor",
"si-crypto",
"si-data-nats",
"si-data-pg",
@@ -1394,6 +1443,7 @@ version = "0.1.0"
dependencies = [
"buck2-resources",
"color-eyre",
+ "content-store",
"council-server",
"dal",
"derive_builder",
@@ -1402,6 +1452,8 @@ dependencies = [
"module-index-client",
"names",
"pinga-server",
+ "rebaser-client",
+ "rebaser-server",
"remain",
"serde",
"serde_json",
@@ -1433,12 +1485,12 @@ dependencies = [
[[package]]
name = "darling"
-version = "0.20.5"
+version = "0.20.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8"
+checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955"
dependencies = [
- "darling_core 0.20.5",
- "darling_macro 0.20.5",
+ "darling_core 0.20.6",
+ "darling_macro 0.20.6",
]
[[package]]
@@ -1457,16 +1509,16 @@ dependencies = [
[[package]]
name = "darling_core"
-version = "0.20.5"
+version = "0.20.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3"
+checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim 0.10.0",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -1482,13 +1534,13 @@ dependencies = [
[[package]]
name = "darling_macro"
-version = "0.20.5"
+version = "0.20.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77"
+checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be"
dependencies = [
- "darling_core 0.20.5",
+ "darling_core 0.20.6",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -1809,9 +1861,9 @@ dependencies = [
[[package]]
name = "either"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
dependencies = [
"serde",
]
@@ -1837,6 +1889,12 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "embedded-io"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
+
[[package]]
name = "encode_unicode"
version = "0.3.6"
@@ -1862,7 +1920,7 @@ dependencies = [
"num-traits",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -2091,7 +2149,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -2221,7 +2279,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http",
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"slab",
"tokio",
"tokio-util",
@@ -2238,13 +2296,22 @@ dependencies = [
"crunchy",
]
+[[package]]
+name = "hash32"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
+dependencies = [
+ "byteorder",
+]
+
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
- "ahash 0.7.7",
+ "ahash 0.7.8",
]
[[package]]
@@ -2259,7 +2326,7 @@ version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
dependencies = [
- "ahash 0.8.7",
+ "ahash 0.8.8",
"allocator-api2",
]
@@ -2272,6 +2339,20 @@ dependencies = [
"hashbrown 0.14.3",
]
+[[package]]
+name = "heapless"
+version = "0.7.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
+dependencies = [
+ "atomic-polyfill",
+ "hash32",
+ "rustc_version",
+ "serde",
+ "spin 0.9.8",
+ "stable_deref_trait",
+]
+
[[package]]
name = "heck"
version = "0.4.1"
@@ -2283,9 +2364,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
-version = "0.3.5"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3"
+checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd"
[[package]]
name = "hex"
@@ -2544,9 +2625,9 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.2.2"
+version = "2.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520"
+checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
dependencies = [
"equivalent",
"hashbrown 0.14.3",
@@ -2555,9 +2636,9 @@ dependencies = [
[[package]]
name = "indicatif"
-version = "0.17.7"
+version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25"
+checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3"
dependencies = [
"console",
"instant",
@@ -2580,7 +2661,7 @@ checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -2812,7 +2893,7 @@ checksum = "afc95a651c82daf7004c824405aa1019723644950d488571bd718e3ed84646ed"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -3276,7 +3357,7 @@ checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a"
dependencies = [
"futures-core",
"futures-sink",
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"js-sys",
"once_cell",
"pin-project-lite",
@@ -3421,7 +3502,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -3435,7 +3516,7 @@ dependencies = [
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -3547,7 +3628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
dependencies = [
"fixedbitset",
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"serde",
"serde_derive",
]
@@ -3607,7 +3688,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -3640,10 +3721,12 @@ name = "pinga-server"
version = "0.1.0"
dependencies = [
"buck2-resources",
+ "content-store",
"dal",
"derive_builder",
"futures",
"nats-subscriber",
+ "rebaser-client",
"remain",
"serde",
"serde_json",
@@ -3684,9 +3767,9 @@ dependencies = [
[[package]]
name = "pkg-config"
-version = "0.3.29"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "platforms"
@@ -3736,6 +3819,18 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
+[[package]]
+name = "postcard"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8"
+dependencies = [
+ "cobs",
+ "embedded-io",
+ "heapless",
+ "serde",
+]
+
[[package]]
name = "postgres-derive"
version = "0.4.5"
@@ -3745,7 +3840,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -3872,7 +3967,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
"version_check",
"yansi 1.0.0-rc.1",
]
@@ -4016,6 +4111,70 @@ dependencies = [
"rand_core 0.5.1",
]
+[[package]]
+name = "rebaser"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "color-eyre",
+ "rebaser-server",
+ "telemetry-application",
+ "tokio",
+ "tokio-util",
+]
+
+[[package]]
+name = "rebaser-client"
+version = "0.1.0"
+dependencies = [
+ "futures",
+ "rebaser-core",
+ "remain",
+ "serde",
+ "serde_json",
+ "si-data-nats",
+ "telemetry",
+ "thiserror",
+ "ulid",
+]
+
+[[package]]
+name = "rebaser-core"
+version = "0.1.0"
+dependencies = [
+ "serde",
+ "serde_json",
+ "ulid",
+]
+
+[[package]]
+name = "rebaser-server"
+version = "0.1.0"
+dependencies = [
+ "buck2-resources",
+ "content-store",
+ "dal",
+ "derive_builder",
+ "futures",
+ "nats-subscriber",
+ "rebaser-core",
+ "remain",
+ "serde",
+ "serde_json",
+ "si-crypto",
+ "si-data-nats",
+ "si-data-pg",
+ "si-settings",
+ "si-std",
+ "si-test-macros",
+ "stream-cancel",
+ "telemetry",
+ "thiserror",
+ "tokio",
+ "ulid",
+ "veritech-client",
+]
+
[[package]]
name = "redox_syscall"
version = "0.4.1"
@@ -4077,7 +4236,7 @@ dependencies = [
"quote",
"refinery-core",
"regex",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -4132,7 +4291,7 @@ checksum = "1ad5e011230cad274d0532460c5ab69828ea47ae75681b42a841663efffaf794"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -4308,9 +4467,9 @@ dependencies = [
[[package]]
name = "rust_decimal"
-version = "1.34.2"
+version = "1.34.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "755392e1a2f77afd95580d3f0d0e94ac83eeeb7167552c9b5bca549e61a94d83"
+checksum = "b39449a79f45e8da28c57c341891b69a183044b29518bb8f86dbac9df60bb7df"
dependencies = [
"arrayvec",
"borsh",
@@ -4399,9 +4558,9 @@ dependencies = [
[[package]]
name = "rustls-pemfile"
-version = "2.0.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4"
+checksum = "3c333bb734fcdedcea57de1602543590f545f127dc8b533324318fd492c5c70b"
dependencies = [
"base64 0.21.7",
"rustls-pki-types",
@@ -4409,9 +4568,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.2.0"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf"
+checksum = "048a63e5b3ac996d78d402940b5fa47973d2d080c6c6fffa1d0f19c4445310b7"
[[package]]
name = "rustls-webpki"
@@ -4487,6 +4646,7 @@ dependencies = [
"clap",
"color-eyre",
"nats-multiplexer",
+ "rebaser-client",
"sdf-server",
"si-std",
"telemetry-application",
@@ -4503,6 +4663,7 @@ dependencies = [
"base64 0.21.7",
"buck2-resources",
"chrono",
+ "content-store",
"convert_case 0.6.0",
"dal",
"dal-test",
@@ -4560,7 +4721,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -4601,7 +4762,7 @@ dependencies = [
"proc-macro2",
"quote",
"sea-bae",
- "syn 2.0.48",
+ "syn 2.0.49",
"unicode-ident",
]
@@ -4726,7 +4887,7 @@ checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -4735,7 +4896,7 @@ version = "1.0.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
dependencies = [
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"itoa",
"ryu",
"serde",
@@ -4768,7 +4929,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -4828,7 +4989,7 @@ dependencies = [
"chrono",
"hex",
"indexmap 1.9.3",
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"serde",
"serde_derive",
"serde_json",
@@ -4842,10 +5003,10 @@ version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f"
dependencies = [
- "darling 0.20.5",
+ "darling 0.20.6",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -4854,10 +5015,10 @@ version = "3.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d"
dependencies = [
- "darling 0.20.5",
+ "darling 0.20.6",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -4866,7 +5027,7 @@ version = "0.9.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e"
dependencies = [
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"itoa",
"ryu",
"serde",
@@ -4920,6 +5081,16 @@ dependencies = [
"tokio-util",
]
+[[package]]
+name = "si-cbor"
+version = "0.1.0"
+dependencies = [
+ "ciborium",
+ "remain",
+ "serde",
+ "thiserror",
+]
+
[[package]]
name = "si-cli"
version = "0.1.0"
@@ -5005,7 +5176,7 @@ dependencies = [
"refinery",
"remain",
"rustls 0.22.2",
- "rustls-pemfile 2.0.0",
+ "rustls-pemfile 2.1.0",
"serde",
"si-std",
"telemetry",
@@ -5032,7 +5203,7 @@ dependencies = [
"base64 0.21.7",
"chrono",
"derive_builder",
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"object-tree",
"petgraph",
"remain",
@@ -5089,7 +5260,7 @@ version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -5269,7 +5440,7 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
dependencies = [
- "ahash 0.8.7",
+ "ahash 0.8.8",
"atoi",
"bigdecimal",
"byteorder",
@@ -5287,7 +5458,7 @@ dependencies = [
"futures-util",
"hashlink",
"hex",
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"log",
"memchr",
"once_cell",
@@ -5534,7 +5705,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -5569,9 +5740,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.48"
+version = "2.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496"
dependencies = [
"proc-macro2",
"quote",
@@ -5587,7 +5758,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -5735,27 +5906,27 @@ checksum = "7ba277e77219e9eea169e8508942db1bf5d8a41ff2db9b20aab5a5aadc9fa25d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
name = "thiserror"
-version = "1.0.56"
+version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
+checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.56"
+version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
+checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -5860,7 +6031,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -6045,7 +6216,7 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
- "toml_edit 0.22.4",
+ "toml_edit 0.22.6",
]
[[package]]
@@ -6063,11 +6234,11 @@ version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"serde",
"serde_spanned",
"toml_datetime",
- "winnow",
+ "winnow 0.5.40",
]
[[package]]
@@ -6076,22 +6247,22 @@ version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
dependencies = [
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"toml_datetime",
- "winnow",
+ "winnow 0.5.40",
]
[[package]]
name = "toml_edit"
-version = "0.22.4"
+version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951"
+checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6"
dependencies = [
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
"serde",
"serde_spanned",
"toml_datetime",
- "winnow",
+ "winnow 0.6.1",
]
[[package]]
@@ -6196,7 +6367,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -6607,7 +6778,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
"wasm-bindgen-shared",
]
@@ -6641,7 +6812,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -6872,9 +7043,18 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
-version = "0.5.39"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winnow"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29"
+checksum = "d90f4e0f530c4c69f62b80d839e9ef3855edc9cba471a160c4d692deed62b401"
dependencies = [
"memchr",
]
@@ -6993,7 +7173,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
[[package]]
@@ -7013,5 +7193,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.49",
]
diff --git a/Cargo.toml b/Cargo.toml
index 08c65f1ed8..2dc4522146 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,7 @@ members = [
"bin/cyclone",
"bin/module-index",
"bin/pinga",
+ "bin/rebaser",
"bin/sdf",
"bin/si",
"bin/veritech",
@@ -15,6 +16,7 @@ members = [
"lib/buck2-resources",
"lib/bytes-lines-codec",
"lib/config-file",
+ "lib/content-store",
"lib/council-server",
"lib/cyclone-client",
"lib/cyclone-core",
@@ -30,7 +32,11 @@ members = [
"lib/nats-subscriber",
"lib/object-tree",
"lib/pinga-server",
+ "lib/rebaser-client",
+ "lib/rebaser-core",
+ "lib/rebaser-server",
"lib/sdf-server",
+ "lib/si-cbor",
"lib/si-crypto",
"lib/si-data-nats",
"lib/si-data-pg",
@@ -124,6 +130,7 @@ pathdiff = "0.2.1"
petgraph = { version = "0.6.3", features = ["serde-1"] }
pin-project-lite = "0.2.9"
podman-api = "0.10"
+postcard = { version = "1.0.8", features = ["use-std"] }
postgres-types = { version = "0.2.5", features = ["derive"] }
pretty_assertions_sorted = "1.2.1"
proc-macro2 = "1.0.56"
diff --git a/README.md b/README.md
index 83baa13c6f..79a2b4dc1e 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,12 @@ To learn more, read our ["Second Wave DevOps" blog post](https://www.systeminit.
## Quickstart
-Follow the [Local Development Setup](#local-development-setup) instructions below.
+**We recommend running SI using the stable version of the engine.
+To do so, please checkout [`old-engine`](https://github.com/systeminit/si/tree/old-engine) and follow the instructions in its [README](https://github.com/systeminit/si/blob/old-engine/README.md).**
+
+> Disclaimer: contents of the [`docs`](./docs) directory may be out of date until the current architecture becomes stable.
+
+Otherwise, follow the [Local Development Setup](#local-development-setup) instructions below.
We are working on and investigating more way(s) to try out System Initiative in the future.
## Local Development Setup
diff --git a/app/web/package.json b/app/web/package.json
index 2896fe50ce..4dc750fb1b 100644
--- a/app/web/package.json
+++ b/app/web/package.json
@@ -55,6 +55,9 @@
"date-fns": "^2.29.2",
"floating-vue": "^2.0.0-beta.16",
"fontfaceobserver": "^2.3.0",
+ "graphology": "^0.25.4",
+ "graphology-layout-forceatlas2": "^0.10.1",
+ "graphology-layout-noverlap": "^0.4.2",
"is-promise": "^4.0.0",
"javascript-time-ago": "^2.5.7",
"joi": "^17.11.0",
@@ -72,6 +75,7 @@
"plur": "^5.1.0",
"posthog-js": "^1.76.0",
"reconnecting-websocket": "^4.4.0",
+ "sigma": "3.0.0-beta.5",
"tinycolor2": "^1.4.2",
"typescript": "^4.9.5",
"util-browser": "^0.0.2",
@@ -105,6 +109,7 @@
"cypress-vite": "^1.5.0",
"eslint": "^8.36.0",
"faker": "^6.6.6",
+ "graphology-types": "^0.24.7",
"unplugin-icons": "^0.17.1",
"vite": "^5.0.10",
"vite-plugin-checker": "^0.6.2",
diff --git a/app/web/src/components/Workspace/WorkspaceViz.vue b/app/web/src/components/Workspace/WorkspaceViz.vue
new file mode 100644
index 0000000000..171b00a3cb
--- /dev/null
+++ b/app/web/src/components/Workspace/WorkspaceViz.vue
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/web/src/components/Workspace/WorkspaceVizSchemaVariant.vue b/app/web/src/components/Workspace/WorkspaceVizSchemaVariant.vue
new file mode 100644
index 0000000000..11d14a3f77
--- /dev/null
+++ b/app/web/src/components/Workspace/WorkspaceVizSchemaVariant.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
diff --git a/app/web/src/store/viz.store.ts b/app/web/src/store/viz.store.ts
new file mode 100644
index 0000000000..d091404b7e
--- /dev/null
+++ b/app/web/src/store/viz.store.ts
@@ -0,0 +1,81 @@
+import { defineStore } from "pinia";
+import { ApiRequest, addStoreHooks } from "@si/vue-lib/pinia";
+import { useWorkspacesStore } from "@/store/workspaces.store";
+import { useChangeSetsStore } from "@/store/change_sets.store";
+import { Visibility } from "@/api/sdf/dal/visibility";
+import { nilId } from "@/utils/nilId";
+
+export type NodeKind = "Category" | "Content" | "Func" | "Ordering" | "Prop";
+
+export type ContentKind =
+ | "Root"
+ | "ActionPrototype"
+ | "AttributePrototype"
+ | "AttributePrototypeArgument"
+ | "AttributeValue"
+ | "Component"
+ | "ExternalProvider"
+ | "FuncArg"
+ | "Func"
+ | "InternalProvider"
+ | "Prop"
+ | "Schema"
+ | "SchemaVariant"
+ | "StaticArgumentValue"
+ | "ValidationPrototype";
+
+export interface VizResponse {
+ edges: {
+ from: string;
+ to: string;
+ }[];
+
+ nodes: {
+ id: string;
+ nodeKind: NodeKind;
+ contentKind: ContentKind | null;
+ name: string | null;
+ }[];
+
+ rootNodeId: string;
+}
+
+export const useVizStore = () => {
+ const changeSetStore = useChangeSetsStore();
+ const selectedChangeSetId = changeSetStore.selectedChangeSetId;
+ const workspacesStore = useWorkspacesStore();
+ const workspaceId = workspacesStore.selectedWorkspacePk;
+ const visibility: Visibility = {
+ visibility_change_set_pk: selectedChangeSetId ?? nilId(),
+ };
+
+ return addStoreHooks(
+ defineStore(
+ `ws${workspaceId || "NONE"}/cs${selectedChangeSetId || "NONE"}/viz`,
+ {
+ state: () => ({
+ edges: [],
+ nodes: [],
+ }),
+ getters: {
+ nodes: (state) => state.nodes,
+ edges: (state) => state.edges,
+ },
+ actions: {
+ async FETCH_VIZ() {
+ return new ApiRequest({
+ url: "/graphviz/nodes_edges",
+ params: { ...visibility },
+ });
+ },
+ async FETCH_SCHEMA_VARIANT_VIZ(schemaVariantId: string) {
+ return new ApiRequest({
+ url: "/graphviz/schema_variant",
+ params: { schemaVariantId, ...visibility },
+ });
+ },
+ },
+ },
+ ),
+ )();
+};
diff --git a/bin/rebaser/BUCK b/bin/rebaser/BUCK
new file mode 100644
index 0000000000..f61bde4387
--- /dev/null
+++ b/bin/rebaser/BUCK
@@ -0,0 +1,29 @@
+load(
+ "@prelude-si//:macros.bzl",
+ "docker_image",
+ "rust_binary",
+)
+
+rust_binary(
+ name = "rebaser",
+ deps = [
+ "//lib/rebaser-server:rebaser-server",
+ "//lib/telemetry-application-rs:telemetry-application",
+ "//third-party/rust:clap",
+ "//third-party/rust:color-eyre",
+ "//third-party/rust:tokio",
+ "//third-party/rust:tokio-util",
+ ],
+ srcs = glob(["src/**/*.rs"]),
+ resources = {
+ "dev.encryption.key": "//lib/cyclone-server:dev.encryption.key",
+ "dev.donkey.key": "//lib/dal:dev.donkey.key",
+ "dev.postgres.root.crt": "//config/keys:dev.postgres.root.crt",
+ },
+)
+
+docker_image(
+ name = "image",
+ image_name = "rebaser",
+ build_deps = ["//bin/rebaser:rebaser"]
+)
diff --git a/bin/rebaser/Cargo.toml b/bin/rebaser/Cargo.toml
new file mode 100644
index 0000000000..7bcf3086ed
--- /dev/null
+++ b/bin/rebaser/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "rebaser"
+version = "0.1.0"
+edition = "2021"
+rust-version = "1.64"
+publish = false
+
+[[bin]]
+name = "rebaser"
+path = "src/main.rs"
+
+[dependencies]
+clap = { workspace = true }
+color-eyre = { workspace = true }
+rebaser-server = { path = "../../lib/rebaser-server" }
+telemetry-application = { path = "../../lib/telemetry-application-rs" }
+tokio = { workspace = true }
+tokio-util = { workspace = true }
diff --git a/bin/rebaser/Dockerfile b/bin/rebaser/Dockerfile
new file mode 100644
index 0000000000..0be26bbabc
--- /dev/null
+++ b/bin/rebaser/Dockerfile
@@ -0,0 +1,38 @@
+# hadolint ignore=DL3007
+FROM nixos/nix:latest AS builder
+ARG BIN=rebaser
+
+COPY . /workdir
+WORKDIR /workdir
+
+RUN set -eux; \
+ nix \
+ --extra-experimental-features "nix-command flakes impure-derivations ca-derivations" \
+ --option filter-syscalls false \
+ build \
+ ".#$BIN";
+
+RUN mkdir -p /tmp/nix-store-closure /tmp/local-bin
+# hadolint ignore=SC2046
+RUN cp -R $(nix-store --query --requisites result/) /tmp/nix-store-closure
+# hadolint ignore=SC2046
+RUN ln -snf $(nix-store --query result/)/bin/* /tmp/local-bin/
+
+FROM alpine:3 AS final
+ARG BIN=rebaser
+
+# hadolint ignore=DL3018
+RUN set -eux; \
+ apk add --no-cache runuser; \
+ adduser -D app; \
+ for dir in /run /etc /usr/local/etc /home/app/.config; do \
+ mkdir -pv "$dir/$BIN"; \
+ done;
+
+WORKDIR /run/$BIN
+COPY --from=builder /tmp/nix-store-closure /nix/store
+COPY --from=builder /tmp/local-bin/* /usr/local/bin/
+
+ENTRYPOINT [ \
+ "/sbin/runuser", "-u", "app", "--", "/usr/local/bin/rebaser" \
+]
diff --git a/bin/rebaser/src/args.rs b/bin/rebaser/src/args.rs
new file mode 100644
index 0000000000..b74aa412c7
--- /dev/null
+++ b/bin/rebaser/src/args.rs
@@ -0,0 +1,112 @@
+use clap::{ArgAction, Parser};
+use rebaser_server::{Config, ConfigError, ConfigFile, StandardConfigFile};
+
+const NAME: &str = "rebaser";
+
+/// Parse, validate, and return the CLI arguments as a typed struct.
+pub(crate) fn parse() -> Args {
+ Args::parse()
+}
+
+#[derive(Parser, Debug)]
+#[command(name = NAME, max_term_width = 100)]
+pub(crate) struct Args {
+ /// Sets the verbosity mode.
+ ///
+ /// Multiple -v options increase verbosity. The maximum is 4.
+ #[arg(short = 'v', long = "verbose", action = ArgAction::Count)]
+ pub(crate) verbose: u8,
+
+ /// PostgreSQL connection pool dbname [example: myapp]
+ #[arg(long)]
+ pub(crate) pg_dbname: Option,
+
+ /// PostgreSQL connection pool hostname [example: prod.db.example.com]
+ #[arg(long)]
+ pub(crate) pg_hostname: Option,
+
+ /// PostgreSQL connection pool max size [example: 8]
+ #[arg(long)]
+ pub(crate) pg_pool_max_size: Option,
+
+ /// PostgreSQL connection pool port [example: 5432]
+ #[arg(long)]
+ pub(crate) pg_port: Option,
+
+ /// PostgreSQL connection pool user [example: dbuser]
+ #[arg(long)]
+ pub(crate) pg_user: Option,
+
+ /// NATS connection URL [example: demo.nats.io]
+ #[arg(long)]
+ pub(crate) nats_url: Option,
+
+ /// Disable OpenTelemetry on startup
+ #[arg(long)]
+ pub(crate) disable_opentelemetry: bool,
+
+ /// Cyclone encryption key file location [default: /run/rebaser/cyclone_encryption.key]
+ #[arg(long)]
+ pub(crate) cyclone_encryption_key_path: Option,
+
+ /// The number of concurrent jobs that can be processed [default: 10]
+ #[arg(long)]
+ pub(crate) concurrency: Option,
+
+ /// Instance ID [example: 01GWEAANW5BVFK5KDRVS6DEY0F"]
+ ///
+ /// And instance ID is used when tracking the execution of jobs in a way that can be traced
+ /// back to an instance of a Pinga service.
+ #[arg(long)]
+ pub(crate) instance_id: Option,
+}
+
+impl TryFrom for Config {
+ type Error = ConfigError;
+
+ fn try_from(args: Args) -> Result {
+ ConfigFile::layered_load(NAME, |config_map| {
+ if let Some(dbname) = args.pg_dbname {
+ config_map.set("pg.dbname", dbname);
+ }
+ if let Some(hostname) = args.pg_hostname {
+ config_map.set("pg.hostname", hostname);
+ }
+ if let Some(pool_max_size) = args.pg_pool_max_size {
+ config_map.set("pg.pool_max_size", i64::from(pool_max_size));
+ }
+ if let Some(port) = args.pg_port {
+ config_map.set("pg.port", i64::from(port));
+ }
+ if let Some(user) = args.pg_user {
+ config_map.set("pg.user", user);
+ }
+ if let Some(url) = args.nats_url {
+ config_map.set("nats.url", url);
+ }
+ if let Some(cyclone_encyption_key_path) = args.cyclone_encryption_key_path {
+ config_map.set("cyclone_encryption_key_path", cyclone_encyption_key_path);
+ }
+ if let Some(concurrency) = args.concurrency {
+ config_map.set("concurrency_limit", i64::from(concurrency));
+ }
+ if let Some(instance_id) = args.instance_id {
+ config_map.set("instance_id", instance_id);
+ }
+
+ config_map.set("pg.application_name", NAME);
+ })?
+ .try_into()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn verify_command() {
+ use clap::CommandFactory;
+ Args::command().debug_assert()
+ }
+}
diff --git a/bin/rebaser/src/main.rs b/bin/rebaser/src/main.rs
new file mode 100644
index 0000000000..693e1a1260
--- /dev/null
+++ b/bin/rebaser/src/main.rs
@@ -0,0 +1,62 @@
+use color_eyre::Result;
+use rebaser_server::{Config, Server};
+use telemetry_application::prelude::*;
+use tokio_util::{sync::CancellationToken, task::TaskTracker};
+
+mod args;
+
+const RT_DEFAULT_THREAD_STACK_SIZE: usize = 2 * 1024 * 1024 * 3;
+
+fn main() -> Result<()> {
+ let thread_builder = ::std::thread::Builder::new().stack_size(RT_DEFAULT_THREAD_STACK_SIZE);
+ let thread_handler = thread_builder.spawn(|| {
+ tokio::runtime::Builder::new_multi_thread()
+ .thread_stack_size(RT_DEFAULT_THREAD_STACK_SIZE)
+ .thread_name("bin/rebaser-tokio::runtime")
+ .enable_all()
+ .build()?
+ .block_on(async_main())
+ })?;
+ thread_handler.join().unwrap()
+}
+
+async fn async_main() -> Result<()> {
+ let shutdown_token = CancellationToken::new();
+ let task_tracker = TaskTracker::new();
+
+ color_eyre::install()?;
+ let args = args::parse();
+
+ let (mut telemetry, telemetry_shutdown) = {
+ let config = TelemetryConfig::builder()
+ .service_name("rebaser")
+ .service_namespace("si")
+ .log_env_var_prefix("SI")
+ .app_modules(vec!["rebaser", "rebaser_server"])
+ .interesting_modules(vec!["si_data_nats", "si_data_pg"])
+ .build()?;
+
+ telemetry_application::init(config, &task_tracker, shutdown_token.clone())?
+ };
+
+ if args.verbose > 0 {
+ telemetry
+ .set_verbosity_and_wait(args.verbose.into())
+ .await?;
+ }
+ debug!(arguments =?args, "parsed cli arguments");
+
+ let config = Config::try_from(args)?;
+
+ Server::from_config(config).await?.run().await?;
+
+ // TODO(nick): see other TODOs from the other services with similar shutdown procedures.
+ {
+ shutdown_token.cancel();
+ task_tracker.wait().await;
+ telemetry_shutdown.wait().await?;
+ }
+
+ info!("graceful shutdown complete.");
+ Ok(())
+}
diff --git a/bin/sdf/BUCK b/bin/sdf/BUCK
index c1e732a7de..ea14648bd2 100644
--- a/bin/sdf/BUCK
+++ b/bin/sdf/BUCK
@@ -9,6 +9,7 @@ rust_binary(
name = "sdf",
deps = [
"//lib/nats-multiplexer:nats-multiplexer",
+ "//lib/rebaser-client:rebaser-client",
"//lib/sdf-server:sdf-server",
"//lib/si-std:si-std",
"//lib/telemetry-application-rs:telemetry-application",
diff --git a/bin/sdf/Cargo.toml b/bin/sdf/Cargo.toml
index a4ab96c772..f4d06d7791 100644
--- a/bin/sdf/Cargo.toml
+++ b/bin/sdf/Cargo.toml
@@ -10,11 +10,13 @@ name = "sdf"
path = "src/main.rs"
[dependencies]
-clap = { workspace = true }
-color-eyre = { workspace = true }
nats-multiplexer = { path = "../../lib/nats-multiplexer" }
+rebaser-client = { path = "../../lib/rebaser-client" }
sdf-server = { path = "../../lib/sdf-server" }
si-std = { path = "../../lib/si-std" }
telemetry-application = { path = "../../lib/telemetry-application-rs" }
+
+clap = { workspace = true }
+color-eyre = { workspace = true }
tokio = { workspace = true }
tokio-util = { workspace = true }
diff --git a/bin/sdf/src/main.rs b/bin/sdf/src/main.rs
index c85fb17a48..259729cd50 100644
--- a/bin/sdf/src/main.rs
+++ b/bin/sdf/src/main.rs
@@ -12,6 +12,8 @@ use sdf_server::{
use telemetry_application::prelude::*;
use tokio_util::{sync::CancellationToken, task::TaskTracker};
+use rebaser_client::Config as RebaserClientConfig;
+
mod args;
type JobProcessor = sdf_server::NatsProcessor;
@@ -99,15 +101,21 @@ async fn async_main() -> Result<()> {
let pg_pool = Server::create_pg_pool(config.pg_pool()).await?;
+ let content_store_pg_pool = Server::create_pg_pool(config.content_store_pg_pool()).await?;
+
let veritech = Server::create_veritech_client(nats_conn.clone());
let symmetric_crypto_service =
Server::create_symmetric_crypto_service(config.symmetric_crypto_service()).await?;
- let pkgs_path: PathBuf = config.pkgs_path().try_into()?;
+ let pkgs_path: PathBuf = config.pkgs_path().into();
let module_index_url = config.module_index_url().to_string();
+ // TODO: accept command line arguments and or environment variables to configure the rebaser
+ // client
+ let rebaser_config = RebaserClientConfig::default();
+
let (ws_multiplexer, ws_multiplexer_client) =
Multiplexer::new(&nats_conn, WS_MULTIPLEXER_SUBJECT).await?;
let (crdt_multiplexer, crdt_multiplexer_client) =
@@ -122,6 +130,8 @@ async fn async_main() -> Result<()> {
Some(pkgs_path),
Some(module_index_url),
symmetric_crypto_service,
+ rebaser_config,
+ content_store_pg_pool,
);
if let MigrationMode::Run | MigrationMode::RunAndQuit = config.migration_mode() {
@@ -153,15 +163,15 @@ async fn async_main() -> Result<()> {
crdt_multiplexer,
crdt_multiplexer_client,
)?;
- let second_shutdown_broadcast_rx = initial_shutdown_broadcast_rx.resubscribe();
+ let _second_shutdown_broadcast_rx = initial_shutdown_broadcast_rx.resubscribe();
- Server::start_resource_refresh_scheduler(
- services_context.clone(),
- initial_shutdown_broadcast_rx,
- )
- .await;
+ // Server::start_resource_refresh_scheduler(
+ // services_context.clone(),
+ // initial_shutdown_broadcast_rx,
+ // )
+ // .await;
- Server::start_status_updater(services_context, second_shutdown_broadcast_rx).await?;
+ // Server::start_status_updater(services_context, second_shutdown_broadcast_rx).await?;
server.run().await?;
}
@@ -177,15 +187,15 @@ async fn async_main() -> Result<()> {
crdt_multiplexer_client,
)
.await?;
- let second_shutdown_broadcast_rx = initial_shutdown_broadcast_rx.resubscribe();
+ let _second_shutdown_broadcast_rx = initial_shutdown_broadcast_rx.resubscribe();
- Server::start_resource_refresh_scheduler(
- services_context.clone(),
- initial_shutdown_broadcast_rx,
- )
- .await;
+ // Server::start_resource_refresh_scheduler(
+ // services_context.clone(),
+ // initial_shutdown_broadcast_rx,
+ // )
+ // .await;
- Server::start_status_updater(services_context, second_shutdown_broadcast_rx).await?;
+ // Server::start_status_updater(services_context, second_shutdown_broadcast_rx).await?;
server.run().await?;
}
diff --git a/component/postgres/BUCK b/component/postgres/BUCK
index 67649016ad..387a8820d3 100644
--- a/component/postgres/BUCK
+++ b/component/postgres/BUCK
@@ -30,7 +30,7 @@ docker_image(
"--env",
"POSTGRES_DB=si",
"--env",
- "POSTGRES_MULTIPLE_DBS=si_test,si_test_dal,si_test_sdf_server,si_auth",
+ "POSTGRES_MULTIPLE_DBS=si_content_store,si_auth,si_test,si_test_content_store,si_test_dal,si_test_sdf_server",
"--publish",
"5432:5432",
],
diff --git a/dev/Tiltfile b/dev/Tiltfile
index 1c25eb85b8..995d9500ac 100644
--- a/dev/Tiltfile
+++ b/dev/Tiltfile
@@ -11,11 +11,11 @@ groups = {
"postgres-test",
],
"backend": [
- "council",
"pinga",
"veritech",
"sdf",
"module-index",
+ "rebaser",
],
"frontend": [
"web",
@@ -77,38 +77,38 @@ for service in compose_services:
links = []
dc_resource(service, links = links, labels = ["platform"])
-# Locally build and run `module-index`
-module_index_target = "//bin/module-index:module-index"
+# Locally build and run `rebaser-server`
+rebaser_target = "//bin/rebaser:rebaser"
local_resource(
- "module-index",
+ "rebaser",
labels = ["backend"],
- cmd = "buck2 build {}".format(module_index_target),
- serve_cmd = "buck2 run {}".format(module_index_target),
- serve_env = {"SI_FORCE_COLOR": "true"},
+ cmd = "buck2 build {}".format(rebaser_target),
+ serve_cmd = "buck2 run {}".format(rebaser_target),
allow_parallel = True,
- auto_init = False,
resource_deps = [
+ "nats",
"otelcol",
"postgres",
],
- deps = _buck2_dep_inputs(module_index_target),
- trigger_mode = trigger_mode,
+ deps = _buck2_dep_inputs(rebaser_target),
+ trigger_mode = trigger_mode
)
-# Locally build and run `council`
-council_target = "//bin/council:council"
+# Locally build and run `module-index`
+module_index_target = "//bin/module-index:module-index"
local_resource(
- "council",
+ "module-index",
labels = ["backend"],
- cmd = "buck2 build {}".format(council_target),
- serve_cmd = "buck2 run {}".format(council_target),
+ cmd = "buck2 build {}".format(module_index_target),
+ serve_cmd = "buck2 run {}".format(module_index_target),
serve_env = {"SI_FORCE_COLOR": "true"},
allow_parallel = True,
+ auto_init = False,
resource_deps = [
- "nats",
"otelcol",
+ "postgres",
],
- deps = _buck2_dep_inputs(council_target),
+ deps = _buck2_dep_inputs(module_index_target),
trigger_mode = trigger_mode,
)
@@ -122,7 +122,6 @@ local_resource(
serve_env = {"SI_FORCE_COLOR": "true"},
allow_parallel = True,
resource_deps = [
- "council",
"nats",
"otelcol",
"veritech",
@@ -166,6 +165,7 @@ local_resource(
"pinga",
"postgres",
"veritech",
+ "rebaser",
],
deps = _buck2_dep_inputs(sdf_target),
trigger_mode = trigger_mode,
diff --git a/dev/docker-compose.platform.yml b/dev/docker-compose.platform.yml
index a916104a7e..d2ff65dad3 100644
--- a/dev/docker-compose.platform.yml
+++ b/dev/docker-compose.platform.yml
@@ -9,7 +9,7 @@ services:
- "PGPASSWORD=bugbear"
- "POSTGRES_USER=si"
- "POSTGRES_DB=si"
- - "POSTGRES_MULTIPLE_DBS=si_auth,si_module_index"
+ - "POSTGRES_MULTIPLE_DBS=si_content_store,si_auth,si_module_index"
ports:
- "5432:5432"
@@ -20,7 +20,7 @@ services:
- "PGPASSWORD=bugbear"
- "POSTGRES_USER=si_test"
- "POSTGRES_DB=si_test"
- - "POSTGRES_MULTIPLE_DBS=si_test_dal,si_test_sdf_server"
+ - "POSTGRES_MULTIPLE_DBS=si_test_content_store,si_test_dal,si_test_sdf_server"
command:
- "-c"
- "fsync=off"
diff --git a/flake.nix b/flake.nix
index 2ed2d6b8be..e6be0c28f3 100644
--- a/flake.nix
+++ b/flake.nix
@@ -70,6 +70,7 @@
libiconv
darwin.apple_sdk.frameworks.Security
darwin.apple_sdk.frameworks.SystemConfiguration
+ darwin.apple_sdk.frameworks.CoreFoundation
];
# This isn't an exact science, but confirmed the system interpreter by
@@ -239,6 +240,8 @@
pinga = binDerivation {pkgName = "pinga";};
+ rebaser = binDerivation {pkgName = "rebaser";};
+
sdf = binDerivation {pkgName = "sdf";};
si = binDerivation {pkgName = "si";};
diff --git a/lib/content-store/BUCK b/lib/content-store/BUCK
new file mode 100644
index 0000000000..2642e94bc9
--- /dev/null
+++ b/lib/content-store/BUCK
@@ -0,0 +1,30 @@
+load("@prelude-si//:macros.bzl", "rust_library")
+
+rust_library(
+ name = "content-store",
+ deps = [
+ "//lib/si-cbor:si-cbor",
+ "//lib/si-data-pg:si-data-pg",
+ "//lib/telemetry-rs:telemetry",
+ "//third-party/rust:async-trait",
+ "//third-party/rust:blake3",
+ "//third-party/rust:bytes",
+ "//third-party/rust:chrono",
+ "//third-party/rust:color-eyre",
+ "//third-party/rust:postcard",
+ "//third-party/rust:postgres-types",
+ "//third-party/rust:refinery",
+ "//third-party/rust:remain",
+ "//third-party/rust:serde",
+ "//third-party/rust:serde_json",
+ "//third-party/rust:thiserror",
+ "//third-party/rust:uuid",
+ ],
+ srcs = glob([
+ "src/**/*.rs",
+ "src/store/pg/migrations/**/*.sql",
+ ]),
+ env = {
+ "CARGO_MANIFEST_DIR": ".",
+ },
+)
diff --git a/lib/content-store/Cargo.toml b/lib/content-store/Cargo.toml
new file mode 100644
index 0000000000..5949f1296b
--- /dev/null
+++ b/lib/content-store/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "content-store"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[dependencies]
+si-cbor = { path = "../../lib/si-cbor" }
+si-data-pg = { path = "../../lib/si-data-pg" }
+telemetry = { path = "../../lib/telemetry-rs" }
+
+async-trait = { workspace = true }
+blake3 = { workspace = true }
+bytes = { workspace = true }
+chrono = { workspace = true }
+color-eyre = { workspace = true }
+postcard = { workspace = true }
+postgres-types = { workspace = true }
+refinery = { workspace = true }
+remain = { workspace = true }
+serde = { workspace = true }
+serde_json = { workspace = true }
+thiserror = { workspace = true }
+uuid = { workspace = true }
diff --git a/lib/content-store/build.rs b/lib/content-store/build.rs
new file mode 100644
index 0000000000..d2e79ef4d0
--- /dev/null
+++ b/lib/content-store/build.rs
@@ -0,0 +1,13 @@
+use std::fs;
+
+fn main() -> Result<(), Box> {
+ println!("cargo:rerun-if-changed=src/store/pg/migrations");
+ for entry in fs::read_dir("./src/store/pg/migrations")? {
+ let entry = entry?;
+ let path = entry.path();
+ if path.is_file() {
+ println!("cargo:rerun-if-changed={}", path.display());
+ }
+ }
+ Ok(())
+}
diff --git a/lib/content-store/src/hash.rs b/lib/content-store/src/hash.rs
new file mode 100644
index 0000000000..06a55918b0
--- /dev/null
+++ b/lib/content-store/src/hash.rs
@@ -0,0 +1,154 @@
+use bytes::BytesMut;
+use std::{fmt, str::FromStr};
+
+use postgres_types::ToSql;
+use serde::{
+ de::{self, Visitor},
+ Deserialize, Serialize,
+};
+use serde_json::Value;
+
+use thiserror::Error;
+
+/// The [`blake3::Hash`] of a given set of contents.
+#[derive(Clone, Copy, Eq, Hash, PartialEq)]
+pub struct ContentHash(blake3::Hash);
+
+impl ContentHash {
+ /// Create a new [`ContentHash`] from a byte array.
+ #[must_use]
+ pub fn new(input: &[u8]) -> Self {
+ Self(blake3::hash(input))
+ }
+
+ /// Provide a [`hasher`](ContentHasher) to create [`hashes`](ContentHash).
+ pub fn hasher() -> ContentHasher {
+ ContentHasher::new()
+ }
+}
+
+impl From<&Value> for ContentHash {
+ fn from(value: &Value) -> Self {
+ let input = value.to_string();
+ Self::new(input.as_bytes())
+ }
+}
+
+impl From<&str> for ContentHash {
+ fn from(input: &str) -> Self {
+ Self::new(input.as_bytes())
+ }
+}
+
+impl Default for ContentHash {
+ fn default() -> Self {
+ Self::new("".as_bytes())
+ }
+}
+
+impl fmt::Debug for ContentHash {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ContentHash({})", self.0)
+ }
+}
+
+impl fmt::Display for ContentHash {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl Serialize for ContentHash {
+ fn serialize(&self, serializer: S) -> Result
+ where
+ S: serde::Serializer,
+ {
+ serializer.serialize_str(&self.to_string())
+ }
+}
+
+struct ContentHashVisitor;
+
+impl<'de> Visitor<'de> for ContentHashVisitor {
+ type Value = ContentHash;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a blake3 hash string")
+ }
+
+ fn visit_str(self, v: &str) -> Result
+ where
+ E: de::Error,
+ {
+ ContentHash::from_str(v).map_err(|e| E::custom(e.to_string()))
+ }
+}
+
+impl<'de> Deserialize<'de> for ContentHash {
+ fn deserialize(deserializer: D) -> Result
+ where
+ D: serde::Deserializer<'de>,
+ {
+ deserializer.deserialize_str(ContentHashVisitor)
+ }
+}
+
+#[derive(Debug, Error)]
+#[error("failed to parse hash hex string")]
+pub struct ContentHashParseError(#[from] blake3::HexError);
+
+impl FromStr for ContentHash {
+ type Err = ContentHashParseError;
+
+ fn from_str(s: &str) -> Result {
+ Ok(Self(blake3::Hash::from_str(s)?))
+ }
+}
+
+#[derive(Debug, Default)]
+pub struct ContentHasher(blake3::Hasher);
+
+impl ContentHasher {
+ pub fn new() -> Self {
+ ContentHasher(blake3::Hasher::new())
+ }
+
+ pub fn update(&mut self, input: &[u8]) {
+ self.0.update(input);
+ }
+
+ pub fn finalize(&self) -> ContentHash {
+ ContentHash(self.0.finalize())
+ }
+}
+
+impl ToSql for ContentHash {
+ fn to_sql(
+ &self,
+ ty: &postgres_types::Type,
+ out: &mut BytesMut,
+ ) -> Result>
+ where
+ Self: Sized,
+ {
+ let self_string = self.to_string();
+
+ self_string.to_sql(ty, out)
+ }
+
+ fn accepts(ty: &postgres_types::Type) -> bool
+ where
+ Self: Sized,
+ {
+ String::accepts(ty)
+ }
+
+ fn to_sql_checked(
+ &self,
+ ty: &postgres_types::Type,
+ out: &mut BytesMut,
+ ) -> Result> {
+ let self_string = self.to_string();
+ self_string.to_sql_checked(ty, out)
+ }
+}
diff --git a/lib/content-store/src/lib.rs b/lib/content-store/src/lib.rs
new file mode 100644
index 0000000000..c4af35d573
--- /dev/null
+++ b/lib/content-store/src/lib.rs
@@ -0,0 +1,36 @@
+//! This crate provides the ability to interface with content stores of varying kinds as well as
+//! the ability to generate hashes for hashable content blobs.
+
+#![warn(
+ missing_debug_implementations,
+ missing_docs,
+ unreachable_pub,
+ bad_style,
+ dead_code,
+ improper_ctypes,
+ non_shorthand_field_patterns,
+ no_mangle_generic_items,
+ overflowing_literals,
+ path_statements,
+ patterns_in_fns_without_body,
+ unconditional_recursion,
+ unused,
+ unused_allocation,
+ unused_comparisons,
+ unused_parens,
+ while_true,
+ clippy::missing_panics_doc
+)]
+
+mod hash;
+mod pair;
+mod store;
+mod value;
+
+pub use hash::ContentHash;
+pub use store::local::LocalStore;
+pub use store::pg::tools::PgStoreTools;
+pub use store::pg::PgStore;
+pub use store::Store;
+pub use store::{StoreError, StoreResult};
+pub use value::Value;
diff --git a/lib/content-store/src/pair.rs b/lib/content-store/src/pair.rs
new file mode 100644
index 0000000000..4f577732e1
--- /dev/null
+++ b/lib/content-store/src/pair.rs
@@ -0,0 +1,108 @@
+use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
+use si_data_pg::{PgError, PgPool, PgPoolError, PgRow};
+use std::str::FromStr;
+use telemetry::prelude::*;
+use thiserror::Error;
+
+use crate::hash::{ContentHash, ContentHashParseError};
+
+#[remain::sorted]
+#[derive(Error, Debug)]
+pub enum ContentPairError {
+ #[error("content hash parse error: {0}")]
+ ContentHashParse(#[from] ContentHashParseError),
+ #[error("pg error: {0}")]
+ Pg(#[from] PgError),
+ #[error("pg pool error: {0}")]
+ PgPool(#[from] PgPoolError),
+}
+
+pub(crate) type ContentPairResult = Result;
+
+#[derive(Debug, Serialize, Deserialize)]
+pub(crate) struct ContentPair {
+ key: String,
+ created_at: DateTime,
+ value: Vec,
+}
+
+impl TryFrom for ContentPair {
+ type Error = ContentPairError;
+
+ fn try_from(row: PgRow) -> Result {
+ Ok(Self {
+ key: row.try_get("key")?,
+ created_at: row.try_get("created_at")?,
+ value: row.try_get("value")?,
+ })
+ }
+}
+
+impl ContentPair {
+ #[instrument(name = "content_store.content_pair.new", level = "debug", skip_all)]
+ pub(crate) async fn new(
+ pg_pool: &PgPool,
+ key: ContentHash,
+ value: &[u8],
+ ) -> ContentPairResult<()> {
+ let client = pg_pool.get().await?;
+ client
+ .query(
+ "INSERT INTO content_pairs (key, value) VALUES ($1, $2) ON CONFLICT DO NOTHING",
+ &[&key.to_string(), &value],
+ )
+ .await?;
+ Ok(())
+ }
+
+ pub(crate) fn value(&self) -> &[u8] {
+ &self.value
+ }
+
+ pub(crate) fn key(&self) -> ContentPairResult {
+ Ok(ContentHash::from_str(self.key.as_str())?)
+ }
+
+ pub(crate) async fn find(
+ pg_pool: &PgPool,
+ key: &ContentHash,
+ ) -> ContentPairResult