Compare commits
	
		
			No commits in common. "ee1b12f85f8ab71c4e14afeda47a71ed14b4c6d4" and "eaed50280528a7354c19c32140faf2ad450d74fb" have entirely different histories.
		
	
	
		
			ee1b12f85f
			...
			eaed502805
		
	
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,5 +1,3 @@
 | 
				
			|||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/target
 | 
					/target
 | 
				
			||||||
secrets
 | 
					secrets
 | 
				
			||||||
tmp
 | 
					tmp
 | 
				
			||||||
 | 
				
			|||||||
@ -5,5 +5,4 @@ DB_NAMESPACE = "brain"
 | 
				
			|||||||
DB_NAME = "migration"
 | 
					DB_NAME = "migration"
 | 
				
			||||||
CERT_PATH = "./tmp/brain-crt.pem"
 | 
					CERT_PATH = "./tmp/brain-crt.pem"
 | 
				
			||||||
CERT_KEY_PATH = "./tmp/brain-key.pem"
 | 
					CERT_KEY_PATH = "./tmp/brain-key.pem"
 | 
				
			||||||
BRAIN_PUBLIC_ENDPOINT = "127.0.0.1:31337"
 | 
					 | 
				
			||||||
# ADMIN_PUB_KEYS = "admin_key01, admin_key02, admin_key03"
 | 
					# ADMIN_PUB_KEYS = "admin_key01, admin_key02, admin_key03"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										370
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										370
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -1,6 +1,5 @@
 | 
				
			|||||||
# This file is automatically @generated by Cargo.
 | 
					# This file is automatically @generated by Cargo.
 | 
				
			||||||
# It is not intended for manual editing.
 | 
					# It is not intended for manual editing.
 | 
				
			||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
version = 4
 | 
					version = 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -440,7 +439,7 @@ dependencies = [
 | 
				
			|||||||
 "miniz_oxide",
 | 
					 "miniz_oxide",
 | 
				
			||||||
 "object",
 | 
					 "object",
 | 
				
			||||||
 "rustc-demangle",
 | 
					 "rustc-demangle",
 | 
				
			||||||
 "windows-targets",
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -826,16 +825,6 @@ version = "0.3.1"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
 | 
					checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "core-foundation"
 | 
					 | 
				
			||||||
version = "0.9.4"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "core-foundation-sys",
 | 
					 | 
				
			||||||
 "libc",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "core-foundation-sys"
 | 
					name = "core-foundation-sys"
 | 
				
			||||||
version = "0.8.7"
 | 
					version = "0.8.7"
 | 
				
			||||||
@ -1011,7 +1000,7 @@ dependencies = [
 | 
				
			|||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "detee-shared"
 | 
					name = "detee-shared"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
source = "git+ssh://git@gitea.detee.cloud/testnet/proto?branch=surreal_brain_app#0b195b4589e4ec689af7ddca27dc051716ecee78"
 | 
					source = "git+ssh://git@gitea.detee.cloud/testnet/proto?branch=surreal_brain_app#005677153b3fcd3251b64111a736c806106fdc04"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "bincode 2.0.1",
 | 
					 "bincode 2.0.1",
 | 
				
			||||||
 "prost",
 | 
					 "prost",
 | 
				
			||||||
@ -1268,21 +1257,6 @@ version = "0.1.5"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
 | 
					checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "foreign-types"
 | 
					 | 
				
			||||||
version = "0.3.2"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "foreign-types-shared",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "foreign-types-shared"
 | 
					 | 
				
			||||||
version = "0.1.1"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "form_urlencoded"
 | 
					name = "form_urlencoded"
 | 
				
			||||||
version = "1.2.1"
 | 
					version = "1.2.1"
 | 
				
			||||||
@ -1723,7 +1697,7 @@ dependencies = [
 | 
				
			|||||||
 "tokio",
 | 
					 "tokio",
 | 
				
			||||||
 "tokio-rustls",
 | 
					 "tokio-rustls",
 | 
				
			||||||
 "tower-service",
 | 
					 "tower-service",
 | 
				
			||||||
 "webpki-roots 0.26.8",
 | 
					 "webpki-roots",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -1739,46 +1713,24 @@ dependencies = [
 | 
				
			|||||||
 "tower-service",
 | 
					 "tower-service",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "hyper-tls"
 | 
					 | 
				
			||||||
version = "0.6.0"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "bytes",
 | 
					 | 
				
			||||||
 "http-body-util",
 | 
					 | 
				
			||||||
 "hyper",
 | 
					 | 
				
			||||||
 "hyper-util",
 | 
					 | 
				
			||||||
 "native-tls",
 | 
					 | 
				
			||||||
 "tokio",
 | 
					 | 
				
			||||||
 "tokio-native-tls",
 | 
					 | 
				
			||||||
 "tower-service",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "hyper-util"
 | 
					name = "hyper-util"
 | 
				
			||||||
version = "0.1.14"
 | 
					version = "0.1.11"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
 | 
					checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "base64 0.22.1",
 | 
					 | 
				
			||||||
 "bytes",
 | 
					 "bytes",
 | 
				
			||||||
 "futures-channel",
 | 
					 "futures-channel",
 | 
				
			||||||
 "futures-core",
 | 
					 | 
				
			||||||
 "futures-util",
 | 
					 "futures-util",
 | 
				
			||||||
 "http",
 | 
					 "http",
 | 
				
			||||||
 "http-body",
 | 
					 "http-body",
 | 
				
			||||||
 "hyper",
 | 
					 "hyper",
 | 
				
			||||||
 "ipnet",
 | 
					 | 
				
			||||||
 "libc",
 | 
					 "libc",
 | 
				
			||||||
 "percent-encoding",
 | 
					 | 
				
			||||||
 "pin-project-lite",
 | 
					 "pin-project-lite",
 | 
				
			||||||
 "socket2",
 | 
					 "socket2",
 | 
				
			||||||
 "system-configuration",
 | 
					 | 
				
			||||||
 "tokio",
 | 
					 "tokio",
 | 
				
			||||||
 "tower-service",
 | 
					 "tower-service",
 | 
				
			||||||
 "tracing",
 | 
					 "tracing",
 | 
				
			||||||
 "windows-registry",
 | 
					 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -1987,16 +1939,6 @@ version = "2.11.0"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
 | 
					checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "iri-string"
 | 
					 | 
				
			||||||
version = "0.7.8"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "memchr",
 | 
					 | 
				
			||||||
 "serde",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "is_terminal_polyfill"
 | 
					name = "is_terminal_polyfill"
 | 
				
			||||||
version = "1.70.1"
 | 
					version = "1.70.1"
 | 
				
			||||||
@ -2362,23 +2304,6 @@ dependencies = [
 | 
				
			|||||||
 "rand 0.8.5",
 | 
					 "rand 0.8.5",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "native-tls"
 | 
					 | 
				
			||||||
version = "0.2.14"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "libc",
 | 
					 | 
				
			||||||
 "log",
 | 
					 | 
				
			||||||
 "openssl",
 | 
					 | 
				
			||||||
 "openssl-probe",
 | 
					 | 
				
			||||||
 "openssl-sys",
 | 
					 | 
				
			||||||
 "schannel",
 | 
					 | 
				
			||||||
 "security-framework",
 | 
					 | 
				
			||||||
 "security-framework-sys",
 | 
					 | 
				
			||||||
 "tempfile",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "ndarray"
 | 
					name = "ndarray"
 | 
				
			||||||
version = "0.15.6"
 | 
					version = "0.15.6"
 | 
				
			||||||
@ -2531,50 +2456,6 @@ version = "1.21.3"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 | 
					checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "openssl"
 | 
					 | 
				
			||||||
version = "0.10.73"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "bitflags",
 | 
					 | 
				
			||||||
 "cfg-if",
 | 
					 | 
				
			||||||
 "foreign-types",
 | 
					 | 
				
			||||||
 "libc",
 | 
					 | 
				
			||||||
 "once_cell",
 | 
					 | 
				
			||||||
 "openssl-macros",
 | 
					 | 
				
			||||||
 "openssl-sys",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "openssl-macros"
 | 
					 | 
				
			||||||
version = "0.1.1"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "proc-macro2",
 | 
					 | 
				
			||||||
 "quote",
 | 
					 | 
				
			||||||
 "syn 2.0.100",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "openssl-probe"
 | 
					 | 
				
			||||||
version = "0.1.6"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "openssl-sys"
 | 
					 | 
				
			||||||
version = "0.9.109"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "cc",
 | 
					 | 
				
			||||||
 "libc",
 | 
					 | 
				
			||||||
 "pkg-config",
 | 
					 | 
				
			||||||
 "vcpkg",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "parking"
 | 
					name = "parking"
 | 
				
			||||||
version = "2.2.1"
 | 
					version = "2.2.1"
 | 
				
			||||||
@ -2601,7 +2482,7 @@ dependencies = [
 | 
				
			|||||||
 "libc",
 | 
					 "libc",
 | 
				
			||||||
 "redox_syscall",
 | 
					 "redox_syscall",
 | 
				
			||||||
 "smallvec",
 | 
					 "smallvec",
 | 
				
			||||||
 "windows-targets",
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -2875,7 +2756,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			|||||||
checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
 | 
					checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "heck 0.5.0",
 | 
					 "heck 0.5.0",
 | 
				
			||||||
 "itertools 0.14.0",
 | 
					 "itertools 0.11.0",
 | 
				
			||||||
 "log",
 | 
					 "log",
 | 
				
			||||||
 "multimap",
 | 
					 "multimap",
 | 
				
			||||||
 "once_cell",
 | 
					 "once_cell",
 | 
				
			||||||
@ -2895,7 +2776,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			|||||||
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
 | 
					checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "anyhow",
 | 
					 "anyhow",
 | 
				
			||||||
 "itertools 0.14.0",
 | 
					 "itertools 0.11.0",
 | 
				
			||||||
 "proc-macro2",
 | 
					 "proc-macro2",
 | 
				
			||||||
 "quote",
 | 
					 "quote",
 | 
				
			||||||
 "syn 2.0.100",
 | 
					 "syn 2.0.100",
 | 
				
			||||||
@ -3214,53 +3095,48 @@ dependencies = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "reqwest"
 | 
					name = "reqwest"
 | 
				
			||||||
version = "0.12.19"
 | 
					version = "0.12.15"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119"
 | 
					checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "base64 0.22.1",
 | 
					 "base64 0.22.1",
 | 
				
			||||||
 "bytes",
 | 
					 "bytes",
 | 
				
			||||||
 "encoding_rs",
 | 
					 | 
				
			||||||
 "futures-channel",
 | 
					 | 
				
			||||||
 "futures-core",
 | 
					 "futures-core",
 | 
				
			||||||
 "futures-util",
 | 
					 "futures-util",
 | 
				
			||||||
 "h2",
 | 
					 | 
				
			||||||
 "http",
 | 
					 "http",
 | 
				
			||||||
 "http-body",
 | 
					 "http-body",
 | 
				
			||||||
 "http-body-util",
 | 
					 "http-body-util",
 | 
				
			||||||
 "hyper",
 | 
					 "hyper",
 | 
				
			||||||
 "hyper-rustls",
 | 
					 "hyper-rustls",
 | 
				
			||||||
 "hyper-tls",
 | 
					 | 
				
			||||||
 "hyper-util",
 | 
					 "hyper-util",
 | 
				
			||||||
 "ipnet",
 | 
					 "ipnet",
 | 
				
			||||||
 "js-sys",
 | 
					 "js-sys",
 | 
				
			||||||
 "log",
 | 
					 "log",
 | 
				
			||||||
 "mime",
 | 
					 "mime",
 | 
				
			||||||
 "mime_guess",
 | 
					 "mime_guess",
 | 
				
			||||||
 "native-tls",
 | 
					 | 
				
			||||||
 "once_cell",
 | 
					 "once_cell",
 | 
				
			||||||
 "percent-encoding",
 | 
					 "percent-encoding",
 | 
				
			||||||
 "pin-project-lite",
 | 
					 "pin-project-lite",
 | 
				
			||||||
 "quinn",
 | 
					 "quinn",
 | 
				
			||||||
 "rustls",
 | 
					 "rustls",
 | 
				
			||||||
 | 
					 "rustls-pemfile",
 | 
				
			||||||
 "rustls-pki-types",
 | 
					 "rustls-pki-types",
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "serde_json",
 | 
					 "serde_json",
 | 
				
			||||||
 "serde_urlencoded",
 | 
					 "serde_urlencoded",
 | 
				
			||||||
 "sync_wrapper",
 | 
					 "sync_wrapper",
 | 
				
			||||||
 "tokio",
 | 
					 "tokio",
 | 
				
			||||||
 "tokio-native-tls",
 | 
					 | 
				
			||||||
 "tokio-rustls",
 | 
					 "tokio-rustls",
 | 
				
			||||||
 "tokio-util",
 | 
					 "tokio-util",
 | 
				
			||||||
 "tower 0.5.2",
 | 
					 "tower 0.5.2",
 | 
				
			||||||
 "tower-http",
 | 
					 | 
				
			||||||
 "tower-service",
 | 
					 "tower-service",
 | 
				
			||||||
 "url",
 | 
					 "url",
 | 
				
			||||||
 "wasm-bindgen",
 | 
					 "wasm-bindgen",
 | 
				
			||||||
 "wasm-bindgen-futures",
 | 
					 "wasm-bindgen-futures",
 | 
				
			||||||
 "wasm-streams",
 | 
					 "wasm-streams",
 | 
				
			||||||
 "web-sys",
 | 
					 "web-sys",
 | 
				
			||||||
 "webpki-roots 1.0.0",
 | 
					 "webpki-roots",
 | 
				
			||||||
 | 
					 "windows-registry",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -3524,15 +3400,6 @@ dependencies = [
 | 
				
			|||||||
 "winapi-util",
 | 
					 "winapi-util",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "schannel"
 | 
					 | 
				
			||||||
version = "0.1.27"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "windows-sys 0.59.0",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "scopeguard"
 | 
					name = "scopeguard"
 | 
				
			||||||
version = "1.2.0"
 | 
					version = "1.2.0"
 | 
				
			||||||
@ -3557,29 +3424,6 @@ version = "4.1.0"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
 | 
					checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "security-framework"
 | 
					 | 
				
			||||||
version = "2.11.1"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "bitflags",
 | 
					 | 
				
			||||||
 "core-foundation",
 | 
					 | 
				
			||||||
 "core-foundation-sys",
 | 
					 | 
				
			||||||
 "libc",
 | 
					 | 
				
			||||||
 "security-framework-sys",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "security-framework-sys"
 | 
					 | 
				
			||||||
version = "2.14.0"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "core-foundation-sys",
 | 
					 | 
				
			||||||
 "libc",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "semver"
 | 
					name = "semver"
 | 
				
			||||||
version = "1.0.26"
 | 
					version = "1.0.26"
 | 
				
			||||||
@ -3958,7 +3802,6 @@ dependencies = [
 | 
				
			|||||||
 "log",
 | 
					 "log",
 | 
				
			||||||
 "nanoid",
 | 
					 "nanoid",
 | 
				
			||||||
 "rand 0.8.5",
 | 
					 "rand 0.8.5",
 | 
				
			||||||
 "reqwest",
 | 
					 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "serde_json",
 | 
					 "serde_json",
 | 
				
			||||||
 "serde_yaml",
 | 
					 "serde_yaml",
 | 
				
			||||||
@ -4154,27 +3997,6 @@ dependencies = [
 | 
				
			|||||||
 "windows",
 | 
					 "windows",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "system-configuration"
 | 
					 | 
				
			||||||
version = "0.6.1"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "bitflags",
 | 
					 | 
				
			||||||
 "core-foundation",
 | 
					 | 
				
			||||||
 "system-configuration-sys",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "system-configuration-sys"
 | 
					 | 
				
			||||||
version = "0.6.0"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "core-foundation-sys",
 | 
					 | 
				
			||||||
 "libc",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "tap"
 | 
					name = "tap"
 | 
				
			||||||
version = "1.0.1"
 | 
					version = "1.0.1"
 | 
				
			||||||
@ -4369,16 +4191,6 @@ dependencies = [
 | 
				
			|||||||
 "syn 2.0.100",
 | 
					 "syn 2.0.100",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "tokio-native-tls"
 | 
					 | 
				
			||||||
version = "0.3.1"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "native-tls",
 | 
					 | 
				
			||||||
 "tokio",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "tokio-rustls"
 | 
					name = "tokio-rustls"
 | 
				
			||||||
version = "0.26.2"
 | 
					version = "0.26.2"
 | 
				
			||||||
@ -4413,7 +4225,7 @@ dependencies = [
 | 
				
			|||||||
 "tokio",
 | 
					 "tokio",
 | 
				
			||||||
 "tokio-rustls",
 | 
					 "tokio-rustls",
 | 
				
			||||||
 "tungstenite",
 | 
					 "tungstenite",
 | 
				
			||||||
 "webpki-roots 0.26.8",
 | 
					 "webpki-roots",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -4528,24 +4340,6 @@ dependencies = [
 | 
				
			|||||||
 "tower-service",
 | 
					 "tower-service",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "tower-http"
 | 
					 | 
				
			||||||
version = "0.6.6"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "bitflags",
 | 
					 | 
				
			||||||
 "bytes",
 | 
					 | 
				
			||||||
 "futures-util",
 | 
					 | 
				
			||||||
 "http",
 | 
					 | 
				
			||||||
 "http-body",
 | 
					 | 
				
			||||||
 "iri-string",
 | 
					 | 
				
			||||||
 "pin-project-lite",
 | 
					 | 
				
			||||||
 "tower 0.5.2",
 | 
					 | 
				
			||||||
 "tower-layer",
 | 
					 | 
				
			||||||
 "tower-service",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "tower-layer"
 | 
					name = "tower-layer"
 | 
				
			||||||
version = "0.3.3"
 | 
					version = "0.3.3"
 | 
				
			||||||
@ -4776,12 +4570,6 @@ version = "0.8.1"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "87782b74f898179396e93c0efabb38de0d58d50bbd47eae00c71b3a1144dbbae"
 | 
					checksum = "87782b74f898179396e93c0efabb38de0d58d50bbd47eae00c71b3a1144dbbae"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "vcpkg"
 | 
					 | 
				
			||||||
version = "0.2.15"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "version_check"
 | 
					name = "version_check"
 | 
				
			||||||
version = "0.9.5"
 | 
					version = "0.9.5"
 | 
				
			||||||
@ -4954,15 +4742,6 @@ dependencies = [
 | 
				
			|||||||
 "rustls-pki-types",
 | 
					 "rustls-pki-types",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					 | 
				
			||||||
name = "webpki-roots"
 | 
					 | 
				
			||||||
version = "1.0.0"
 | 
					 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					 | 
				
			||||||
checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb"
 | 
					 | 
				
			||||||
dependencies = [
 | 
					 | 
				
			||||||
 "rustls-pki-types",
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "winapi"
 | 
					name = "winapi"
 | 
				
			||||||
version = "0.3.9"
 | 
					version = "0.3.9"
 | 
				
			||||||
@ -5001,7 +4780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			|||||||
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
 | 
					checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "windows-core 0.57.0",
 | 
					 "windows-core 0.57.0",
 | 
				
			||||||
 "windows-targets",
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -5013,7 +4792,7 @@ dependencies = [
 | 
				
			|||||||
 "windows-implement 0.57.0",
 | 
					 "windows-implement 0.57.0",
 | 
				
			||||||
 "windows-interface 0.57.0",
 | 
					 "windows-interface 0.57.0",
 | 
				
			||||||
 "windows-result 0.1.2",
 | 
					 "windows-result 0.1.2",
 | 
				
			||||||
 "windows-targets",
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -5025,8 +4804,8 @@ dependencies = [
 | 
				
			|||||||
 "windows-implement 0.60.0",
 | 
					 "windows-implement 0.60.0",
 | 
				
			||||||
 "windows-interface 0.59.1",
 | 
					 "windows-interface 0.59.1",
 | 
				
			||||||
 "windows-link",
 | 
					 "windows-link",
 | 
				
			||||||
 "windows-result 0.3.4",
 | 
					 "windows-result 0.3.2",
 | 
				
			||||||
 "windows-strings",
 | 
					 "windows-strings 0.4.0",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -5081,13 +4860,13 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows-registry"
 | 
					name = "windows-registry"
 | 
				
			||||||
version = "0.5.2"
 | 
					version = "0.4.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820"
 | 
					checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "windows-link",
 | 
					 "windows-result 0.3.2",
 | 
				
			||||||
 "windows-result 0.3.4",
 | 
					 "windows-strings 0.3.1",
 | 
				
			||||||
 "windows-strings",
 | 
					 "windows-targets 0.53.0",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -5096,23 +4875,32 @@ version = "0.1.2"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
 | 
					checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "windows-targets",
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows-result"
 | 
					name = "windows-result"
 | 
				
			||||||
version = "0.3.4"
 | 
					version = "0.3.2"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
 | 
					checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "windows-link",
 | 
					 "windows-link",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows-strings"
 | 
					name = "windows-strings"
 | 
				
			||||||
version = "0.4.2"
 | 
					version = "0.3.1"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
 | 
					checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "windows-link",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows-strings"
 | 
				
			||||||
 | 
					version = "0.4.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "windows-link",
 | 
					 "windows-link",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
@ -5123,7 +4911,7 @@ version = "0.52.0"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 | 
					checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "windows-targets",
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -5132,7 +4920,7 @@ version = "0.59.0"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 | 
					checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "windows-targets",
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -5141,14 +4929,30 @@ version = "0.52.6"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 | 
					checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "windows_aarch64_gnullvm",
 | 
					 "windows_aarch64_gnullvm 0.52.6",
 | 
				
			||||||
 "windows_aarch64_msvc",
 | 
					 "windows_aarch64_msvc 0.52.6",
 | 
				
			||||||
 "windows_i686_gnu",
 | 
					 "windows_i686_gnu 0.52.6",
 | 
				
			||||||
 "windows_i686_gnullvm",
 | 
					 "windows_i686_gnullvm 0.52.6",
 | 
				
			||||||
 "windows_i686_msvc",
 | 
					 "windows_i686_msvc 0.52.6",
 | 
				
			||||||
 "windows_x86_64_gnu",
 | 
					 "windows_x86_64_gnu 0.52.6",
 | 
				
			||||||
 "windows_x86_64_gnullvm",
 | 
					 "windows_x86_64_gnullvm 0.52.6",
 | 
				
			||||||
 "windows_x86_64_msvc",
 | 
					 "windows_x86_64_msvc 0.52.6",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows-targets"
 | 
				
			||||||
 | 
					version = "0.53.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "windows_aarch64_gnullvm 0.53.0",
 | 
				
			||||||
 | 
					 "windows_aarch64_msvc 0.53.0",
 | 
				
			||||||
 | 
					 "windows_i686_gnu 0.53.0",
 | 
				
			||||||
 | 
					 "windows_i686_gnullvm 0.53.0",
 | 
				
			||||||
 | 
					 "windows_i686_msvc 0.53.0",
 | 
				
			||||||
 | 
					 "windows_x86_64_gnu 0.53.0",
 | 
				
			||||||
 | 
					 "windows_x86_64_gnullvm 0.53.0",
 | 
				
			||||||
 | 
					 "windows_x86_64_msvc 0.53.0",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -5157,48 +4961,96 @@ version = "0.52.6"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 | 
					checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_aarch64_gnullvm"
 | 
				
			||||||
 | 
					version = "0.53.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows_aarch64_msvc"
 | 
					name = "windows_aarch64_msvc"
 | 
				
			||||||
version = "0.52.6"
 | 
					version = "0.52.6"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 | 
					checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_aarch64_msvc"
 | 
				
			||||||
 | 
					version = "0.53.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows_i686_gnu"
 | 
					name = "windows_i686_gnu"
 | 
				
			||||||
version = "0.52.6"
 | 
					version = "0.52.6"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 | 
					checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_i686_gnu"
 | 
				
			||||||
 | 
					version = "0.53.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows_i686_gnullvm"
 | 
					name = "windows_i686_gnullvm"
 | 
				
			||||||
version = "0.52.6"
 | 
					version = "0.52.6"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 | 
					checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_i686_gnullvm"
 | 
				
			||||||
 | 
					version = "0.53.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows_i686_msvc"
 | 
					name = "windows_i686_msvc"
 | 
				
			||||||
version = "0.52.6"
 | 
					version = "0.52.6"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 | 
					checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_i686_msvc"
 | 
				
			||||||
 | 
					version = "0.53.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows_x86_64_gnu"
 | 
					name = "windows_x86_64_gnu"
 | 
				
			||||||
version = "0.52.6"
 | 
					version = "0.52.6"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 | 
					checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_x86_64_gnu"
 | 
				
			||||||
 | 
					version = "0.53.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows_x86_64_gnullvm"
 | 
					name = "windows_x86_64_gnullvm"
 | 
				
			||||||
version = "0.52.6"
 | 
					version = "0.52.6"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 | 
					checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_x86_64_gnullvm"
 | 
				
			||||||
 | 
					version = "0.53.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows_x86_64_msvc"
 | 
					name = "windows_x86_64_msvc"
 | 
				
			||||||
version = "0.52.6"
 | 
					version = "0.52.6"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 | 
					checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows_x86_64_msvc"
 | 
				
			||||||
 | 
					version = "0.53.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "winnow"
 | 
					name = "winnow"
 | 
				
			||||||
version = "0.7.6"
 | 
					version = "0.7.6"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[package]
 | 
					[package]
 | 
				
			||||||
name = "surreal-brain"
 | 
					name = "surreal-brain"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
@ -40,5 +38,4 @@ ed25519-dalek = { version = "2.1.1", features = ["rand_core"] }
 | 
				
			|||||||
hyper-util = "0.1.11"
 | 
					hyper-util = "0.1.11"
 | 
				
			||||||
itertools = "0.14.0"
 | 
					itertools = "0.14.0"
 | 
				
			||||||
rand = "0.8"
 | 
					rand = "0.8"
 | 
				
			||||||
reqwest = { version = "0.12.19", features = ["blocking"] }
 | 
					 | 
				
			||||||
tower = "0.5.2"
 | 
					tower = "0.5.2"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										474
									
								
								LICENSE
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										474
									
								
								LICENSE
									
									
									
									
									
								
							@ -1,202 +1,338 @@
 | 
				
			|||||||
 | 
					                    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
 | 
					                       Version 2, June 1991
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                 Apache License
 | 
					 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 | 
				
			||||||
                           Version 2.0, January 2004
 | 
					 <https://fsf.org/>
 | 
				
			||||||
                        http://www.apache.org/licenses/
 | 
					 Everyone is permitted to copy and distribute verbatim copies
 | 
				
			||||||
 | 
					 of this license document, but changing it is not allowed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
					                            Preamble
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   1. Definitions.
 | 
					  The licenses for most software are designed to take away your
 | 
				
			||||||
 | 
					freedom to share and change it.  By contrast, the GNU General Public
 | 
				
			||||||
 | 
					License is intended to guarantee your freedom to share and change free
 | 
				
			||||||
 | 
					software--to make sure the software is free for all its users.  This
 | 
				
			||||||
 | 
					General Public License applies to most of the Free Software
 | 
				
			||||||
 | 
					Foundation's software and to any other program whose authors commit to
 | 
				
			||||||
 | 
					using it.  (Some other Free Software Foundation software is covered by
 | 
				
			||||||
 | 
					the GNU Lesser General Public License instead.)  You can apply it to
 | 
				
			||||||
 | 
					your programs, too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
					  When we speak of free software, we are referring to freedom, not
 | 
				
			||||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
					price.  Our General Public Licenses are designed to make sure that you
 | 
				
			||||||
 | 
					have the freedom to distribute copies of free software (and charge for
 | 
				
			||||||
 | 
					this service if you wish), that you receive source code or can get it
 | 
				
			||||||
 | 
					if you want it, that you can change the software or use pieces of it
 | 
				
			||||||
 | 
					in new free programs; and that you know you can do these things.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
					  To protect your rights, we need to make restrictions that forbid
 | 
				
			||||||
      the copyright owner that is granting the License.
 | 
					anyone to deny you these rights or to ask you to surrender the rights.
 | 
				
			||||||
 | 
					These restrictions translate to certain responsibilities for you if you
 | 
				
			||||||
 | 
					distribute copies of the software, or if you modify it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
					  For example, if you distribute copies of such a program, whether
 | 
				
			||||||
      other entities that control, are controlled by, or are under common
 | 
					gratis or for a fee, you must give the recipients all the rights that
 | 
				
			||||||
      control with that entity. For the purposes of this definition,
 | 
					you have.  You must make sure that they, too, receive or can get the
 | 
				
			||||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
					source code.  And you must show them these terms so they know their
 | 
				
			||||||
      direction or management of such entity, whether by contract or
 | 
					rights.
 | 
				
			||||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
					 | 
				
			||||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
					  We protect your rights with two steps: (1) copyright the software, and
 | 
				
			||||||
      exercising permissions granted by this License.
 | 
					(2) offer you this license which gives you legal permission to copy,
 | 
				
			||||||
 | 
					distribute and/or modify the software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "Source" form shall mean the preferred form for making modifications,
 | 
					  Also, for each author's protection and ours, we want to make certain
 | 
				
			||||||
      including but not limited to software source code, documentation
 | 
					that everyone understands that there is no warranty for this free
 | 
				
			||||||
      source, and configuration files.
 | 
					software.  If the software is modified by someone else and passed on, we
 | 
				
			||||||
 | 
					want its recipients to know that what they have is not the original, so
 | 
				
			||||||
 | 
					that any problems introduced by others will not reflect on the original
 | 
				
			||||||
 | 
					authors' reputations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "Object" form shall mean any form resulting from mechanical
 | 
					  Finally, any free program is threatened constantly by software
 | 
				
			||||||
      transformation or translation of a Source form, including but
 | 
					patents.  We wish to avoid the danger that redistributors of a free
 | 
				
			||||||
      not limited to compiled object code, generated documentation,
 | 
					program will individually obtain patent licenses, in effect making the
 | 
				
			||||||
      and conversions to other media types.
 | 
					program proprietary.  To prevent this, we have made it clear that any
 | 
				
			||||||
 | 
					patent must be licensed for everyone's free use or not licensed at all.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
					  The precise terms and conditions for copying, distribution and
 | 
				
			||||||
      Object form, made available under the License, as indicated by a
 | 
					modification follow.
 | 
				
			||||||
      copyright notice that is included in or attached to the work
 | 
					 | 
				
			||||||
      (an example is provided in the Appendix below).
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
					                    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
      form, that is based on (or derived from) the Work and for which the
 | 
					   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 | 
				
			||||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
					 | 
				
			||||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
					 | 
				
			||||||
      of this License, Derivative Works shall not include works that remain
 | 
					 | 
				
			||||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
					 | 
				
			||||||
      the Work and Derivative Works thereof.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "Contribution" shall mean any work of authorship, including
 | 
					  0. This License applies to any program or other work which contains
 | 
				
			||||||
      the original version of the Work and any modifications or additions
 | 
					a notice placed by the copyright holder saying it may be distributed
 | 
				
			||||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
					under the terms of this General Public License.  The "Program", below,
 | 
				
			||||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
					refers to any such program or work, and a "work based on the Program"
 | 
				
			||||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
					means either the Program or any derivative work under copyright law:
 | 
				
			||||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
					that is to say, a work containing the Program or a portion of it,
 | 
				
			||||||
      means any form of electronic, verbal, or written communication sent
 | 
					either verbatim or with modifications and/or translated into another
 | 
				
			||||||
      to the Licensor or its representatives, including but not limited to
 | 
					language.  (Hereinafter, translation is included without limitation in
 | 
				
			||||||
      communication on electronic mailing lists, source code control systems,
 | 
					the term "modification".)  Each licensee is addressed as "you".
 | 
				
			||||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
					 | 
				
			||||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
					 | 
				
			||||||
      excluding communication that is conspicuously marked or otherwise
 | 
					 | 
				
			||||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
					Activities other than copying, distribution and modification are not
 | 
				
			||||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
					covered by this License; they are outside its scope.  The act of
 | 
				
			||||||
      subsequently incorporated within the Work.
 | 
					running the Program is not restricted, and the output from the Program
 | 
				
			||||||
 | 
					is covered only if its contents constitute a work based on the
 | 
				
			||||||
 | 
					Program (independent of having been made by running the Program).
 | 
				
			||||||
 | 
					Whether that is true depends on what the Program does.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
					  1. You may copy and distribute verbatim copies of the Program's
 | 
				
			||||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
					source code as you receive it, in any medium, provided that you
 | 
				
			||||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
					conspicuously and appropriately publish on each copy an appropriate
 | 
				
			||||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
					copyright notice and disclaimer of warranty; keep intact all the
 | 
				
			||||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
					notices that refer to this License and to the absence of any warranty;
 | 
				
			||||||
      Work and such Derivative Works in Source or Object form.
 | 
					and give any other recipients of the Program a copy of this License
 | 
				
			||||||
 | 
					along with the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
					You may charge a fee for the physical act of transferring a copy, and
 | 
				
			||||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
					you may at your option offer warranty protection in exchange for a fee.
 | 
				
			||||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
					 | 
				
			||||||
      (except as stated in this section) patent license to make, have made,
 | 
					 | 
				
			||||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
					 | 
				
			||||||
      where such license applies only to those patent claims licensable
 | 
					 | 
				
			||||||
      by such Contributor that are necessarily infringed by their
 | 
					 | 
				
			||||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
					 | 
				
			||||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
					 | 
				
			||||||
      institute patent litigation against any entity (including a
 | 
					 | 
				
			||||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
					 | 
				
			||||||
      or a Contribution incorporated within the Work constitutes direct
 | 
					 | 
				
			||||||
      or contributory patent infringement, then any patent licenses
 | 
					 | 
				
			||||||
      granted to You under this License for that Work shall terminate
 | 
					 | 
				
			||||||
      as of the date such litigation is filed.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
					  2. You may modify your copy or copies of the Program or any portion
 | 
				
			||||||
      Work or Derivative Works thereof in any medium, with or without
 | 
					of it, thus forming a work based on the Program, and copy and
 | 
				
			||||||
      modifications, and in Source or Object form, provided that You
 | 
					distribute such modifications or work under the terms of Section 1
 | 
				
			||||||
      meet the following conditions:
 | 
					above, provided that you also meet all of these conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      (a) You must give any other recipients of the Work or
 | 
					    a) You must cause the modified files to carry prominent notices
 | 
				
			||||||
          Derivative Works a copy of this License; and
 | 
					    stating that you changed the files and the date of any change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      (b) You must cause any modified files to carry prominent notices
 | 
					    b) You must cause any work that you distribute or publish, that in
 | 
				
			||||||
          stating that You changed the files; and
 | 
					    whole or in part contains or is derived from the Program or any
 | 
				
			||||||
 | 
					    part thereof, to be licensed as a whole at no charge to all third
 | 
				
			||||||
 | 
					    parties under the terms of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
					    c) If the modified program normally reads commands interactively
 | 
				
			||||||
          that You distribute, all copyright, patent, trademark, and
 | 
					    when run, you must cause it, when started running for such
 | 
				
			||||||
          attribution notices from the Source form of the Work,
 | 
					    interactive use in the most ordinary way, to print or display an
 | 
				
			||||||
          excluding those notices that do not pertain to any part of
 | 
					    announcement including an appropriate copyright notice and a
 | 
				
			||||||
          the Derivative Works; and
 | 
					    notice that there is no warranty (or else, saying that you provide
 | 
				
			||||||
 | 
					    a warranty) and that users may redistribute the program under
 | 
				
			||||||
 | 
					    these conditions, and telling the user how to view a copy of this
 | 
				
			||||||
 | 
					    License.  (Exception: if the Program itself is interactive but
 | 
				
			||||||
 | 
					    does not normally print such an announcement, your work based on
 | 
				
			||||||
 | 
					    the Program is not required to print an announcement.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
					These requirements apply to the modified work as a whole.  If
 | 
				
			||||||
          distribution, then any Derivative Works that You distribute must
 | 
					identifiable sections of that work are not derived from the Program,
 | 
				
			||||||
          include a readable copy of the attribution notices contained
 | 
					and can be reasonably considered independent and separate works in
 | 
				
			||||||
          within such NOTICE file, excluding those notices that do not
 | 
					themselves, then this License, and its terms, do not apply to those
 | 
				
			||||||
          pertain to any part of the Derivative Works, in at least one
 | 
					sections when you distribute them as separate works.  But when you
 | 
				
			||||||
          of the following places: within a NOTICE text file distributed
 | 
					distribute the same sections as part of a whole which is a work based
 | 
				
			||||||
          as part of the Derivative Works; within the Source form or
 | 
					on the Program, the distribution of the whole must be on the terms of
 | 
				
			||||||
          documentation, if provided along with the Derivative Works; or,
 | 
					this License, whose permissions for other licensees extend to the
 | 
				
			||||||
          within a display generated by the Derivative Works, if and
 | 
					entire whole, and thus to each and every part regardless of who wrote it.
 | 
				
			||||||
          wherever such third-party notices normally appear. The contents
 | 
					 | 
				
			||||||
          of the NOTICE file are for informational purposes only and
 | 
					 | 
				
			||||||
          do not modify the License. You may add Your own attribution
 | 
					 | 
				
			||||||
          notices within Derivative Works that You distribute, alongside
 | 
					 | 
				
			||||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
					 | 
				
			||||||
          that such additional attribution notices cannot be construed
 | 
					 | 
				
			||||||
          as modifying the License.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      You may add Your own copyright statement to Your modifications and
 | 
					Thus, it is not the intent of this section to claim rights or contest
 | 
				
			||||||
      may provide additional or different license terms and conditions
 | 
					your rights to work written entirely by you; rather, the intent is to
 | 
				
			||||||
      for use, reproduction, or distribution of Your modifications, or
 | 
					exercise the right to control the distribution of derivative or
 | 
				
			||||||
      for any such Derivative Works as a whole, provided Your use,
 | 
					collective works based on the Program.
 | 
				
			||||||
      reproduction, and distribution of the Work otherwise complies with
 | 
					 | 
				
			||||||
      the conditions stated in this License.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
					In addition, mere aggregation of another work not based on the Program
 | 
				
			||||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
					with the Program (or with a work based on the Program) on a volume of
 | 
				
			||||||
      by You to the Licensor shall be under the terms and conditions of
 | 
					a storage or distribution medium does not bring the other work under
 | 
				
			||||||
      this License, without any additional terms or conditions.
 | 
					the scope of this License.
 | 
				
			||||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
					 | 
				
			||||||
      the terms of any separate license agreement you may have executed
 | 
					 | 
				
			||||||
      with Licensor regarding such Contributions.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
					  3. You may copy and distribute the Program (or a work based on it,
 | 
				
			||||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
					under Section 2) in object code or executable form under the terms of
 | 
				
			||||||
      except as required for reasonable and customary use in describing the
 | 
					Sections 1 and 2 above provided that you also do one of the following:
 | 
				
			||||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
					    a) Accompany it with the complete corresponding machine-readable
 | 
				
			||||||
      agreed to in writing, Licensor provides the Work (and each
 | 
					    source code, which must be distributed under the terms of Sections
 | 
				
			||||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
					    1 and 2 above on a medium customarily used for software interchange; or,
 | 
				
			||||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
					 | 
				
			||||||
      implied, including, without limitation, any warranties or conditions
 | 
					 | 
				
			||||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
					 | 
				
			||||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
					 | 
				
			||||||
      appropriateness of using or redistributing the Work and assume any
 | 
					 | 
				
			||||||
      risks associated with Your exercise of permissions under this License.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
					    b) Accompany it with a written offer, valid for at least three
 | 
				
			||||||
      whether in tort (including negligence), contract, or otherwise,
 | 
					    years, to give any third party, for a charge no more than your
 | 
				
			||||||
      unless required by applicable law (such as deliberate and grossly
 | 
					    cost of physically performing source distribution, a complete
 | 
				
			||||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
					    machine-readable copy of the corresponding source code, to be
 | 
				
			||||||
      liable to You for damages, including any direct, indirect, special,
 | 
					    distributed under the terms of Sections 1 and 2 above on a medium
 | 
				
			||||||
      incidental, or consequential damages of any character arising as a
 | 
					    customarily used for software interchange; or,
 | 
				
			||||||
      result of this License or out of the use or inability to use the
 | 
					 | 
				
			||||||
      Work (including but not limited to damages for loss of goodwill,
 | 
					 | 
				
			||||||
      work stoppage, computer failure or malfunction, or any and all
 | 
					 | 
				
			||||||
      other commercial damages or losses), even if such Contributor
 | 
					 | 
				
			||||||
      has been advised of the possibility of such damages.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
					    c) Accompany it with the information you received as to the offer
 | 
				
			||||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
					    to distribute corresponding source code.  (This alternative is
 | 
				
			||||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
					    allowed only for noncommercial distribution and only if you
 | 
				
			||||||
      or other liability obligations and/or rights consistent with this
 | 
					    received the program in object code or executable form with such
 | 
				
			||||||
      License. However, in accepting such obligations, You may act only
 | 
					    an offer, in accord with Subsection b above.)
 | 
				
			||||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
					 | 
				
			||||||
      of any other Contributor, and only if You agree to indemnify,
 | 
					 | 
				
			||||||
      defend, and hold each Contributor harmless for any liability
 | 
					 | 
				
			||||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
					 | 
				
			||||||
      of your accepting any such warranty or additional liability.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   END OF TERMS AND CONDITIONS
 | 
					The source code for a work means the preferred form of the work for
 | 
				
			||||||
 | 
					making modifications to it.  For an executable work, complete source
 | 
				
			||||||
 | 
					code means all the source code for all modules it contains, plus any
 | 
				
			||||||
 | 
					associated interface definition files, plus the scripts used to
 | 
				
			||||||
 | 
					control compilation and installation of the executable.  However, as a
 | 
				
			||||||
 | 
					special exception, the source code distributed need not include
 | 
				
			||||||
 | 
					anything that is normally distributed (in either source or binary
 | 
				
			||||||
 | 
					form) with the major components (compiler, kernel, and so on) of the
 | 
				
			||||||
 | 
					operating system on which the executable runs, unless that component
 | 
				
			||||||
 | 
					itself accompanies the executable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   APPENDIX: How to apply the Apache License to your work.
 | 
					If distribution of executable or object code is made by offering
 | 
				
			||||||
 | 
					access to copy from a designated place, then offering equivalent
 | 
				
			||||||
 | 
					access to copy the source code from the same place counts as
 | 
				
			||||||
 | 
					distribution of the source code, even though third parties are not
 | 
				
			||||||
 | 
					compelled to copy the source along with the object code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      To apply the Apache License to your work, attach the following
 | 
					  4. You may not copy, modify, sublicense, or distribute the Program
 | 
				
			||||||
      boilerplate notice, with the fields enclosed by brackets "[]"
 | 
					except as expressly provided under this License.  Any attempt
 | 
				
			||||||
      replaced with your own identifying information. (Don't include
 | 
					otherwise to copy, modify, sublicense or distribute the Program is
 | 
				
			||||||
      the brackets!)  The text should be enclosed in the appropriate
 | 
					void, and will automatically terminate your rights under this License.
 | 
				
			||||||
      comment syntax for the file format. We also recommend that a
 | 
					However, parties who have received copies, or rights, from you under
 | 
				
			||||||
      file or class name and description of purpose be included on the
 | 
					this License will not have their licenses terminated so long as such
 | 
				
			||||||
      same "printed page" as the copyright notice for easier
 | 
					parties remain in full compliance.
 | 
				
			||||||
      identification within third-party archives.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   Copyright [yyyy] [name of copyright owner]
 | 
					  5. You are not required to accept this License, since you have not
 | 
				
			||||||
 | 
					signed it.  However, nothing else grants you permission to modify or
 | 
				
			||||||
 | 
					distribute the Program or its derivative works.  These actions are
 | 
				
			||||||
 | 
					prohibited by law if you do not accept this License.  Therefore, by
 | 
				
			||||||
 | 
					modifying or distributing the Program (or any work based on the
 | 
				
			||||||
 | 
					Program), you indicate your acceptance of this License to do so, and
 | 
				
			||||||
 | 
					all its terms and conditions for copying, distributing or modifying
 | 
				
			||||||
 | 
					the Program or works based on it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
					  6. Each time you redistribute the Program (or any work based on the
 | 
				
			||||||
   you may not use this file except in compliance with the License.
 | 
					Program), the recipient automatically receives a license from the
 | 
				
			||||||
   You may obtain a copy of the License at
 | 
					original licensor to copy, distribute or modify the Program subject to
 | 
				
			||||||
 | 
					these terms and conditions.  You may not impose any further
 | 
				
			||||||
 | 
					restrictions on the recipients' exercise of the rights granted herein.
 | 
				
			||||||
 | 
					You are not responsible for enforcing compliance by third parties to
 | 
				
			||||||
 | 
					this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
					  7. If, as a consequence of a court judgment or allegation of patent
 | 
				
			||||||
 | 
					infringement or for any other reason (not limited to patent issues),
 | 
				
			||||||
 | 
					conditions are imposed on you (whether by court order, agreement or
 | 
				
			||||||
 | 
					otherwise) that contradict the conditions of this License, they do not
 | 
				
			||||||
 | 
					excuse you from the conditions of this License.  If you cannot
 | 
				
			||||||
 | 
					distribute so as to satisfy simultaneously your obligations under this
 | 
				
			||||||
 | 
					License and any other pertinent obligations, then as a consequence you
 | 
				
			||||||
 | 
					may not distribute the Program at all.  For example, if a patent
 | 
				
			||||||
 | 
					license would not permit royalty-free redistribution of the Program by
 | 
				
			||||||
 | 
					all those who receive copies directly or indirectly through you, then
 | 
				
			||||||
 | 
					the only way you could satisfy both it and this License would be to
 | 
				
			||||||
 | 
					refrain entirely from distribution of the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   Unless required by applicable law or agreed to in writing, software
 | 
					If any portion of this section is held invalid or unenforceable under
 | 
				
			||||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
					any particular circumstance, the balance of the section is intended to
 | 
				
			||||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					apply and the section as a whole is intended to apply in other
 | 
				
			||||||
   See the License for the specific language governing permissions and
 | 
					circumstances.
 | 
				
			||||||
   limitations under the License.
 | 
					
 | 
				
			||||||
 | 
					It is not the purpose of this section to induce you to infringe any
 | 
				
			||||||
 | 
					patents or other property right claims or to contest validity of any
 | 
				
			||||||
 | 
					such claims; this section has the sole purpose of protecting the
 | 
				
			||||||
 | 
					integrity of the free software distribution system, which is
 | 
				
			||||||
 | 
					implemented by public license practices.  Many people have made
 | 
				
			||||||
 | 
					generous contributions to the wide range of software distributed
 | 
				
			||||||
 | 
					through that system in reliance on consistent application of that
 | 
				
			||||||
 | 
					system; it is up to the author/donor to decide if he or she is willing
 | 
				
			||||||
 | 
					to distribute software through any other system and a licensee cannot
 | 
				
			||||||
 | 
					impose that choice.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This section is intended to make thoroughly clear what is believed to
 | 
				
			||||||
 | 
					be a consequence of the rest of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  8. If the distribution and/or use of the Program is restricted in
 | 
				
			||||||
 | 
					certain countries either by patents or by copyrighted interfaces, the
 | 
				
			||||||
 | 
					original copyright holder who places the Program under this License
 | 
				
			||||||
 | 
					may add an explicit geographical distribution limitation excluding
 | 
				
			||||||
 | 
					those countries, so that distribution is permitted only in or among
 | 
				
			||||||
 | 
					countries not thus excluded.  In such case, this License incorporates
 | 
				
			||||||
 | 
					the limitation as if written in the body of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  9. The Free Software Foundation may publish revised and/or new versions
 | 
				
			||||||
 | 
					of the General Public License from time to time.  Such new versions will
 | 
				
			||||||
 | 
					be similar in spirit to the present version, but may differ in detail to
 | 
				
			||||||
 | 
					address new problems or concerns.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each version is given a distinguishing version number.  If the Program
 | 
				
			||||||
 | 
					specifies a version number of this License which applies to it and "any
 | 
				
			||||||
 | 
					later version", you have the option of following the terms and conditions
 | 
				
			||||||
 | 
					either of that version or of any later version published by the Free
 | 
				
			||||||
 | 
					Software Foundation.  If the Program does not specify a version number of
 | 
				
			||||||
 | 
					this License, you may choose any version ever published by the Free Software
 | 
				
			||||||
 | 
					Foundation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  10. If you wish to incorporate parts of the Program into other free
 | 
				
			||||||
 | 
					programs whose distribution conditions are different, write to the author
 | 
				
			||||||
 | 
					to ask for permission.  For software which is copyrighted by the Free
 | 
				
			||||||
 | 
					Software Foundation, write to the Free Software Foundation; we sometimes
 | 
				
			||||||
 | 
					make exceptions for this.  Our decision will be guided by the two goals
 | 
				
			||||||
 | 
					of preserving the free status of all derivatives of our free software and
 | 
				
			||||||
 | 
					of promoting the sharing and reuse of software generally.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            NO WARRANTY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 | 
				
			||||||
 | 
					FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
 | 
				
			||||||
 | 
					OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 | 
				
			||||||
 | 
					PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 | 
				
			||||||
 | 
					OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
 | 
				
			||||||
 | 
					TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
 | 
				
			||||||
 | 
					PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 | 
				
			||||||
 | 
					REPAIR OR CORRECTION.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
				
			||||||
 | 
					WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 | 
				
			||||||
 | 
					REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
 | 
				
			||||||
 | 
					INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
 | 
				
			||||||
 | 
					OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
 | 
				
			||||||
 | 
					TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
 | 
				
			||||||
 | 
					YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 | 
				
			||||||
 | 
					PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 | 
				
			||||||
 | 
					POSSIBILITY OF SUCH DAMAGES.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                     END OF TERMS AND CONDITIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            How to Apply These Terms to Your New Programs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  If you develop a new program, and you want it to be of the greatest
 | 
				
			||||||
 | 
					possible use to the public, the best way to achieve this is to make it
 | 
				
			||||||
 | 
					free software which everyone can redistribute and change under these terms.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  To do so, attach the following notices to the program.  It is safest
 | 
				
			||||||
 | 
					to attach them to the start of each source file to most effectively
 | 
				
			||||||
 | 
					convey the exclusion of warranty; and each file should have at least
 | 
				
			||||||
 | 
					the "copyright" line and a pointer to where the full notice is found.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <one line to give the program's name and a brief idea of what it does.>
 | 
				
			||||||
 | 
					    Copyright (C) <year>  <name of author>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					    it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					    the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					    (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					    GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    You should have received a copy of the GNU General Public License along
 | 
				
			||||||
 | 
					    with this program; if not, see <https://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also add information on how to contact you by electronic and paper mail.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If the program is interactive, make it output a short notice like this
 | 
				
			||||||
 | 
					when it starts in an interactive mode:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Gnomovision version 69, Copyright (C) year name of author
 | 
				
			||||||
 | 
					    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 | 
				
			||||||
 | 
					    This is free software, and you are welcome to redistribute it
 | 
				
			||||||
 | 
					    under certain conditions; type `show c' for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The hypothetical commands `show w' and `show c' should show the appropriate
 | 
				
			||||||
 | 
					parts of the General Public License.  Of course, the commands you use may
 | 
				
			||||||
 | 
					be called something other than `show w' and `show c'; they could even be
 | 
				
			||||||
 | 
					mouse-clicks or menu items--whatever suits your program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You should also get your employer (if you work as a programmer) or your
 | 
				
			||||||
 | 
					school, if any, to sign a "copyright disclaimer" for the program, if
 | 
				
			||||||
 | 
					necessary.  Here is a sample; alter the names:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
 | 
				
			||||||
 | 
					  `Gnomovision' (which makes passes at compilers) written by James Hacker.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <signature of Moe Ghoul>, 1 April 1989
 | 
				
			||||||
 | 
					  Moe Ghoul, President of Vice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This General Public License does not permit incorporating your program into
 | 
				
			||||||
 | 
					proprietary programs.  If your program is a subroutine library, you may
 | 
				
			||||||
 | 
					consider it more useful to permit linking proprietary applications with the
 | 
				
			||||||
 | 
					library.  If this is what you want to do, use the GNU Lesser General
 | 
				
			||||||
 | 
					Public License instead of this License.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1 @@
 | 
				
			|||||||
<!--
 | 
					 | 
				
			||||||
SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
-->
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Brain Miration to SurrealDB
 | 
					# Brain Miration to SurrealDB
 | 
				
			||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
reorder_impl_items = true
 | 
					reorder_impl_items = true
 | 
				
			||||||
use_small_heuristics = "Max"
 | 
					use_small_heuristics = "Max"
 | 
				
			||||||
imports_granularity = "Module"
 | 
					imports_granularity = "Module"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
accounts:
 | 
					accounts:
 | 
				
			||||||
  DXXkYSnhP3ijsHYxkedcuMomEyc122WaAbkDX7SaGuUS:
 | 
					  DXXkYSnhP3ijsHYxkedcuMomEyc122WaAbkDX7SaGuUS:
 | 
				
			||||||
    balance: 20293420000
 | 
					    balance: 20293420000
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +0,0 @@
 | 
				
			|||||||
SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
@ -1,7 +1,4 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					 | 
				
			||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"
 | 
					cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mkdir -p secrets
 | 
					mkdir -p secrets
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,4 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					 | 
				
			||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"
 | 
					cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"
 | 
				
			||||||
cd ..
 | 
					cd ..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13,7 +10,7 @@ server="$1"
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[ "$server" == "testnet" ]] && server="root@prod-brain-1"
 | 
					[[ "$server" == "testnet" ]] && server="root@prod-brain-1"
 | 
				
			||||||
[[ "$server" == "staging" ]] && server="brain-staging"
 | 
					[[ "$server" == "staging" ]] && server="root@staging-brain-1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cargo build --release --bin brain
 | 
					cargo build --release --bin brain
 | 
				
			||||||
ssh $server systemctl stop detee-brain.service
 | 
					ssh $server systemctl stop detee-brain.service
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +0,0 @@
 | 
				
			|||||||
SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
@ -1 +0,0 @@
 | 
				
			|||||||
SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
@ -1,12 +1,9 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use detee_shared::app_proto::brain_app_cli_server::BrainAppCliServer;
 | 
					use detee_shared::app_proto::brain_app_cli_server::BrainAppCliServer;
 | 
				
			||||||
use detee_shared::app_proto::brain_app_daemon_server::BrainAppDaemonServer;
 | 
					use detee_shared::app_proto::brain_app_daemon_server::BrainAppDaemonServer;
 | 
				
			||||||
use detee_shared::general_proto::brain_general_cli_server::BrainGeneralCliServer;
 | 
					use detee_shared::general_proto::brain_general_cli_server::BrainGeneralCliServer;
 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_cli_server::BrainVmCliServer;
 | 
					use detee_shared::vm_proto::brain_vm_cli_server::BrainVmCliServer;
 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_daemon_server::BrainVmDaemonServer;
 | 
					use detee_shared::vm_proto::brain_vm_daemon_server::BrainVmDaemonServer;
 | 
				
			||||||
use dotenv::dotenv;
 | 
					use dotenv::dotenv;
 | 
				
			||||||
use std::net::SocketAddr;
 | 
					 | 
				
			||||||
use std::sync::Arc;
 | 
					use std::sync::Arc;
 | 
				
			||||||
use surreal_brain::constants::{BRAIN_GRPC_ADDR, CERT_KEY_PATH, CERT_PATH};
 | 
					use surreal_brain::constants::{BRAIN_GRPC_ADDR, CERT_KEY_PATH, CERT_PATH};
 | 
				
			||||||
use surreal_brain::db;
 | 
					use surreal_brain::db;
 | 
				
			||||||
@ -22,7 +19,6 @@ async fn main() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    env_logger::builder()
 | 
					    env_logger::builder()
 | 
				
			||||||
        .filter_level(log::LevelFilter::Trace)
 | 
					        .filter_level(log::LevelFilter::Trace)
 | 
				
			||||||
        .filter_module("rustls", log::LevelFilter::Debug)
 | 
					 | 
				
			||||||
        .filter_module("tungstenite", log::LevelFilter::Debug)
 | 
					        .filter_module("tungstenite", log::LevelFilter::Debug)
 | 
				
			||||||
        .filter_module("tokio_tungstenite", log::LevelFilter::Debug)
 | 
					        .filter_module("tokio_tungstenite", log::LevelFilter::Debug)
 | 
				
			||||||
        .init();
 | 
					        .init();
 | 
				
			||||||
@ -33,12 +29,6 @@ async fn main() {
 | 
				
			|||||||
    let db_ns = std::env::var("DB_NAMESPACE").expect("the env variable DB_NAMESPACE is not set");
 | 
					    let db_ns = std::env::var("DB_NAMESPACE").expect("the env variable DB_NAMESPACE is not set");
 | 
				
			||||||
    let db_name = std::env::var("DB_NAME").expect("the environment variable DB_NAME is not set");
 | 
					    let db_name = std::env::var("DB_NAME").expect("the environment variable DB_NAME is not set");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // To make sure env is set correctly
 | 
					 | 
				
			||||||
    std::env::var("BRAIN_PUBLIC_ENDPOINT")
 | 
					 | 
				
			||||||
        .expect("the environment variable BRAIN_PUBLIC_ENDPOINT is not set")
 | 
					 | 
				
			||||||
        .parse::<SocketAddr>()
 | 
					 | 
				
			||||||
        .expect("BRAIN_PUBLIC_ENDPOINT is not a socket address");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let db = db::db_connection(&db_url, &db_user, &db_pass, &db_ns, &db_name).await.unwrap();
 | 
					    let db = db::db_connection(&db_url, &db_user, &db_pass, &db_ns, &db_name).await.unwrap();
 | 
				
			||||||
    let db_arc = Arc::new(db);
 | 
					    let db_arc = Arc::new(db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,52 +0,0 @@
 | 
				
			|||||||
use detee_shared::app_proto::brain_app_cli_server::BrainAppCliServer;
 | 
					 | 
				
			||||||
use detee_shared::app_proto::brain_app_daemon_server::BrainAppDaemonServer;
 | 
					 | 
				
			||||||
use detee_shared::general_proto::brain_general_cli_server::BrainGeneralCliServer;
 | 
					 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_cli_server::BrainVmCliServer;
 | 
					 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_daemon_server::BrainVmDaemonServer;
 | 
					 | 
				
			||||||
use dotenv::dotenv;
 | 
					 | 
				
			||||||
use std::sync::Arc;
 | 
					 | 
				
			||||||
use surreal_brain::constants::BRAIN_GRPC_ADDR;
 | 
					 | 
				
			||||||
use surreal_brain::db;
 | 
					 | 
				
			||||||
use surreal_brain::grpc::app::{AppCliServer, AppDaemonServer};
 | 
					 | 
				
			||||||
use surreal_brain::grpc::general::GeneralCliServer;
 | 
					 | 
				
			||||||
use surreal_brain::grpc::vm::{VmCliServer, VmDaemonServer};
 | 
					 | 
				
			||||||
use tonic::transport::Server;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[tokio::main]
 | 
					 | 
				
			||||||
async fn main() {
 | 
					 | 
				
			||||||
    if dotenv::from_filename("/etc/detee/brain/config.ini").is_err() {
 | 
					 | 
				
			||||||
        dotenv().ok();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    env_logger::builder()
 | 
					 | 
				
			||||||
        .filter_level(log::LevelFilter::Trace)
 | 
					 | 
				
			||||||
        .filter_module("tungstenite", log::LevelFilter::Debug)
 | 
					 | 
				
			||||||
        .filter_module("tokio_tungstenite", log::LevelFilter::Debug)
 | 
					 | 
				
			||||||
        .init();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let db_url = std::env::var("DB_URL").expect("the environment variable DB_URL is not set");
 | 
					 | 
				
			||||||
    let db_user = std::env::var("DB_USER").expect("the environment variable DB_USER is not set");
 | 
					 | 
				
			||||||
    let db_pass = std::env::var("DB_PASS").expect("the environment variable DB_PASS is not set");
 | 
					 | 
				
			||||||
    let db_ns = std::env::var("DB_NAMESPACE").expect("the env variable DB_NAMESPACE is not set");
 | 
					 | 
				
			||||||
    let db_name = std::env::var("DB_NAME").expect("the environment variable DB_NAME is not set");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let db = db::db_connection(&db_url, &db_user, &db_pass, &db_ns, &db_name).await.unwrap();
 | 
					 | 
				
			||||||
    let db_arc = Arc::new(db);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let addr = BRAIN_GRPC_ADDR.parse().unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let snp_daemon_server = BrainVmDaemonServer::new(VmDaemonServer::new(db_arc.clone()));
 | 
					 | 
				
			||||||
    let snp_cli_server = BrainVmCliServer::new(VmCliServer::new(db_arc.clone()));
 | 
					 | 
				
			||||||
    let general_service_server = BrainGeneralCliServer::new(GeneralCliServer::new(db_arc.clone()));
 | 
					 | 
				
			||||||
    let sgx_daemon_server = BrainAppDaemonServer::new(AppDaemonServer::new(db_arc.clone()));
 | 
					 | 
				
			||||||
    let sgx_cli_server = BrainAppCliServer::new(AppCliServer::new(db_arc.clone()));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Server::builder()
 | 
					 | 
				
			||||||
        .add_service(snp_daemon_server)
 | 
					 | 
				
			||||||
        .add_service(snp_cli_server)
 | 
					 | 
				
			||||||
        .add_service(general_service_server)
 | 
					 | 
				
			||||||
        .add_service(sgx_daemon_server)
 | 
					 | 
				
			||||||
        .add_service(sgx_cli_server)
 | 
					 | 
				
			||||||
        .serve(addr)
 | 
					 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
        .unwrap();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// After deleting this migration, also delete old_brain structs
 | 
					// After deleting this migration, also delete old_brain structs
 | 
				
			||||||
// and dangling impls from the model
 | 
					// and dangling impls from the model
 | 
				
			||||||
use dotenv::dotenv;
 | 
					use dotenv::dotenv;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,6 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use std::sync::LazyLock;
 | 
					use std::sync::LazyLock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const BRAIN_GRPC_ADDR: &str = "0.0.0.0:31337";
 | 
					pub const BRAIN_GRPC_ADDR: &str = "0.0.0.0:31337";
 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const CERT_PATH: &str = "/etc/detee/brain/brain-crt.pem";
 | 
					pub const CERT_PATH: &str = "/etc/detee/brain/brain-crt.pem";
 | 
				
			||||||
pub const CERT_KEY_PATH: &str = "/etc/detee/brain/brain-key.pem";
 | 
					pub const CERT_KEY_PATH: &str = "/etc/detee/brain/brain-key.pem";
 | 
				
			||||||
pub const CONFIG_PATH: &str = "/etc/detee/brain/config.ini";
 | 
					pub const CONFIG_PATH: &str = "/etc/detee/brain/config.ini";
 | 
				
			||||||
@ -54,5 +51,3 @@ pub const MIN_ESCROW: u64 = 5000 * TOKEN_DECIMAL;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub const APP_DAEMON_TIMEOUT: u64 = 20;
 | 
					pub const APP_DAEMON_TIMEOUT: u64 = 20;
 | 
				
			||||||
pub const VM_DAEMON_TIMEOUT: u64 = 10;
 | 
					pub const VM_DAEMON_TIMEOUT: u64 = 10;
 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const DEFAULT_ENDPOINT: &str = "127.0.0.1:31337";
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,8 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use std::time::Duration;
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::Error;
 | 
					use super::Error;
 | 
				
			||||||
use crate::constants::{
 | 
					use crate::constants::{
 | 
				
			||||||
    ACCOUNT, ACTIVE_APP, APP_DAEMON_TIMEOUT, APP_NODE, DEFAULT_ENDPOINT, DELETED_APP, NEW_APP_REQ,
 | 
					    ACCOUNT, ACTIVE_APP, APP_DAEMON_TIMEOUT, APP_NODE, DELETED_APP, NEW_APP_REQ,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use crate::db;
 | 
					use crate::db;
 | 
				
			||||||
use crate::db::general::Report;
 | 
					use crate::db::general::Report;
 | 
				
			||||||
@ -20,7 +18,6 @@ use tokio_stream::StreamExt;
 | 
				
			|||||||
pub struct AppNode {
 | 
					pub struct AppNode {
 | 
				
			||||||
    pub id: RecordId,
 | 
					    pub id: RecordId,
 | 
				
			||||||
    pub operator: RecordId,
 | 
					    pub operator: RecordId,
 | 
				
			||||||
    pub pub_sub_node: String,
 | 
					 | 
				
			||||||
    pub country: String,
 | 
					    pub country: String,
 | 
				
			||||||
    pub region: String,
 | 
					    pub region: String,
 | 
				
			||||||
    pub city: String,
 | 
					    pub city: String,
 | 
				
			||||||
@ -86,12 +83,6 @@ impl NewAppReq {
 | 
				
			|||||||
        let new_app_req: Option<Self> = db.select((NEW_APP_REQ, id)).await?;
 | 
					        let new_app_req: Option<Self> = db.select((NEW_APP_REQ, id)).await?;
 | 
				
			||||||
        Ok(new_app_req)
 | 
					        Ok(new_app_req)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub async fn delete(db: &Surreal<Client>, id: &str) -> Result<(), Error> {
 | 
					 | 
				
			||||||
        let _: Option<Self> = db.delete((NEW_APP_REQ, id)).await?;
 | 
					 | 
				
			||||||
        Ok(())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub async fn submit_error(db: &Surreal<Client>, id: &str, error: String) -> Result<(), Error> {
 | 
					    pub async fn submit_error(db: &Surreal<Client>, id: &str, error: String) -> Result<(), Error> {
 | 
				
			||||||
        let tx_query = String::from(
 | 
					        let tx_query = String::from(
 | 
				
			||||||
            "
 | 
					            "
 | 
				
			||||||
@ -142,7 +133,7 @@ impl NewAppReq {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    pub async fn submit(self, db: &Surreal<Client>) -> Result<(), Error> {
 | 
					    pub async fn submit(self, db: &Surreal<Client>) -> Result<(), Error> {
 | 
				
			||||||
        let locked_nano = self.locked_nano;
 | 
					        let locked_nano = self.locked_nano;
 | 
				
			||||||
        let tx_query = format!("
 | 
					        let tx_query = format!( "
 | 
				
			||||||
            BEGIN TRANSACTION;
 | 
					            BEGIN TRANSACTION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                LET $account = $account_input;
 | 
					                LET $account = $account_input;
 | 
				
			||||||
@ -159,6 +150,7 @@ impl NewAppReq {
 | 
				
			|||||||
                }};
 | 
					                }};
 | 
				
			||||||
                UPDATE $account SET tmp_locked += {locked_nano};
 | 
					                UPDATE $account SET tmp_locked += {locked_nano};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                RELATE
 | 
					                RELATE
 | 
				
			||||||
                    $account
 | 
					                    $account
 | 
				
			||||||
                    ->$new_app_req
 | 
					                    ->$new_app_req
 | 
				
			||||||
@ -169,7 +161,8 @@ impl NewAppReq {
 | 
				
			|||||||
                    vcpus: {}, disk_size_gb: {}, locked_nano: {locked_nano}, price_per_unit: {}, error: '',
 | 
					                    vcpus: {}, disk_size_gb: {}, locked_nano: {locked_nano}, price_per_unit: {}, error: '',
 | 
				
			||||||
                }};
 | 
					                }};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            COMMIT TRANSACTION;",
 | 
					            COMMIT TRANSACTION;
 | 
				
			||||||
 | 
					            ",
 | 
				
			||||||
            self.ports, self.memory_mb, self.vcpus, self.disk_size_gb, self.price_per_unit);
 | 
					            self.ports, self.memory_mb, self.vcpus, self.disk_size_gb, self.price_per_unit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        log::trace!("submit_new_app_req query: {tx_query}");
 | 
					        log::trace!("submit_new_app_req query: {tx_query}");
 | 
				
			||||||
@ -229,7 +222,7 @@ impl AppNodeWithReports {
 | 
				
			|||||||
        limit_one: bool,
 | 
					        limit_one: bool,
 | 
				
			||||||
    ) -> Result<Vec<Self>, Error> {
 | 
					    ) -> Result<Vec<Self>, Error> {
 | 
				
			||||||
        let mut filter_query = format!(
 | 
					        let mut filter_query = format!(
 | 
				
			||||||
            "select *, <-report.* as reports from {APP_NODE} where
 | 
					            "select *, <-report.* from {APP_NODE} where
 | 
				
			||||||
            avail_ports >= {} &&
 | 
					            avail_ports >= {} &&
 | 
				
			||||||
            max_ports_per_app >= {} &&
 | 
					            max_ports_per_app >= {} &&
 | 
				
			||||||
            avail_vcpus >= {} &&
 | 
					            avail_vcpus >= {} &&
 | 
				
			||||||
@ -239,10 +232,9 @@ impl AppNodeWithReports {
 | 
				
			|||||||
            filters.free_ports,
 | 
					            filters.free_ports,
 | 
				
			||||||
            filters.vcpus,
 | 
					            filters.vcpus,
 | 
				
			||||||
            filters.memory_mb,
 | 
					            filters.memory_mb,
 | 
				
			||||||
            filters.storage_gb
 | 
					            filters.storage_mb
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TODO: bind all strings
 | 
					 | 
				
			||||||
        if !filters.city.is_empty() {
 | 
					        if !filters.city.is_empty() {
 | 
				
			||||||
            filter_query += &format!("&& city = '{}' ", filters.city);
 | 
					            filter_query += &format!("&& city = '{}' ", filters.city);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -320,15 +312,6 @@ impl ActiveApp {
 | 
				
			|||||||
        (self.vcpus as f64 * 5f64) + (self.memory_mb as f64 / 200f64) + (self.disk_size_gb as f64)
 | 
					        (self.vcpus as f64 * 5f64) + (self.memory_mb as f64 / 200f64) + (self.disk_size_gb as f64)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn get_by_uuid(db: &Surreal<Client>, uuid: &str) -> Result<Option<Self>, Error> {
 | 
					 | 
				
			||||||
        let contract: Option<Self> = db
 | 
					 | 
				
			||||||
            .query("select * from $active_app_id;".to_string())
 | 
					 | 
				
			||||||
            .bind(("active_app_id", RecordId::from((ACTIVE_APP, uuid))))
 | 
					 | 
				
			||||||
            .await?
 | 
					 | 
				
			||||||
            .take(0)?;
 | 
					 | 
				
			||||||
        Ok(contract)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub async fn activate(
 | 
					    pub async fn activate(
 | 
				
			||||||
        db: &Surreal<Client>,
 | 
					        db: &Surreal<Client>,
 | 
				
			||||||
        new_app_res: app_proto::NewAppRes,
 | 
					        new_app_res: app_proto::NewAppRes,
 | 
				
			||||||
@ -350,7 +333,7 @@ impl ActiveApp {
 | 
				
			|||||||
            app_node: new_app_req.app_node,
 | 
					            app_node: new_app_req.app_node,
 | 
				
			||||||
            app_name: new_app_req.app_name,
 | 
					            app_name: new_app_req.app_name,
 | 
				
			||||||
            mapped_ports,
 | 
					            mapped_ports,
 | 
				
			||||||
            host_ipv4: new_app_res.ip_address,
 | 
					            host_ipv4: String::new(),
 | 
				
			||||||
            vcpus: new_app_req.vcpus,
 | 
					            vcpus: new_app_req.vcpus,
 | 
				
			||||||
            memory_mb: new_app_req.memory_mb,
 | 
					            memory_mb: new_app_req.memory_mb,
 | 
				
			||||||
            disk_size_gb: new_app_req.disk_size_gb,
 | 
					            disk_size_gb: new_app_req.disk_size_gb,
 | 
				
			||||||
@ -367,7 +350,7 @@ impl ActiveApp {
 | 
				
			|||||||
        let locked_nano = active_app.locked_nano;
 | 
					        let locked_nano = active_app.locked_nano;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let _: Vec<ActiveApp> = db.insert(()).relation(active_app).await?;
 | 
					        let _: Vec<ActiveApp> = db.insert(()).relation(active_app).await?;
 | 
				
			||||||
        NewAppReq::delete(&db, &new_app_res.uuid).await?;
 | 
					        db.delete::<Option<NewAppReq>>((NEW_APP_REQ, &new_app_res.uuid)).await?;
 | 
				
			||||||
        db.query(format!("UPDATE {ACCOUNT}:{admin_account} SET tmp_locked -= {locked_nano};"))
 | 
					        db.query(format!("UPDATE {ACCOUNT}:{admin_account} SET tmp_locked -= {locked_nano};"))
 | 
				
			||||||
            .await?;
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -474,6 +457,7 @@ impl WrappedAppResp {
 | 
				
			|||||||
                        match active_app_notif {
 | 
					                        match active_app_notif {
 | 
				
			||||||
                            Ok(active_app_notif) =>{
 | 
					                            Ok(active_app_notif) =>{
 | 
				
			||||||
                                if active_app_notif.action == surrealdb::Action::Create {
 | 
					                                if active_app_notif.action == surrealdb::Action::Create {
 | 
				
			||||||
 | 
					                                    let _: Option<NewAppReq> = db.delete((NEW_APP_REQ, app_id)).await?;
 | 
				
			||||||
                                    return Ok(Self::NewAppRes(active_app_notif.data.into()));
 | 
					                                    return Ok(Self::NewAppRes(active_app_notif.data.into()));
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
@ -597,10 +581,10 @@ impl ActiveAppWithNode {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Serialize)]
 | 
					#[derive(Debug, Serialize)]
 | 
				
			||||||
pub struct AppNodeResources {
 | 
					pub struct AppNodeResources {
 | 
				
			||||||
    pub avail_ports: u32,
 | 
					    pub avail_no_of_port: u32,
 | 
				
			||||||
    pub avail_vcpus: u32,
 | 
					    pub avail_vcpus: u32,
 | 
				
			||||||
    pub avail_mem_mb: u32,
 | 
					    pub avail_memory_mb: u32,
 | 
				
			||||||
    pub avail_storage_gbs: u32,
 | 
					    pub avail_storage_mb: u32,
 | 
				
			||||||
    pub max_ports_per_app: u32,
 | 
					    pub max_ports_per_app: u32,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -611,7 +595,6 @@ impl AppNodeResources {
 | 
				
			|||||||
        node_pubkey: &str,
 | 
					        node_pubkey: &str,
 | 
				
			||||||
    ) -> Result<Option<AppNode>, Error> {
 | 
					    ) -> Result<Option<AppNode>, Error> {
 | 
				
			||||||
        let app_node: Option<AppNode> = db.update((APP_NODE, node_pubkey)).merge(self).await?;
 | 
					        let app_node: Option<AppNode> = db.update((APP_NODE, node_pubkey)).merge(self).await?;
 | 
				
			||||||
        log::trace!("Merged app node resources for {node_pubkey}: {:?}", app_node);
 | 
					 | 
				
			||||||
        Ok(app_node)
 | 
					        Ok(app_node)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -623,7 +606,6 @@ impl From<&old_brain::BrainData> for Vec<AppNode> {
 | 
				
			|||||||
            nodes.push(AppNode {
 | 
					            nodes.push(AppNode {
 | 
				
			||||||
                id: RecordId::from((APP_NODE, old_node.node_pubkey.clone())),
 | 
					                id: RecordId::from((APP_NODE, old_node.node_pubkey.clone())),
 | 
				
			||||||
                operator: RecordId::from((ACCOUNT, old_node.operator_wallet.clone())),
 | 
					                operator: RecordId::from((ACCOUNT, old_node.operator_wallet.clone())),
 | 
				
			||||||
                pub_sub_node: DEFAULT_ENDPOINT.to_string(),
 | 
					 | 
				
			||||||
                country: old_node.country.clone(),
 | 
					                country: old_node.country.clone(),
 | 
				
			||||||
                region: old_node.region.clone(),
 | 
					                region: old_node.region.clone(),
 | 
				
			||||||
                city: old_node.city.clone(),
 | 
					                city: old_node.city.clone(),
 | 
				
			||||||
@ -703,7 +685,6 @@ pub struct DeletedApp {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
impl DeletedApp {
 | 
					impl DeletedApp {
 | 
				
			||||||
    pub async fn list_by_node(db: &Surreal<Client>, node_pubkey: &str) -> Result<Vec<Self>, Error> {
 | 
					    pub async fn list_by_node(db: &Surreal<Client>, node_pubkey: &str) -> Result<Vec<Self>, Error> {
 | 
				
			||||||
        // TODO: bind all strings
 | 
					 | 
				
			||||||
        let mut result = db
 | 
					        let mut result = db
 | 
				
			||||||
            .query(format!("select * from {DELETED_APP} where out = {APP_NODE}:{node_pubkey};"))
 | 
					            .query(format!("select * from {DELETED_APP} where out = {APP_NODE}:{node_pubkey};"))
 | 
				
			||||||
            .await?;
 | 
					            .await?;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use super::Error;
 | 
					use super::Error;
 | 
				
			||||||
use crate::constants::{ACCOUNT, BAN, KICK, MIN_ESCROW, VM_NODE};
 | 
					use crate::constants::{ACCOUNT, BAN, KICK, MIN_ESCROW, VM_NODE};
 | 
				
			||||||
use crate::db::prelude::*;
 | 
					use crate::db::prelude::*;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,19 +1,17 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub mod app;
 | 
					pub mod app;
 | 
				
			||||||
pub mod general;
 | 
					pub mod general;
 | 
				
			||||||
pub mod vm;
 | 
					pub mod vm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::constants::{
 | 
					use crate::constants::{
 | 
				
			||||||
    APP_NODE, DB_SCHEMA_FILES, DEFAULT_ENDPOINT, DELETED_APP, DELETED_VM, MIN_ESCROW, NEW_APP_REQ,
 | 
					    APP_NODE, DB_SCHEMA_FILES, DELETED_APP, DELETED_VM, MIN_ESCROW, NEW_APP_REQ, NEW_VM_REQ,
 | 
				
			||||||
    NEW_VM_REQ, UPDATE_VM_REQ,
 | 
					    UPDATE_VM_REQ,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use crate::old_brain;
 | 
					use crate::old_brain;
 | 
				
			||||||
use prelude::*;
 | 
					use prelude::*;
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use surrealdb::engine::remote::ws::{Client, Ws};
 | 
					use surrealdb::engine::remote::ws::{Client, Ws};
 | 
				
			||||||
use surrealdb::opt::auth::Root;
 | 
					use surrealdb::opt::auth::Root;
 | 
				
			||||||
use surrealdb::{Notification, RecordId, Surreal};
 | 
					use surrealdb::{Notification, Surreal};
 | 
				
			||||||
use tokio::sync::mpsc::Sender;
 | 
					use tokio::sync::mpsc::Sender;
 | 
				
			||||||
use tokio_stream::StreamExt;
 | 
					use tokio_stream::StreamExt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -53,8 +51,6 @@ pub enum Error {
 | 
				
			|||||||
    TooBigTransaction(String),
 | 
					    TooBigTransaction(String),
 | 
				
			||||||
    #[error("Unknown: {0}")]
 | 
					    #[error("Unknown: {0}")]
 | 
				
			||||||
    Unknown(String),
 | 
					    Unknown(String),
 | 
				
			||||||
    #[error(transparent)]
 | 
					 | 
				
			||||||
    Tonic(#[from] tonic::Status),
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod prelude {
 | 
					pub mod prelude {
 | 
				
			||||||
@ -173,8 +169,6 @@ pub async fn live_appnode_msgs<
 | 
				
			|||||||
            return Err(Error::UnknownTable(t.to_string()));
 | 
					            return Err(Error::UnknownTable(t.to_string()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    log::trace!("live_appnode_msgs for {table_name} DB stream for node {node_pubkey}");
 | 
					 | 
				
			||||||
    // TODO: bind node_pubkey
 | 
					 | 
				
			||||||
    let mut query_resp = db
 | 
					    let mut query_resp = db
 | 
				
			||||||
        .query(format!("live select * from {table_name} where out = {APP_NODE}:{node_pubkey};"))
 | 
					        .query(format!("live select * from {table_name} where out = {APP_NODE}:{node_pubkey};"))
 | 
				
			||||||
        .await?;
 | 
					        .await?;
 | 
				
			||||||
@ -200,36 +194,7 @@ pub async fn live_appnode_msgs<
 | 
				
			|||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn check_pubsub_node(
 | 
					 | 
				
			||||||
    db: &Surreal<Client>,
 | 
					 | 
				
			||||||
    id: RecordId,
 | 
					 | 
				
			||||||
) -> Result<Option<tonic::Status>, Error> {
 | 
					 | 
				
			||||||
    let pub_endpoint =
 | 
					 | 
				
			||||||
        std::env::var("BRAIN_PUBLIC_ENDPOINT").unwrap_or(DEFAULT_ENDPOINT.to_string());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut query_resp =
 | 
					 | 
				
			||||||
        db.query("select pub_sub_node from $record_id").bind(("record_id", id)).await?;
 | 
					 | 
				
			||||||
    let node_endpoint = query_resp
 | 
					 | 
				
			||||||
        .take::<Option<PubSubNode>>(0)?
 | 
					 | 
				
			||||||
        .ok_or(tonic::Status::internal("Could not get current brain endpoint"))?
 | 
					 | 
				
			||||||
        .pub_sub_node;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if pub_endpoint == node_endpoint {
 | 
					 | 
				
			||||||
        return Ok(None);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut status = tonic::Status::new(tonic::Code::Unavailable, "moved");
 | 
					 | 
				
			||||||
    status.metadata_mut().insert("location", node_endpoint.parse().unwrap());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Ok(Some(status))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Deserialize, Debug, Clone)]
 | 
					#[derive(Deserialize, Debug, Clone)]
 | 
				
			||||||
pub struct ErrorFromTable {
 | 
					pub struct ErrorFromTable {
 | 
				
			||||||
    pub error: String,
 | 
					    pub error: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Deserialize, Debug)]
 | 
					 | 
				
			||||||
struct PubSubNode {
 | 
					 | 
				
			||||||
    pub pub_sub_node: String,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										15
									
								
								src/db/vm.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										15
									
								
								src/db/vm.rs
									
									
									
									
									
								
							@ -1,12 +1,10 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use std::str::FromStr;
 | 
					use std::str::FromStr;
 | 
				
			||||||
use std::time::Duration;
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::Error;
 | 
					use super::Error;
 | 
				
			||||||
use crate::constants::{
 | 
					use crate::constants::{
 | 
				
			||||||
    ACCOUNT, ACTIVE_VM, DEFAULT_ENDPOINT, DELETED_VM, NEW_VM_REQ, UPDATE_VM_REQ, VM_DAEMON_TIMEOUT,
 | 
					    ACCOUNT, ACTIVE_VM, DELETED_VM, NEW_VM_REQ, UPDATE_VM_REQ, VM_DAEMON_TIMEOUT, VM_NODE,
 | 
				
			||||||
    VM_NODE, VM_UPDATE_EVENT,
 | 
					    VM_UPDATE_EVENT,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use crate::db::{Account, ErrorFromTable, Report};
 | 
					use crate::db::{Account, ErrorFromTable, Report};
 | 
				
			||||||
use crate::old_brain;
 | 
					use crate::old_brain;
 | 
				
			||||||
@ -21,7 +19,6 @@ use tokio_stream::StreamExt as _;
 | 
				
			|||||||
pub struct VmNode {
 | 
					pub struct VmNode {
 | 
				
			||||||
    pub id: RecordId,
 | 
					    pub id: RecordId,
 | 
				
			||||||
    pub operator: RecordId,
 | 
					    pub operator: RecordId,
 | 
				
			||||||
    pub pub_sub_node: String,
 | 
					 | 
				
			||||||
    pub country: String,
 | 
					    pub country: String,
 | 
				
			||||||
    pub region: String,
 | 
					    pub region: String,
 | 
				
			||||||
    pub city: String,
 | 
					    pub city: String,
 | 
				
			||||||
@ -433,11 +430,8 @@ impl ActiveVm {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn get_by_uuid(db: &Surreal<Client>, uuid: &str) -> Result<Option<Self>, Error> {
 | 
					    pub async fn get_by_uuid(db: &Surreal<Client>, uuid: &str) -> Result<Option<Self>, Error> {
 | 
				
			||||||
        let contract: Option<Self> = db
 | 
					        let contract: Option<Self> =
 | 
				
			||||||
            .query("select * from $active_vm_id;".to_string())
 | 
					            db.query(format!("select * from {ACTIVE_VM}:{uuid};")).await?.take(0)?;
 | 
				
			||||||
            .bind(("active_vm_id", RecordId::from((ACTIVE_VM, uuid))))
 | 
					 | 
				
			||||||
            .await?
 | 
					 | 
				
			||||||
            .take(0)?;
 | 
					 | 
				
			||||||
        Ok(contract)
 | 
					        Ok(contract)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1000,7 +994,6 @@ impl From<&old_brain::BrainData> for Vec<VmNode> {
 | 
				
			|||||||
            nodes.push(VmNode {
 | 
					            nodes.push(VmNode {
 | 
				
			||||||
                id: RecordId::from((VM_NODE, old_node.public_key.clone())),
 | 
					                id: RecordId::from((VM_NODE, old_node.public_key.clone())),
 | 
				
			||||||
                operator: RecordId::from((ACCOUNT, old_node.operator_wallet.clone())),
 | 
					                operator: RecordId::from((ACCOUNT, old_node.operator_wallet.clone())),
 | 
				
			||||||
                pub_sub_node: DEFAULT_ENDPOINT.to_string(),
 | 
					 | 
				
			||||||
                country: old_node.country.clone(),
 | 
					                country: old_node.country.clone(),
 | 
				
			||||||
                region: old_node.region.clone(),
 | 
					                region: old_node.region.clone(),
 | 
				
			||||||
                city: old_node.city.clone(),
 | 
					                city: old_node.city.clone(),
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,4 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					use crate::constants::{ACCOUNT, APP_NODE};
 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::constants::{ACCOUNT, APP_NODE, DEFAULT_ENDPOINT};
 | 
					 | 
				
			||||||
use crate::db::app::ActiveApp;
 | 
					use crate::db::app::ActiveApp;
 | 
				
			||||||
use crate::db::prelude as db;
 | 
					use crate::db::prelude as db;
 | 
				
			||||||
use crate::grpc::{check_sig_from_parts, check_sig_from_req};
 | 
					use crate::grpc::{check_sig_from_parts, check_sig_from_req};
 | 
				
			||||||
@ -44,8 +42,6 @@ impl BrainAppDaemon for AppDaemonServer {
 | 
				
			|||||||
        let app_node = db::AppNode {
 | 
					        let app_node = db::AppNode {
 | 
				
			||||||
            id: RecordId::from((APP_NODE, req.node_pubkey.clone())),
 | 
					            id: RecordId::from((APP_NODE, req.node_pubkey.clone())),
 | 
				
			||||||
            operator: RecordId::from((ACCOUNT, req.operator_wallet)),
 | 
					            operator: RecordId::from((ACCOUNT, req.operator_wallet)),
 | 
				
			||||||
            pub_sub_node: std::env::var("BRAIN_PUBLIC_ENDPOINT")
 | 
					 | 
				
			||||||
                .unwrap_or(DEFAULT_ENDPOINT.to_string()),
 | 
					 | 
				
			||||||
            country: req.country,
 | 
					            country: req.country,
 | 
				
			||||||
            region: req.region,
 | 
					            region: req.region,
 | 
				
			||||||
            city: req.city,
 | 
					            city: req.city,
 | 
				
			||||||
@ -141,7 +137,6 @@ impl BrainAppDaemon for AppDaemonServer {
 | 
				
			|||||||
            match daemon_message {
 | 
					            match daemon_message {
 | 
				
			||||||
                Ok(msg) => match msg.msg {
 | 
					                Ok(msg) => match msg.msg {
 | 
				
			||||||
                    Some(daemon_message_app::Msg::NewAppRes(new_app_resp)) => {
 | 
					                    Some(daemon_message_app::Msg::NewAppRes(new_app_resp)) => {
 | 
				
			||||||
                        log::trace!("New app response from node: {pubkey}, {:?}", new_app_resp);
 | 
					 | 
				
			||||||
                        if !new_app_resp.error.is_empty() {
 | 
					                        if !new_app_resp.error.is_empty() {
 | 
				
			||||||
                            db::NewAppReq::submit_error(
 | 
					                            db::NewAppReq::submit_error(
 | 
				
			||||||
                                &self.db,
 | 
					                                &self.db,
 | 
				
			||||||
@ -155,7 +150,6 @@ impl BrainAppDaemon for AppDaemonServer {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    Some(daemon_message_app::Msg::AppNodeResources(app_node_resources)) => {
 | 
					                    Some(daemon_message_app::Msg::AppNodeResources(app_node_resources)) => {
 | 
				
			||||||
                        let node_resource: db::AppNodeResources = app_node_resources.into();
 | 
					                        let node_resource: db::AppNodeResources = app_node_resources.into();
 | 
				
			||||||
                        log::trace!("App node {pubkey} resources: {:?}", node_resource);
 | 
					 | 
				
			||||||
                        node_resource.merge(&self.db, &pubkey).await?;
 | 
					                        node_resource.merge(&self.db, &pubkey).await?;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    _ => {}
 | 
					                    _ => {}
 | 
				
			||||||
@ -188,13 +182,6 @@ impl BrainAppCli for AppCliServer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    async fn new_app(&self, req: Request<NewAppReq>) -> Result<Response<NewAppRes>, Status> {
 | 
					    async fn new_app(&self, req: Request<NewAppReq>) -> Result<Response<NewAppRes>, Status> {
 | 
				
			||||||
        let req = check_sig_from_req(req)?;
 | 
					        let req = check_sig_from_req(req)?;
 | 
				
			||||||
 | 
					 | 
				
			||||||
        let id = surrealdb::RecordId::from((APP_NODE, req.node_pubkey.clone()));
 | 
					 | 
				
			||||||
        if let Some(redirect) = db::check_pubsub_node(&self.db, id).await? {
 | 
					 | 
				
			||||||
            log::info!("redirect: {redirect}");
 | 
					 | 
				
			||||||
            return Err(redirect);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // TODO: make it atleast 1 hour
 | 
					        // TODO: make it atleast 1 hour
 | 
				
			||||||
        if req.locked_nano < 100 {
 | 
					        if req.locked_nano < 100 {
 | 
				
			||||||
            log::error!("locking lessthan 100 nano lps: {}", req.locked_nano);
 | 
					            log::error!("locking lessthan 100 nano lps: {}", req.locked_nano);
 | 
				
			||||||
@ -228,9 +215,7 @@ impl BrainAppCli for AppCliServer {
 | 
				
			|||||||
                ))
 | 
					                ))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Err(e) => {
 | 
					            Err(e) => {
 | 
				
			||||||
                log::error!(
 | 
					                log::error!("Something weird happened during CLI NewAppReq. Reached error {e:?}");
 | 
				
			||||||
                    "Something wrong happened on channel during CLI NewAppReq. Reached error {e:?}"
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                Err(Status::unknown(
 | 
					                Err(Status::unknown(
 | 
				
			||||||
                    "Unknown error. Please try again or contact the DeTEE devs team.",
 | 
					                    "Unknown error. Please try again or contact the DeTEE devs team.",
 | 
				
			||||||
                ))
 | 
					                ))
 | 
				
			||||||
@ -240,15 +225,6 @@ impl BrainAppCli for AppCliServer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    async fn delete_app(&self, req: Request<DelAppReq>) -> Result<Response<Empty>, Status> {
 | 
					    async fn delete_app(&self, req: Request<DelAppReq>) -> Result<Response<Empty>, Status> {
 | 
				
			||||||
        let req = check_sig_from_req(req)?;
 | 
					        let req = check_sig_from_req(req)?;
 | 
				
			||||||
        let app_node = db::ActiveApp::get_by_uuid(&self.db, &req.uuid)
 | 
					 | 
				
			||||||
            .await?
 | 
					 | 
				
			||||||
            .ok_or(Status::permission_denied("Unauthorized"))?
 | 
					 | 
				
			||||||
            .app_node;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if let Some(redirect) = db::check_pubsub_node(&self.db, app_node).await? {
 | 
					 | 
				
			||||||
            log::info!("redirect: {redirect}");
 | 
					 | 
				
			||||||
            return Err(redirect);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        info!("delete_app process starting for {:?}", req);
 | 
					        info!("delete_app process starting for {:?}", req);
 | 
				
			||||||
        match ActiveApp::delete(&self.db, &req.admin_pubkey, &req.uuid).await {
 | 
					        match ActiveApp::delete(&self.db, &req.admin_pubkey, &req.uuid).await {
 | 
				
			||||||
            Ok(()) => Ok(Response::new(Empty {})),
 | 
					            Ok(()) => Ok(Response::new(Empty {})),
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::db::prelude as db;
 | 
					use crate::db::prelude as db;
 | 
				
			||||||
use crate::grpc::{check_admin_key, check_sig_from_req};
 | 
					use crate::grpc::{check_admin_key, check_sig_from_req};
 | 
				
			||||||
use detee_shared::app_proto::AppContract;
 | 
					use detee_shared::app_proto::AppContract;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub mod app;
 | 
					pub mod app;
 | 
				
			||||||
pub mod general;
 | 
					pub mod general;
 | 
				
			||||||
pub mod types;
 | 
					pub mod types;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::constants::{ACCOUNT, APP_NODE, ID_ALPHABET, NEW_APP_REQ, NEW_VM_REQ, VM_NODE};
 | 
					use crate::constants::{ACCOUNT, APP_NODE, ID_ALPHABET, NEW_APP_REQ, NEW_VM_REQ, VM_NODE};
 | 
				
			||||||
use crate::db::prelude as db;
 | 
					use crate::db::prelude as db;
 | 
				
			||||||
use detee_shared::app_proto::AppNodeListResp;
 | 
					use detee_shared::app_proto::AppNodeListResp;
 | 
				
			||||||
@ -291,7 +289,7 @@ impl From<db::ActiveAppWithNode> for AppContract {
 | 
				
			|||||||
            nano_per_minute: value.price_per_unit,
 | 
					            nano_per_minute: value.price_per_unit,
 | 
				
			||||||
            locked_nano: value.locked_nano,
 | 
					            locked_nano: value.locked_nano,
 | 
				
			||||||
            collected_at: value.collected_at.to_rfc3339(),
 | 
					            collected_at: value.collected_at.to_rfc3339(),
 | 
				
			||||||
            hratls_pubkey: value.hratls_pubkey,
 | 
					            hratls_pubkey: value.mr_enclave,
 | 
				
			||||||
            public_package_mr_enclave,
 | 
					            public_package_mr_enclave,
 | 
				
			||||||
            app_name: value.app_name,
 | 
					            app_name: value.app_name,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -375,10 +373,10 @@ impl From<db::AppDaemonMsg> for BrainMessageApp {
 | 
				
			|||||||
impl From<AppNodeResources> for db::AppNodeResources {
 | 
					impl From<AppNodeResources> for db::AppNodeResources {
 | 
				
			||||||
    fn from(value: AppNodeResources) -> Self {
 | 
					    fn from(value: AppNodeResources) -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            avail_ports: value.avail_no_of_port,
 | 
					            avail_no_of_port: value.avail_no_of_port,
 | 
				
			||||||
            avail_vcpus: value.avail_vcpus,
 | 
					            avail_vcpus: value.avail_vcpus,
 | 
				
			||||||
            avail_mem_mb: value.avail_memory_mb,
 | 
					            avail_memory_mb: value.avail_memory_mb,
 | 
				
			||||||
            avail_storage_gbs: value.avail_storage_gb,
 | 
					            avail_storage_mb: value.avail_storage_mb,
 | 
				
			||||||
            max_ports_per_app: value.max_ports_per_app,
 | 
					            max_ports_per_app: value.max_ports_per_app,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,5 @@
 | 
				
			|||||||
#![allow(dead_code)]
 | 
					#![allow(dead_code)]
 | 
				
			||||||
 | 
					use crate::constants::{ACCOUNT, NEW_VM_REQ, UPDATE_VM_REQ, VM_NODE};
 | 
				
			||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::constants::{ACCOUNT, DEFAULT_ENDPOINT, NEW_VM_REQ, UPDATE_VM_REQ, VM_NODE};
 | 
					 | 
				
			||||||
use crate::db::prelude as db;
 | 
					use crate::db::prelude as db;
 | 
				
			||||||
use crate::grpc::{check_sig_from_parts, check_sig_from_req};
 | 
					use crate::grpc::{check_sig_from_parts, check_sig_from_req};
 | 
				
			||||||
use detee_shared::common_proto::Empty;
 | 
					use detee_shared::common_proto::Empty;
 | 
				
			||||||
@ -44,8 +41,6 @@ impl BrainVmDaemon for VmDaemonServer {
 | 
				
			|||||||
        db::VmNode {
 | 
					        db::VmNode {
 | 
				
			||||||
            id: surrealdb::RecordId::from((VM_NODE, req.node_pubkey.clone())),
 | 
					            id: surrealdb::RecordId::from((VM_NODE, req.node_pubkey.clone())),
 | 
				
			||||||
            operator: surrealdb::RecordId::from((ACCOUNT, req.operator_wallet)),
 | 
					            operator: surrealdb::RecordId::from((ACCOUNT, req.operator_wallet)),
 | 
				
			||||||
            pub_sub_node: std::env::var("BRAIN_PUBLIC_ENDPOINT")
 | 
					 | 
				
			||||||
                .unwrap_or(DEFAULT_ENDPOINT.to_string()),
 | 
					 | 
				
			||||||
            country: req.country,
 | 
					            country: req.country,
 | 
				
			||||||
            region: req.region,
 | 
					            region: req.region,
 | 
				
			||||||
            city: req.city,
 | 
					            city: req.city,
 | 
				
			||||||
@ -227,12 +222,6 @@ impl BrainVmCli for VmCliServer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    async fn new_vm(&self, req: Request<NewVmReq>) -> Result<Response<NewVmResp>, Status> {
 | 
					    async fn new_vm(&self, req: Request<NewVmReq>) -> Result<Response<NewVmResp>, Status> {
 | 
				
			||||||
        let req = check_sig_from_req(req)?;
 | 
					        let req = check_sig_from_req(req)?;
 | 
				
			||||||
        let id = surrealdb::RecordId::from((VM_NODE, req.node_pubkey.clone()));
 | 
					 | 
				
			||||||
        if let Some(redirect) = db::check_pubsub_node(&self.db, id).await? {
 | 
					 | 
				
			||||||
            log::info!("redirect: {redirect}");
 | 
					 | 
				
			||||||
            return Err(redirect);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // TODO: make it atleast 1 hour
 | 
					        // TODO: make it atleast 1 hour
 | 
				
			||||||
        if req.locked_nano < 100 {
 | 
					        if req.locked_nano < 100 {
 | 
				
			||||||
            log::error!("locking lessthan 100 nano lps: {}", req.locked_nano);
 | 
					            log::error!("locking lessthan 100 nano lps: {}", req.locked_nano);
 | 
				
			||||||
@ -272,11 +261,6 @@ impl BrainVmCli for VmCliServer {
 | 
				
			|||||||
        info!("Update VM requested via CLI: {req:?}");
 | 
					        info!("Update VM requested via CLI: {req:?}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let db_req: db::UpdateVmReq = req.clone().into();
 | 
					        let db_req: db::UpdateVmReq = req.clone().into();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if let Some(redirect) = db::check_pubsub_node(&self.db, db_req.vm_node.clone()).await? {
 | 
					 | 
				
			||||||
            log::info!("redirect: {redirect}");
 | 
					 | 
				
			||||||
            return Err(redirect);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        let id = db_req.id.key().to_string();
 | 
					        let id = db_req.id.key().to_string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut hostname_changed = false;
 | 
					        let mut hostname_changed = false;
 | 
				
			||||||
@ -358,15 +342,6 @@ impl BrainVmCli for VmCliServer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    async fn delete_vm(&self, req: Request<DeleteVmReq>) -> Result<Response<Empty>, Status> {
 | 
					    async fn delete_vm(&self, req: Request<DeleteVmReq>) -> Result<Response<Empty>, Status> {
 | 
				
			||||||
        let req = check_sig_from_req(req)?;
 | 
					        let req = check_sig_from_req(req)?;
 | 
				
			||||||
        let vm_node = db::ActiveVm::get_by_uuid(&self.db, &req.uuid)
 | 
					 | 
				
			||||||
            .await?
 | 
					 | 
				
			||||||
            .ok_or(Status::permission_denied("Unauthorized"))?
 | 
					 | 
				
			||||||
            .vm_node;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if let Some(redirect) = db::check_pubsub_node(&self.db, vm_node).await? {
 | 
					 | 
				
			||||||
            log::info!("redirect: {redirect}");
 | 
					 | 
				
			||||||
            return Err(redirect);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        match db::ActiveVm::delete(&self.db, &req.admin_pubkey, &req.uuid).await {
 | 
					        match db::ActiveVm::delete(&self.db, &req.admin_pubkey, &req.uuid).await {
 | 
				
			||||||
            Ok(()) => Ok(Response::new(Empty {})),
 | 
					            Ok(()) => Ok(Response::new(Empty {})),
 | 
				
			||||||
            Err(db::Error::AccessDenied) => Err(Status::permission_denied("Unauthorized")),
 | 
					            Err(db::Error::AccessDenied) => Err(Status::permission_denied("Unauthorized")),
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub mod constants;
 | 
					pub mod constants;
 | 
				
			||||||
pub mod db;
 | 
					pub mod db;
 | 
				
			||||||
pub mod grpc;
 | 
					pub mod grpc;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: delete this file after migration0 gets executed
 | 
					// TODO: delete this file after migration0 gets executed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use chrono::Utc;
 | 
					use chrono::Utc;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,2 @@
 | 
				
			|||||||
<!--
 | 
					 | 
				
			||||||
SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
-->
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This is actually SurrealQL (`.surql`), but the files have the `.sql`
 | 
					This is actually SurrealQL (`.surql`), but the files have the `.sql`
 | 
				
			||||||
extension to enable syntax coloring.
 | 
					extension to enable syntax coloring.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,5 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
source /etc/detee/brain/config.ini
 | 
					source /etc/detee/brain/config.ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
surreal import \
 | 
					surreal import \
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
-- SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFINE FUNCTION OVERWRITE fn::vm_price_per_minute(
 | 
					DEFINE FUNCTION OVERWRITE fn::vm_price_per_minute(
 | 
				
			||||||
	$vm_id: record
 | 
						$vm_id: record
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
-- SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFINE TABLE account SCHEMAFULL;
 | 
					DEFINE TABLE account SCHEMAFULL;
 | 
				
			||||||
DEFINE FIELD balance ON TABLE account TYPE int DEFAULT 0;
 | 
					DEFINE FIELD balance ON TABLE account TYPE int DEFAULT 0;
 | 
				
			||||||
DEFINE FIELD tmp_locked ON TABLE account TYPE int DEFAULT 0;
 | 
					DEFINE FIELD tmp_locked ON TABLE account TYPE int DEFAULT 0;
 | 
				
			||||||
@ -8,7 +6,6 @@ DEFINE FIELD email ON TABLE account TYPE string DEFAULT "";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DEFINE TABLE vm_node SCHEMAFULL;
 | 
					DEFINE TABLE vm_node SCHEMAFULL;
 | 
				
			||||||
DEFINE FIELD operator ON TABLE vm_node TYPE record<account>;
 | 
					DEFINE FIELD operator ON TABLE vm_node TYPE record<account>;
 | 
				
			||||||
DEFINE FIELD pub_sub_node ON TABLE vm_node TYPE string default "127.0.0.1:31337";
 | 
					 | 
				
			||||||
DEFINE FIELD country ON TABLE vm_node TYPE string;
 | 
					DEFINE FIELD country ON TABLE vm_node TYPE string;
 | 
				
			||||||
DEFINE FIELD region ON TABLE vm_node TYPE string;
 | 
					DEFINE FIELD region ON TABLE vm_node TYPE string;
 | 
				
			||||||
DEFINE FIELD city ON TABLE vm_node TYPE string;
 | 
					DEFINE FIELD city ON TABLE vm_node TYPE string;
 | 
				
			||||||
@ -83,7 +80,6 @@ DEFINE FIELD price_per_unit ON TABLE deleted_vm TYPE int;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DEFINE TABLE app_node SCHEMAFULL;
 | 
					DEFINE TABLE app_node SCHEMAFULL;
 | 
				
			||||||
DEFINE FIELD operator ON TABLE app_node TYPE record<account>;
 | 
					DEFINE FIELD operator ON TABLE app_node TYPE record<account>;
 | 
				
			||||||
DEFINE FIELD pub_sub_node ON TABLE app_node TYPE string default "127.0.0.1:31337";
 | 
					 | 
				
			||||||
DEFINE FIELD country ON TABLE app_node TYPE string;
 | 
					DEFINE FIELD country ON TABLE app_node TYPE string;
 | 
				
			||||||
DEFINE FIELD region ON TABLE app_node TYPE string;
 | 
					DEFINE FIELD region ON TABLE app_node TYPE string;
 | 
				
			||||||
DEFINE FIELD city ON TABLE app_node TYPE string;
 | 
					DEFINE FIELD city ON TABLE app_node TYPE string;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
-- SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
INSERT {
 | 
					INSERT {
 | 
				
			||||||
	id: vm_node:online_node,
 | 
						id: vm_node:online_node,
 | 
				
			||||||
	avail_ipv4: 0,
 | 
						avail_ipv4: 0,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,4 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					 | 
				
			||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"
 | 
					cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"
 | 
				
			||||||
import="docker run -i --rm --net=host \
 | 
					import="docker run -i --rm --net=host \
 | 
				
			||||||
  --volume "$(pwd)/../:/opt/scripts/" \
 | 
					  --volume "$(pwd)/../:/opt/scripts/" \
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
-- SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (select balance from account:operator1)[0].balance != 15_000_000_000 {
 | 
					if (select balance from account:operator1)[0].balance != 15_000_000_000 {
 | 
				
			||||||
    throw("Operator 1 did't get paid for serving a VM.")
 | 
					    throw("Operator 1 did't get paid for serving a VM.")
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
-- SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FOR $contract IN (select * from active_vm fetch out) {
 | 
					FOR $contract IN (select * from active_vm fetch out) {
 | 
				
			||||||
    LET $operator = (select * from $contract.out.operator)[0];
 | 
					    LET $operator = (select * from $contract.out.operator)[0];
 | 
				
			||||||
    LET $node_is_online = $contract.out.connected_at > $contract.out.disconnected_at;
 | 
					    LET $node_is_online = $contract.out.connected_at > $contract.out.disconnected_at;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use anyhow::Result;
 | 
					use anyhow::Result;
 | 
				
			||||||
use detee_shared::app_proto::{
 | 
					use detee_shared::app_proto::{
 | 
				
			||||||
    brain_app_cli_client::BrainAppCliClient, AppResource, NewAppReq, NewAppRes,
 | 
					    brain_app_cli_client::BrainAppCliClient, AppResource, NewAppReq, NewAppRes,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use super::test_utils::Key;
 | 
					 | 
				
			||||||
use crate::common::test_utils::{generate_random_public_ip, get_ip_info};
 | 
					 | 
				
			||||||
use anyhow::Result;
 | 
					use anyhow::Result;
 | 
				
			||||||
use detee_shared::app_proto::brain_app_daemon_client::BrainAppDaemonClient;
 | 
					use detee_shared::app_proto::brain_app_daemon_client::BrainAppDaemonClient;
 | 
				
			||||||
use detee_shared::app_proto::{self, NewAppRes, RegisterAppNodeReq};
 | 
					use detee_shared::app_proto::{self, NewAppRes, RegisterAppNodeReq};
 | 
				
			||||||
@ -11,6 +7,8 @@ use tokio::sync::mpsc;
 | 
				
			|||||||
use tokio_stream::wrappers::ReceiverStream;
 | 
					use tokio_stream::wrappers::ReceiverStream;
 | 
				
			||||||
use tonic::transport::Channel;
 | 
					use tonic::transport::Channel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::test_utils::Key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn mock_app_daemon(
 | 
					pub async fn mock_app_daemon(
 | 
				
			||||||
    brain_channel: &Channel,
 | 
					    brain_channel: &Channel,
 | 
				
			||||||
    daemon_error: Option<String>,
 | 
					    daemon_error: Option<String>,
 | 
				
			||||||
@ -47,16 +45,13 @@ pub async fn register_app_node(
 | 
				
			|||||||
    log::info!("Registering app_node: {}", key.pubkey);
 | 
					    log::info!("Registering app_node: {}", key.pubkey);
 | 
				
			||||||
    let node_pubkey = key.pubkey.clone();
 | 
					    let node_pubkey = key.pubkey.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let ip = generate_random_public_ip().to_string();
 | 
					 | 
				
			||||||
    let ip_info = get_ip_info(&ip).await?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let req = RegisterAppNodeReq {
 | 
					    let req = RegisterAppNodeReq {
 | 
				
			||||||
        node_pubkey,
 | 
					        node_pubkey,
 | 
				
			||||||
        operator_wallet: operator_wallet.to_string(),
 | 
					        operator_wallet: operator_wallet.to_string(),
 | 
				
			||||||
        main_ip: ip_info.ip,
 | 
					        main_ip: String::from("185.243.218.213"),
 | 
				
			||||||
        city: ip_info.city,
 | 
					        city: String::from("Oslo"),
 | 
				
			||||||
        country: ip_info.country,
 | 
					        country: String::from("Norway"),
 | 
				
			||||||
        region: ip_info.region,
 | 
					        region: String::from("EU"),
 | 
				
			||||||
        price: 1200,
 | 
					        price: 1200,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -139,7 +134,7 @@ pub async fn daemon_engine(
 | 
				
			|||||||
                tx.send(res).await?;
 | 
					                tx.send(res).await?;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Some(app_proto::brain_message_app::Msg::DeleteAppReq(del_app_req)) => {
 | 
					            Some(app_proto::brain_message_app::Msg::DeleteAppReq(del_app_req)) => {
 | 
				
			||||||
                println!("MOCK_APP_DAEMON::delete app request for {}", del_app_req.uuid);
 | 
					                println!("MOCK_APP_DAEMON:: delete app request for {}", del_app_req.uuid);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            None => todo!(),
 | 
					            None => todo!(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[allow(dead_code)]
 | 
					#[allow(dead_code)]
 | 
				
			||||||
pub mod prepare_test_env;
 | 
					pub mod prepare_test_env;
 | 
				
			||||||
#[allow(dead_code)]
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use anyhow::Result;
 | 
					use anyhow::Result;
 | 
				
			||||||
use detee_shared::app_proto::brain_app_cli_server::BrainAppCliServer;
 | 
					use detee_shared::app_proto::brain_app_cli_server::BrainAppCliServer;
 | 
				
			||||||
use detee_shared::app_proto::brain_app_daemon_server::BrainAppDaemonServer;
 | 
					use detee_shared::app_proto::brain_app_daemon_server::BrainAppDaemonServer;
 | 
				
			||||||
@ -8,6 +6,7 @@ use detee_shared::vm_proto::brain_vm_cli_server::BrainVmCliServer;
 | 
				
			|||||||
use detee_shared::vm_proto::brain_vm_daemon_server::BrainVmDaemonServer;
 | 
					use detee_shared::vm_proto::brain_vm_daemon_server::BrainVmDaemonServer;
 | 
				
			||||||
use dotenv::dotenv;
 | 
					use dotenv::dotenv;
 | 
				
			||||||
use hyper_util::rt::TokioIo;
 | 
					use hyper_util::rt::TokioIo;
 | 
				
			||||||
 | 
					use std::net::SocketAddr;
 | 
				
			||||||
use std::sync::Arc;
 | 
					use std::sync::Arc;
 | 
				
			||||||
use surreal_brain::constants::DB_SCHEMA_FILES;
 | 
					use surreal_brain::constants::DB_SCHEMA_FILES;
 | 
				
			||||||
use surreal_brain::grpc::app::{AppCliServer, AppDaemonServer};
 | 
					use surreal_brain::grpc::app::{AppCliServer, AppDaemonServer};
 | 
				
			||||||
@ -16,8 +15,9 @@ use surreal_brain::grpc::vm::{VmCliServer, VmDaemonServer};
 | 
				
			|||||||
use surrealdb::engine::remote::ws::Client;
 | 
					use surrealdb::engine::remote::ws::Client;
 | 
				
			||||||
use surrealdb::Surreal;
 | 
					use surrealdb::Surreal;
 | 
				
			||||||
use tokio::io::DuplexStream;
 | 
					use tokio::io::DuplexStream;
 | 
				
			||||||
 | 
					use tokio::net::TcpListener;
 | 
				
			||||||
use tokio::sync::OnceCell;
 | 
					use tokio::sync::OnceCell;
 | 
				
			||||||
use tonic::transport::{Channel, Endpoint, Uri};
 | 
					use tonic::transport::{Channel, Endpoint, Server, Uri};
 | 
				
			||||||
use tower::service_fn;
 | 
					use tower::service_fn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub static DB_STATE: OnceCell<Result<()>> = OnceCell::const_new();
 | 
					pub static DB_STATE: OnceCell<Result<()>> = OnceCell::const_new();
 | 
				
			||||||
@ -29,7 +29,7 @@ pub async fn prepare_test_db() -> Result<Surreal<Client>> {
 | 
				
			|||||||
    let db_user = std::env::var("DB_USER").expect("DB_USER not set in .env");
 | 
					    let db_user = std::env::var("DB_USER").expect("DB_USER not set in .env");
 | 
				
			||||||
    let db_pass = std::env::var("DB_PASS").expect("DB_PASS not set in .env");
 | 
					    let db_pass = std::env::var("DB_PASS").expect("DB_PASS not set in .env");
 | 
				
			||||||
    let db_ns = "test_brain";
 | 
					    let db_ns = "test_brain";
 | 
				
			||||||
    let db_name = "test_brain_db";
 | 
					    let db_name = "test_migration_db";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let db = surreal_brain::db::db_connection(&db_url, &db_user, &db_pass, db_ns, db_name).await?;
 | 
					    let db = surreal_brain::db::db_connection(&db_url, &db_user, &db_pass, db_ns, db_name).await?;
 | 
				
			||||||
    DB_STATE
 | 
					    DB_STATE
 | 
				
			||||||
@ -49,6 +49,37 @@ pub async fn prepare_test_db() -> Result<Surreal<Client>> {
 | 
				
			|||||||
    Ok(db)
 | 
					    Ok(db)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn run_service_in_background() -> Result<SocketAddr> {
 | 
				
			||||||
 | 
					    dotenv().ok();
 | 
				
			||||||
 | 
					    let listener = TcpListener::bind("127.0.0.1:0").await?;
 | 
				
			||||||
 | 
					    let addr = listener.local_addr()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let db_url = std::env::var("DB_URL").expect("DB_URL not set in .env");
 | 
				
			||||||
 | 
					    let db_user = std::env::var("DB_USER").expect("DB_USER not set in .env");
 | 
				
			||||||
 | 
					    let db_pass = std::env::var("DB_PASS").expect("DB_PASS not set in .env");
 | 
				
			||||||
 | 
					    let db_ns = "test_brain";
 | 
				
			||||||
 | 
					    let db_name = "test_migration_db";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        let db =
 | 
				
			||||||
 | 
					            surreal_brain::db::db_connection(&db_url, &db_user, &db_pass, db_ns, db_name).await?;
 | 
				
			||||||
 | 
					        let db_arc = Arc::new(db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Server::builder()
 | 
				
			||||||
 | 
					            .add_service(BrainGeneralCliServer::new(GeneralCliServer::new(db_arc.clone())))
 | 
				
			||||||
 | 
					            .add_service(BrainVmCliServer::new(VmCliServer::new(db_arc.clone())))
 | 
				
			||||||
 | 
					            .add_service(BrainVmDaemonServer::new(VmDaemonServer::new(db_arc.clone())))
 | 
				
			||||||
 | 
					            .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener))
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok::<(), anyhow::Error>(())
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tokio::time::sleep(tokio::time::Duration::from_millis(300)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(addr)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn run_service_for_stream_server() -> DuplexStream {
 | 
					pub async fn run_service_for_stream_server() -> DuplexStream {
 | 
				
			||||||
    dotenv().ok();
 | 
					    dotenv().ok();
 | 
				
			||||||
    let (client, server) = tokio::io::duplex(1024);
 | 
					    let (client, server) = tokio::io::duplex(1024);
 | 
				
			||||||
@ -57,7 +88,7 @@ pub async fn run_service_for_stream_server() -> DuplexStream {
 | 
				
			|||||||
    let db_user = std::env::var("DB_USER").expect("DB_USER not set in .env");
 | 
					    let db_user = std::env::var("DB_USER").expect("DB_USER not set in .env");
 | 
				
			||||||
    let db_pass = std::env::var("DB_PASS").expect("DB_PASS not set in .env");
 | 
					    let db_pass = std::env::var("DB_PASS").expect("DB_PASS not set in .env");
 | 
				
			||||||
    let db_ns = "test_brain";
 | 
					    let db_ns = "test_brain";
 | 
				
			||||||
    let db_name = "test_brain_db";
 | 
					    let db_name = "test_migration_db";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tokio::spawn(async move {
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
        let db =
 | 
					        let db =
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use anyhow::Result;
 | 
					use anyhow::Result;
 | 
				
			||||||
use detee_shared::app_proto as sgx_proto;
 | 
					use detee_shared::app_proto as sgx_proto;
 | 
				
			||||||
use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient;
 | 
					use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient;
 | 
				
			||||||
@ -7,8 +5,6 @@ use detee_shared::general_proto::AirdropReq;
 | 
				
			|||||||
use detee_shared::vm_proto as snp_proto;
 | 
					use detee_shared::vm_proto as snp_proto;
 | 
				
			||||||
use ed25519_dalek::{Signer, SigningKey};
 | 
					use ed25519_dalek::{Signer, SigningKey};
 | 
				
			||||||
use itertools::Itertools;
 | 
					use itertools::Itertools;
 | 
				
			||||||
use rand::Rng;
 | 
					 | 
				
			||||||
use std::net::Ipv4Addr;
 | 
					 | 
				
			||||||
use std::sync::OnceLock;
 | 
					use std::sync::OnceLock;
 | 
				
			||||||
use surreal_brain::constants::TOKEN_DECIMAL;
 | 
					use surreal_brain::constants::TOKEN_DECIMAL;
 | 
				
			||||||
use tonic::metadata::AsciiMetadataValue;
 | 
					use tonic::metadata::AsciiMetadataValue;
 | 
				
			||||||
@ -102,35 +98,3 @@ pub async fn airdrop(brain_channel: &Channel, wallet: &str, amount: u64) -> Resu
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
pub async fn get_ip_info(ip: &str) -> anyhow::Result<IPInfo> {
 | 
					 | 
				
			||||||
    let body = reqwest::get(format!("https://ipinfo.io/{ip}")).await?.text().await?;
 | 
					 | 
				
			||||||
    log::info!("Got the following data from ipinfo.io: {body}");
 | 
					 | 
				
			||||||
    Ok(serde_json::de::from_str(&body)?)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(serde::Deserialize, Clone, Debug)]
 | 
					 | 
				
			||||||
pub struct IPInfo {
 | 
					 | 
				
			||||||
    pub country: String,
 | 
					 | 
				
			||||||
    pub region: String,
 | 
					 | 
				
			||||||
    pub city: String,
 | 
					 | 
				
			||||||
    pub ip: String,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn generate_random_public_ip() -> Ipv4Addr {
 | 
					 | 
				
			||||||
    let mut rng = rand::thread_rng();
 | 
					 | 
				
			||||||
    loop {
 | 
					 | 
				
			||||||
        let ip = Ipv4Addr::from(rng.gen::<u32>());
 | 
					 | 
				
			||||||
        if !ip.is_private()
 | 
					 | 
				
			||||||
            && !ip.is_loopback()
 | 
					 | 
				
			||||||
            && !ip.is_link_local()
 | 
					 | 
				
			||||||
            && !ip.is_broadcast()
 | 
					 | 
				
			||||||
            && !ip.is_documentation()
 | 
					 | 
				
			||||||
            && !ip.is_unspecified()
 | 
					 | 
				
			||||||
            && !ip.is_multicast()
 | 
					 | 
				
			||||||
            && ip.octets()[0] < 240
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return ip;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use super::test_utils::Key;
 | 
					use super::test_utils::Key;
 | 
				
			||||||
use anyhow::{anyhow, Result};
 | 
					use anyhow::{anyhow, Result};
 | 
				
			||||||
use detee_shared::app_proto;
 | 
					use detee_shared::app_proto;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,4 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use super::test_utils::Key;
 | 
					use super::test_utils::Key;
 | 
				
			||||||
use crate::common::test_utils::{generate_random_public_ip, get_ip_info};
 | 
					 | 
				
			||||||
use anyhow::Result;
 | 
					use anyhow::Result;
 | 
				
			||||||
use detee_shared::vm_proto;
 | 
					use detee_shared::vm_proto;
 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
 | 
					use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
 | 
				
			||||||
@ -47,16 +44,13 @@ pub async fn register_vm_node(
 | 
				
			|||||||
    log::info!("Registering vm_node: {}", key.pubkey);
 | 
					    log::info!("Registering vm_node: {}", key.pubkey);
 | 
				
			||||||
    let node_pubkey = key.pubkey.clone();
 | 
					    let node_pubkey = key.pubkey.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let ip = generate_random_public_ip().to_string();
 | 
					 | 
				
			||||||
    let ip_info = get_ip_info(&ip).await?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let req = RegisterVmNodeReq {
 | 
					    let req = RegisterVmNodeReq {
 | 
				
			||||||
        node_pubkey,
 | 
					        node_pubkey,
 | 
				
			||||||
        operator_wallet: operator_wallet.to_string(),
 | 
					        operator_wallet: operator_wallet.to_string(),
 | 
				
			||||||
        main_ip: ip_info.ip,
 | 
					        main_ip: String::from("185.243.218.213"),
 | 
				
			||||||
        city: ip_info.city,
 | 
					        city: String::from("Oslo"),
 | 
				
			||||||
        country: ip_info.country,
 | 
					        country: String::from("Norway"),
 | 
				
			||||||
        region: ip_info.region,
 | 
					        region: String::from("EU"),
 | 
				
			||||||
        price: 1200,
 | 
					        price: 1200,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -143,7 +137,7 @@ pub async fn daemon_engine(
 | 
				
			|||||||
                todo!()
 | 
					                todo!()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Some(vm_proto::brain_vm_message::Msg::DeleteVm(del_vm_req)) => {
 | 
					            Some(vm_proto::brain_vm_message::Msg::DeleteVm(del_vm_req)) => {
 | 
				
			||||||
                println!("MOCK_VM_DAEMON::delete vm request for {}", del_vm_req.uuid);
 | 
					                println!("MOCK_VM_DAEMON:: delete vm request for {}", del_vm_req.uuid);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            None => todo!(),
 | 
					            None => todo!(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,35 +0,0 @@
 | 
				
			|||||||
use common::prepare_test_env::prepare_test_db;
 | 
					 | 
				
			||||||
use detee_shared::app_proto::{AppResource, NewAppReq};
 | 
					 | 
				
			||||||
use surreal_brain::db::prelude as db;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mod common;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[tokio::test]
 | 
					 | 
				
			||||||
async fn test_new_app_db_tx() {
 | 
					 | 
				
			||||||
    let db = prepare_test_db().await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let req = NewAppReq {
 | 
					 | 
				
			||||||
      package_url: "https://registry.detee.ltd/sgx/packages/actix-app-info_package_2025-04-16_21-59-38.tar.gz".to_string(),
 | 
					 | 
				
			||||||
      node_pubkey: "AH3SpV6ZjXMGSSe6xGH2ekUZxyUhnesAFz4LjX7PnvVn".to_string(),
 | 
					 | 
				
			||||||
      resource: Some(
 | 
					 | 
				
			||||||
          AppResource {
 | 
					 | 
				
			||||||
              memory_mb: 1500,
 | 
					 | 
				
			||||||
              disk_size_gb: 2,
 | 
					 | 
				
			||||||
              vcpus: 1,
 | 
					 | 
				
			||||||
              ports: vec![ 8080 ],
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
      uuid: "".to_string(),
 | 
					 | 
				
			||||||
      admin_pubkey: "H21Shi4iE7vgfjWEQNvzmpmBMJSaiZ17PYUcdNoAoKNc".to_string(),
 | 
					 | 
				
			||||||
      price_per_unit: 200000,
 | 
					 | 
				
			||||||
      locked_nano: 152400000,
 | 
					 | 
				
			||||||
      hratls_pubkey: "7E0F887AA6BB9104EEC1066F454D4C2D9063D676715F55F919D3FBCEDC63240B".to_string(),
 | 
					 | 
				
			||||||
      public_package_mr_enclave: Some(
 | 
					 | 
				
			||||||
          vec![ 128, 0, 97, 103, 165, 103, 68, 203, 240, 145, 153, 254, 34, 129, 75, 140, 8, 186, 63, 226, 144, 129, 201, 187, 175, 66, 80, 1, 151, 114, 183, 159, ],
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
      app_name: "lively-ferret".to_string(),
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let db_req: db::NewAppReq = req.into();
 | 
					 | 
				
			||||||
    db_req.submit(&db).await.unwrap();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,20 +1,13 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use common::app_daemon_utils::mock_app_daemon;
 | 
					use common::app_daemon_utils::mock_app_daemon;
 | 
				
			||||||
use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
 | 
					use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
 | 
				
			||||||
use common::test_utils::{airdrop, Key};
 | 
					use common::test_utils::{airdrop, Key};
 | 
				
			||||||
use detee_shared::app_proto::brain_app_cli_client::BrainAppCliClient;
 | 
					use detee_shared::app_proto::brain_app_cli_client::BrainAppCliClient;
 | 
				
			||||||
use detee_shared::app_proto::brain_app_daemon_client::BrainAppDaemonClient;
 | 
					use detee_shared::app_proto::{self, DelAppReq};
 | 
				
			||||||
use detee_shared::app_proto::{self, AppNodeFilters, DelAppReq};
 | 
					 | 
				
			||||||
use std::vec;
 | 
					use std::vec;
 | 
				
			||||||
use surreal_brain::constants::{
 | 
					use surreal_brain::constants::{ACCOUNT, ACTIVE_APP, DELETED_APP, NEW_APP_REQ, TOKEN_DECIMAL};
 | 
				
			||||||
    ACCOUNT, ACTIVE_APP, APP_NODE, DELETED_APP, NEW_APP_REQ, TOKEN_DECIMAL,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
use surreal_brain::db::app::AppNode;
 | 
					 | 
				
			||||||
use surreal_brain::db::prelude as db;
 | 
					use surreal_brain::db::prelude as db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::common::app_cli_utils::create_new_app;
 | 
					use crate::common::app_cli_utils::create_new_app;
 | 
				
			||||||
use crate::common::app_daemon_utils::register_app_node;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod common;
 | 
					mod common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -102,16 +95,13 @@ async fn test_app_creation() {
 | 
				
			|||||||
async fn test_timeout_app_creation() {
 | 
					async fn test_timeout_app_creation() {
 | 
				
			||||||
    let _ = prepare_test_db().await.unwrap();
 | 
					    let _ = prepare_test_db().await.unwrap();
 | 
				
			||||||
    let brain_channel = run_service_for_stream().await.unwrap();
 | 
					    let brain_channel = run_service_for_stream().await.unwrap();
 | 
				
			||||||
    let daemon_key = Key::new();
 | 
					    let daemon_key = Key::new().pubkey.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let key = Key::new();
 | 
					    let key = Key::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut daemon_client = BrainAppDaemonClient::new(brain_channel.clone());
 | 
					 | 
				
			||||||
    register_app_node(&mut daemon_client, &daemon_key, &Key::new().pubkey).await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let new_app_req = app_proto::NewAppReq {
 | 
					    let new_app_req = app_proto::NewAppReq {
 | 
				
			||||||
        admin_pubkey: key.pubkey.clone(),
 | 
					        admin_pubkey: key.pubkey.clone(),
 | 
				
			||||||
        node_pubkey: daemon_key.pubkey.clone(),
 | 
					        node_pubkey: daemon_key.clone(),
 | 
				
			||||||
        price_per_unit: 1200,
 | 
					        price_per_unit: 1200,
 | 
				
			||||||
        resource: Some(app_proto::AppResource { ports: vec![8080, 8081], ..Default::default() }),
 | 
					        resource: Some(app_proto::AppResource { ports: vec![8080, 8081], ..Default::default() }),
 | 
				
			||||||
        locked_nano: 100,
 | 
					        locked_nano: 100,
 | 
				
			||||||
@ -189,38 +179,4 @@ async fn test_app_deletion() {
 | 
				
			|||||||
    assert!(deleted_app.is_some());
 | 
					    assert!(deleted_app.is_some());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[tokio::test]
 | 
					 | 
				
			||||||
async fn test_get_one_app_node() {
 | 
					 | 
				
			||||||
    let db = prepare_test_db().await.unwrap();
 | 
					 | 
				
			||||||
    let brain_channel = run_service_for_stream().await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut client_app_cli = BrainAppCliClient::new(brain_channel.clone());
 | 
					 | 
				
			||||||
    let key = Key::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut req = AppNodeFilters { ..Default::default() };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mock_app_node = client_app_cli
 | 
					 | 
				
			||||||
        .get_one_app_node(key.sign_request(req.clone()).unwrap())
 | 
					 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
        .unwrap()
 | 
					 | 
				
			||||||
        .into_inner();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert_eq!(
 | 
					 | 
				
			||||||
        mock_app_node.node_pubkey,
 | 
					 | 
				
			||||||
        "BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg".to_string()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let node_pubkey = mock_app_daemon(&brain_channel, None).await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let new_node_ip =
 | 
					 | 
				
			||||||
        db.select::<Option<AppNode>>((APP_NODE, node_pubkey.clone())).await.unwrap().unwrap().ip;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    req.ip = new_node_ip;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let new_app_node =
 | 
					 | 
				
			||||||
        client_app_cli.get_one_app_node(key.sign_request(req).unwrap()).await.unwrap().into_inner();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert_eq!(new_app_node.node_pubkey, node_pubkey);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: test register app node, delete app contract while node offline, kick, etc..
 | 
					// TODO: test register app node, delete app contract while node offline, kick, etc..
 | 
				
			||||||
 | 
				
			|||||||
@ -1,139 +0,0 @@
 | 
				
			|||||||
use common::app_daemon_utils::{mock_app_daemon, register_app_node};
 | 
					 | 
				
			||||||
use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
 | 
					 | 
				
			||||||
use common::test_utils::{airdrop, Key};
 | 
					 | 
				
			||||||
use detee_shared::app_proto::brain_app_cli_client::BrainAppCliClient;
 | 
					 | 
				
			||||||
use detee_shared::app_proto::brain_app_daemon_client::BrainAppDaemonClient;
 | 
					 | 
				
			||||||
use detee_shared::app_proto::{self, AppNodeResources};
 | 
					 | 
				
			||||||
use surreal_brain::constants::APP_NODE;
 | 
					 | 
				
			||||||
use surreal_brain::db::app::AppNode;
 | 
					 | 
				
			||||||
use surreal_brain::db::prelude as db;
 | 
					 | 
				
			||||||
use tokio_stream::wrappers::ReceiverStream;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mod common;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: test app registration and resource handling
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[tokio::test]
 | 
					 | 
				
			||||||
async fn test_reg_app_node() {
 | 
					 | 
				
			||||||
    let db = prepare_test_db().await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let channel = run_service_for_stream().await.unwrap();
 | 
					 | 
				
			||||||
    let mut client = BrainAppDaemonClient::new(channel);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let node_key = Key::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let del_app_req = register_app_node(&mut client, &node_key, &Key::new().pubkey).await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert!(del_app_req.is_empty());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let app_node: Option<db::AppNode> = db.select((APP_NODE, node_key.pubkey)).await.unwrap();
 | 
					 | 
				
			||||||
    assert!(app_node.is_some());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[tokio::test]
 | 
					 | 
				
			||||||
async fn test_brain_message() {
 | 
					 | 
				
			||||||
    env_logger::builder().filter_level(log::LevelFilter::Error).init();
 | 
					 | 
				
			||||||
    let _ = prepare_test_db().await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let brain_channel = run_service_for_stream().await.unwrap();
 | 
					 | 
				
			||||||
    let daemon_key = mock_app_daemon(&brain_channel, None).await.unwrap();
 | 
					 | 
				
			||||||
    let mut cli_client = BrainAppCliClient::new(brain_channel.clone());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let cli_key = Key::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let req = app_proto::NewAppReq {
 | 
					 | 
				
			||||||
        admin_pubkey: cli_key.pubkey.clone(),
 | 
					 | 
				
			||||||
        node_pubkey: daemon_key,
 | 
					 | 
				
			||||||
        price_per_unit: 1200,
 | 
					 | 
				
			||||||
        // extra_ports: vec![8080, 8081],
 | 
					 | 
				
			||||||
        locked_nano: 100,
 | 
					 | 
				
			||||||
        ..Default::default()
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    airdrop(&brain_channel, &cli_key.pubkey, 10).await.unwrap();
 | 
					 | 
				
			||||||
    let new_app_resp =
 | 
					 | 
				
			||||||
        cli_client.new_app(cli_key.sign_request(req).unwrap()).await.unwrap().into_inner();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert!(new_app_resp.error.is_empty());
 | 
					 | 
				
			||||||
    assert!(new_app_resp.uuid.len() == 40);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[tokio::test]
 | 
					 | 
				
			||||||
async fn test_app_daemon_resource_msg() {
 | 
					 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
    env_logger::builder()
 | 
					 | 
				
			||||||
        .filter_level(log::LevelFilter::Trace)
 | 
					 | 
				
			||||||
        .filter_module("tungstenite", log::LevelFilter::Debug)
 | 
					 | 
				
			||||||
        .filter_module("tokio_tungstenite", log::LevelFilter::Debug)
 | 
					 | 
				
			||||||
        .init();
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let db = prepare_test_db().await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let brain_channel = run_service_for_stream().await.unwrap();
 | 
					 | 
				
			||||||
    let mut daemon_client = BrainAppDaemonClient::new(brain_channel);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let daemon_key = Key::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    register_app_node(&mut daemon_client, &daemon_key, &Key::new().pubkey).await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let (tx, rx) = tokio::sync::mpsc::channel(32);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let tx_01 = tx.clone();
 | 
					 | 
				
			||||||
    let daemon_key_01 = daemon_key.clone();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tokio::spawn(async move {
 | 
					 | 
				
			||||||
        tx_01
 | 
					 | 
				
			||||||
            .send(app_proto::DaemonMessageApp {
 | 
					 | 
				
			||||||
                msg: Some(app_proto::daemon_message_app::Msg::Auth(
 | 
					 | 
				
			||||||
                    daemon_key_01.clone().sign_stream_auth_app(vec![]).unwrap(),
 | 
					 | 
				
			||||||
                )),
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .await
 | 
					 | 
				
			||||||
            .unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let rx_stream = ReceiverStream::new(rx);
 | 
					 | 
				
			||||||
        daemon_client.daemon_messages(rx_stream).await.unwrap();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let tx_02 = tx.clone();
 | 
					 | 
				
			||||||
    let daemon_pubkey = daemon_key.clone().pubkey;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let req_data = AppNodeResources {
 | 
					 | 
				
			||||||
        node_pubkey: daemon_pubkey,
 | 
					 | 
				
			||||||
        avail_no_of_port: 5,
 | 
					 | 
				
			||||||
        avail_vcpus: 4,
 | 
					 | 
				
			||||||
        avail_memory_mb: 8192,
 | 
					 | 
				
			||||||
        avail_storage_gb: 100,
 | 
					 | 
				
			||||||
        max_ports_per_app: 5,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let req_data_copy = req_data.clone();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tokio::spawn(async move {
 | 
					 | 
				
			||||||
        tx_02
 | 
					 | 
				
			||||||
            .send(app_proto::DaemonMessageApp {
 | 
					 | 
				
			||||||
                msg: Some(app_proto::daemon_message_app::Msg::AppNodeResources(req_data_copy)),
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .await
 | 
					 | 
				
			||||||
            .unwrap();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let app_node_opt: Option<AppNode> = db.select((APP_NODE, daemon_key.pubkey)).await.unwrap();
 | 
					 | 
				
			||||||
    assert!(app_node_opt.is_some());
 | 
					 | 
				
			||||||
    let db::AppNode {
 | 
					 | 
				
			||||||
        avail_mem_mb,
 | 
					 | 
				
			||||||
        avail_vcpus,
 | 
					 | 
				
			||||||
        avail_storage_gbs,
 | 
					 | 
				
			||||||
        avail_ports,
 | 
					 | 
				
			||||||
        max_ports_per_app,
 | 
					 | 
				
			||||||
        ..
 | 
					 | 
				
			||||||
    } = app_node_opt.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert_eq!(avail_mem_mb, req_data.avail_memory_mb);
 | 
					 | 
				
			||||||
    assert_eq!(avail_vcpus, req_data.avail_vcpus);
 | 
					 | 
				
			||||||
    assert_eq!(avail_storage_gbs, req_data.avail_storage_gb);
 | 
					 | 
				
			||||||
    assert_eq!(avail_ports, req_data.avail_no_of_port);
 | 
					 | 
				
			||||||
    assert_eq!(max_ports_per_app, req_data.max_ports_per_app);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					use common::prepare_test_env::{
 | 
				
			||||||
 | 
					    prepare_test_db, run_service_for_stream, run_service_in_background,
 | 
				
			||||||
use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
 | 
					};
 | 
				
			||||||
use common::test_utils::{admin_keys, airdrop, Key};
 | 
					use common::test_utils::{admin_keys, airdrop, Key};
 | 
				
			||||||
use common::vm_cli_utils::{
 | 
					use common::vm_cli_utils::{
 | 
				
			||||||
    create_new_vm, list_accounts, list_all_app_contracts, list_all_vm_contracts, register_operator,
 | 
					    create_new_vm, list_accounts, list_all_app_contracts, list_all_vm_contracts, register_operator,
 | 
				
			||||||
@ -20,17 +20,11 @@ mod common;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[tokio::test]
 | 
					#[tokio::test]
 | 
				
			||||||
async fn test_general_balance() {
 | 
					async fn test_general_balance() {
 | 
				
			||||||
    /*
 | 
					    // env_logger::builder().filter_level(log::LevelFilter::Trace).init();
 | 
				
			||||||
    env_logger::builder()
 | 
					 | 
				
			||||||
        .filter_level(log::LevelFilter::Info)
 | 
					 | 
				
			||||||
        .filter_module("tungstenite", log::LevelFilter::Debug)
 | 
					 | 
				
			||||||
        .filter_module("tokio_tungstenite", log::LevelFilter::Debug)
 | 
					 | 
				
			||||||
        .init();
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    prepare_test_db().await.unwrap();
 | 
					    prepare_test_db().await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let channel = run_service_for_stream().await.unwrap();
 | 
					    let addr = run_service_in_background().await.unwrap();
 | 
				
			||||||
    let mut client = BrainGeneralCliClient::new(channel);
 | 
					    let mut client = BrainGeneralCliClient::connect(format!("http://{}", addr)).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let key = Key::new();
 | 
					    let key = Key::new();
 | 
				
			||||||
    let pubkey = key.pubkey.clone();
 | 
					    let pubkey = key.pubkey.clone();
 | 
				
			||||||
@ -51,8 +45,8 @@ async fn test_general_airdrop() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let airdrop_amount = 10;
 | 
					    let airdrop_amount = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let channel = run_service_for_stream().await.unwrap();
 | 
					    let addr = run_service_in_background().await.unwrap();
 | 
				
			||||||
    let mut client = BrainGeneralCliClient::new(channel);
 | 
					    let mut client = BrainGeneralCliClient::connect(format!("http://{}", addr)).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let admin_keys = admin_keys();
 | 
					    let admin_keys = admin_keys();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,95 +0,0 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
 | 
					 | 
				
			||||||
use common::test_utils::{airdrop, Key};
 | 
					 | 
				
			||||||
use common::vm_daemon_utils::register_vm_node;
 | 
					 | 
				
			||||||
use detee_shared::app_proto;
 | 
					 | 
				
			||||||
use detee_shared::app_proto::brain_app_cli_client::BrainAppCliClient;
 | 
					 | 
				
			||||||
use detee_shared::app_proto::brain_app_daemon_client::BrainAppDaemonClient;
 | 
					 | 
				
			||||||
use detee_shared::vm_proto;
 | 
					 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
 | 
					 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::common::app_daemon_utils::register_app_node;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mod common;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[tokio::test]
 | 
					 | 
				
			||||||
async fn test_vm_pub_sub_redirect() {
 | 
					 | 
				
			||||||
    let _ = prepare_test_db().await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let brain_channel = run_service_for_stream().await.unwrap();
 | 
					 | 
				
			||||||
    let mut vm_daemon_client = BrainVmDaemonClient::new(brain_channel.clone());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let node_key = Key::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let pubsub_brain_endpoint = "192.168.1.1:31337";
 | 
					 | 
				
			||||||
    std::env::set_var("BRAIN_PUBLIC_ENDPOINT", pubsub_brain_endpoint);
 | 
					 | 
				
			||||||
    register_vm_node(&mut vm_daemon_client, &node_key, &Key::new().pubkey).await.unwrap();
 | 
					 | 
				
			||||||
    std::env::set_var("BRAIN_PUBLIC_ENDPOINT", "127.0.0.1:31337");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let client_key = Key::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let new_vm_req = vm_proto::NewVmReq {
 | 
					 | 
				
			||||||
        admin_pubkey: client_key.pubkey.clone(),
 | 
					 | 
				
			||||||
        node_pubkey: node_key.pubkey.clone(),
 | 
					 | 
				
			||||||
        price_per_unit: 1200,
 | 
					 | 
				
			||||||
        extra_ports: vec![8080, 8081],
 | 
					 | 
				
			||||||
        locked_nano: 100,
 | 
					 | 
				
			||||||
        ..Default::default()
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    airdrop(&brain_channel, &client_key.pubkey, 10).await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::env::set_var("BRAIN_PUBLIC_ENDPOINT", "10.0.0.1:31337");
 | 
					 | 
				
			||||||
    let mut client_vm_cli = BrainVmCliClient::new(brain_channel.clone());
 | 
					 | 
				
			||||||
    let redirect =
 | 
					 | 
				
			||||||
        client_vm_cli.new_vm(client_key.sign_request(new_vm_req).unwrap()).await.err().unwrap();
 | 
					 | 
				
			||||||
    std::env::set_var("BRAIN_PUBLIC_ENDPOINT", "127.0.0.1:31337");
 | 
					 | 
				
			||||||
    assert_eq!(redirect.code(), tonic::Code::Unavailable);
 | 
					 | 
				
			||||||
    let redirect_url =
 | 
					 | 
				
			||||||
        redirect.metadata().get("location").and_then(|v| v.to_str().ok()).unwrap_or_default();
 | 
					 | 
				
			||||||
    assert_eq!(redirect_url, pubsub_brain_endpoint);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[tokio::test]
 | 
					 | 
				
			||||||
async fn test_app_pub_sub_redirect() {
 | 
					 | 
				
			||||||
    let _ = prepare_test_db().await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let brain_channel = run_service_for_stream().await.unwrap();
 | 
					 | 
				
			||||||
    let mut app_daemon_client = BrainAppDaemonClient::new(brain_channel.clone());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let node_key = Key::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let pubsub_brain_endpoint = "192.168.1.1:31337";
 | 
					 | 
				
			||||||
    std::env::set_var("BRAIN_PUBLIC_ENDPOINT", pubsub_brain_endpoint);
 | 
					 | 
				
			||||||
    register_app_node(&mut app_daemon_client, &node_key, &Key::new().pubkey).await.unwrap();
 | 
					 | 
				
			||||||
    std::env::set_var("BRAIN_PUBLIC_ENDPOINT", "127.0.0.1:31337");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let client_key = Key::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let new_app_req = app_proto::NewAppReq {
 | 
					 | 
				
			||||||
        admin_pubkey: client_key.pubkey.clone(),
 | 
					 | 
				
			||||||
        node_pubkey: node_key.pubkey.clone(),
 | 
					 | 
				
			||||||
        price_per_unit: 1200,
 | 
					 | 
				
			||||||
        resource: Some(app_proto::AppResource { ports: vec![8080, 8081], ..Default::default() }),
 | 
					 | 
				
			||||||
        locked_nano: 100,
 | 
					 | 
				
			||||||
        ..Default::default()
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    airdrop(&brain_channel, &client_key.pubkey, 10).await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::env::set_var("BRAIN_PUBLIC_ENDPOINT", "10.0.0.1:31337");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut client_app_cli = BrainAppCliClient::new(brain_channel.clone());
 | 
					 | 
				
			||||||
    let redirect = client_app_cli
 | 
					 | 
				
			||||||
        .new_app(client_key.sign_request(new_app_req.clone()).unwrap())
 | 
					 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
        .err()
 | 
					 | 
				
			||||||
        .unwrap();
 | 
					 | 
				
			||||||
    std::env::set_var("BRAIN_PUBLIC_ENDPOINT", "127.0.0.1:31337");
 | 
					 | 
				
			||||||
    assert_eq!(redirect.code(), tonic::Code::Unavailable);
 | 
					 | 
				
			||||||
    let redirect_url =
 | 
					 | 
				
			||||||
        redirect.metadata().get("location").and_then(|v| v.to_str().ok()).unwrap_or_default();
 | 
					 | 
				
			||||||
    assert_eq!(redirect_url, pubsub_brain_endpoint);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,19 +1,14 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
 | 
					use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
 | 
				
			||||||
use common::test_utils::{airdrop, Key};
 | 
					use common::test_utils::{airdrop, Key};
 | 
				
			||||||
use common::vm_cli_utils::{create_new_vm, user_list_vm_contracts};
 | 
					use common::vm_cli_utils::{create_new_vm, user_list_vm_contracts};
 | 
				
			||||||
use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node};
 | 
					use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node};
 | 
				
			||||||
use detee_shared::vm_proto;
 | 
					 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
 | 
					use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
 | 
					use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
 | 
				
			||||||
use detee_shared::vm_proto::{
 | 
					use detee_shared::vm_proto::{self, DeleteVmReq};
 | 
				
			||||||
    DeleteVmReq, ExtendVmReq, ListVmContractsReq, NewVmReq, VmNodeFilters,
 | 
					use detee_shared::vm_proto::{ExtendVmReq, ListVmContractsReq, NewVmReq};
 | 
				
			||||||
};
 | 
					 | 
				
			||||||
use futures::StreamExt;
 | 
					use futures::StreamExt;
 | 
				
			||||||
use surreal_brain::constants::{
 | 
					use std::vec;
 | 
				
			||||||
    ACCOUNT, ACTIVE_VM, DELETED_VM, NEW_VM_REQ, TOKEN_DECIMAL, VM_NODE,
 | 
					use surreal_brain::constants::{ACCOUNT, ACTIVE_VM, DELETED_VM, NEW_VM_REQ, TOKEN_DECIMAL};
 | 
				
			||||||
};
 | 
					 | 
				
			||||||
use surreal_brain::db::prelude as db;
 | 
					use surreal_brain::db::prelude as db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod common;
 | 
					mod common;
 | 
				
			||||||
@ -305,42 +300,4 @@ async fn test_extend_vm() {
 | 
				
			|||||||
    assert_eq!(acc.balance, expected_bal_02);
 | 
					    assert_eq!(acc.balance, expected_bal_02);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[tokio::test]
 | 
					 | 
				
			||||||
async fn test_get_one_vm_node() {
 | 
					 | 
				
			||||||
    let db = prepare_test_db().await.unwrap();
 | 
					 | 
				
			||||||
    let brain_channel = run_service_for_stream().await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut client_vm_cli = BrainVmCliClient::new(brain_channel.clone());
 | 
					 | 
				
			||||||
    let key = Key::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut req = VmNodeFilters::default();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mock_vm_node = client_vm_cli
 | 
					 | 
				
			||||||
        .get_one_vm_node(key.sign_request(req.clone()).unwrap())
 | 
					 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
        .unwrap()
 | 
					 | 
				
			||||||
        .into_inner();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mock_data_vm_nodes = [
 | 
					 | 
				
			||||||
        "2Uf5pxhxKTUm6gRMnpbJHYDuyA6BWUfFsdmPyWfbMV1f",
 | 
					 | 
				
			||||||
        "3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4",
 | 
					 | 
				
			||||||
        "7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9",
 | 
					 | 
				
			||||||
        "DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb",
 | 
					 | 
				
			||||||
        "Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu",
 | 
					 | 
				
			||||||
        "HiyMp21zaBVbRCjDsD5hEjQnHeHv4e1gpUR6pVfHTKqv",
 | 
					 | 
				
			||||||
    ];
 | 
					 | 
				
			||||||
    assert!(mock_data_vm_nodes.contains(&mock_vm_node.node_pubkey.as_str()));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let node_pubkey = mock_vm_daemon(&brain_channel, None).await.unwrap();
 | 
					 | 
				
			||||||
    let new_node_ip =
 | 
					 | 
				
			||||||
        db.select::<Option<db::VmNode>>((VM_NODE, node_pubkey.clone())).await.unwrap().unwrap().ip;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    req.ip = new_node_ip;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let new_app_node =
 | 
					 | 
				
			||||||
        client_vm_cli.get_one_vm_node(key.sign_request(req).unwrap()).await.unwrap().into_inner();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert_eq!(new_app_node.node_pubkey, node_pubkey);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: test register vm node, delete vm contract while node offline, kick, etc..
 | 
					// TODO: test register vm node, delete vm contract while node offline, kick, etc..
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,11 @@
 | 
				
			|||||||
// SPDX-License-Identifier: Apache-2.0
 | 
					use common::prepare_test_env::{
 | 
				
			||||||
 | 
					    prepare_test_db, run_service_for_stream, run_service_in_background,
 | 
				
			||||||
use crate::common::test_utils::{airdrop, Key};
 | 
					};
 | 
				
			||||||
use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
 | 
					use common::test_utils::{airdrop, Key};
 | 
				
			||||||
use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node};
 | 
					use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node};
 | 
				
			||||||
use detee_shared::vm_proto;
 | 
					use detee_shared::vm_proto;
 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
 | 
					use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
 | 
				
			||||||
use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
 | 
					use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
 | 
				
			||||||
use surreal_brain::constants::VM_NODE;
 | 
					 | 
				
			||||||
use surreal_brain::db::prelude as db;
 | 
					 | 
				
			||||||
use tokio_stream::wrappers::ReceiverStream;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod common;
 | 
					mod common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -16,12 +13,13 @@ mod common;
 | 
				
			|||||||
async fn test_reg_vm_node() {
 | 
					async fn test_reg_vm_node() {
 | 
				
			||||||
    prepare_test_db().await.unwrap();
 | 
					    prepare_test_db().await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let channel = run_service_for_stream().await.unwrap();
 | 
					    let addr = run_service_in_background().await.unwrap();
 | 
				
			||||||
    let mut client = BrainVmDaemonClient::new(channel);
 | 
					    let mut client = BrainVmDaemonClient::connect(format!("http://{}", addr)).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let del_vm_reqs = register_vm_node(&mut client, &Key::new(), &Key::new().pubkey).await.unwrap();
 | 
					    let vm_contracts =
 | 
				
			||||||
 | 
					        register_vm_node(&mut client, &Key::new(), &Key::new().pubkey).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert!(del_vm_reqs.is_empty())
 | 
					    assert!(vm_contracts.is_empty())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[tokio::test]
 | 
					#[tokio::test]
 | 
				
			||||||
@ -52,83 +50,3 @@ async fn test_brain_message() {
 | 
				
			|||||||
    assert!(new_vm_resp.args.is_some());
 | 
					    assert!(new_vm_resp.args.is_some());
 | 
				
			||||||
    assert!(new_vm_resp.args.unwrap().exposed_ports.len() == 3);
 | 
					    assert!(new_vm_resp.args.unwrap().exposed_ports.len() == 3);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#[tokio::test]
 | 
					 | 
				
			||||||
async fn test_vm_daemon_resource_msg() {
 | 
					 | 
				
			||||||
    let db = prepare_test_db().await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let brain_channel = run_service_for_stream().await.unwrap();
 | 
					 | 
				
			||||||
    let mut daemon_client = BrainVmDaemonClient::new(brain_channel);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let daemon_key = Key::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    register_vm_node(&mut daemon_client, &daemon_key, &Key::new().pubkey).await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let (tx, rx) = tokio::sync::mpsc::channel(32);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let tx_01 = tx.clone();
 | 
					 | 
				
			||||||
    let daemon_key_01 = daemon_key.clone();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tokio::spawn(async move {
 | 
					 | 
				
			||||||
        tx_01
 | 
					 | 
				
			||||||
            .send(vm_proto::VmDaemonMessage {
 | 
					 | 
				
			||||||
                msg: Some(vm_proto::vm_daemon_message::Msg::Auth(
 | 
					 | 
				
			||||||
                    daemon_key_01.clone().sign_stream_auth_vm(vec![]).unwrap(),
 | 
					 | 
				
			||||||
                )),
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .await
 | 
					 | 
				
			||||||
            .unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let rx_stream = ReceiverStream::new(rx);
 | 
					 | 
				
			||||||
        daemon_client.daemon_messages(rx_stream).await.unwrap();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let tx_02 = tx.clone();
 | 
					 | 
				
			||||||
    let daemon_pubkey = daemon_key.clone().pubkey;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let req_data = vm_proto::VmNodeResources {
 | 
					 | 
				
			||||||
        node_pubkey: daemon_pubkey,
 | 
					 | 
				
			||||||
        avail_ports: 5,
 | 
					 | 
				
			||||||
        avail_ipv4: 2,
 | 
					 | 
				
			||||||
        avail_ipv6: 88,
 | 
					 | 
				
			||||||
        avail_vcpus: 4,
 | 
					 | 
				
			||||||
        avail_memory_mb: 8192,
 | 
					 | 
				
			||||||
        avail_storage_gb: 100,
 | 
					 | 
				
			||||||
        max_ports_per_vm: 5,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let req_data_copy = req_data.clone();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tokio::spawn(async move {
 | 
					 | 
				
			||||||
        tx_02
 | 
					 | 
				
			||||||
            .send(vm_proto::VmDaemonMessage {
 | 
					 | 
				
			||||||
                msg: Some(vm_proto::vm_daemon_message::Msg::VmNodeResources(req_data_copy)),
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .await
 | 
					 | 
				
			||||||
            .unwrap();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tokio::time::sleep(tokio::time::Duration::from_millis(300)).await;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let vm_node_opt: Option<db::VmNode> = db.select((VM_NODE, daemon_key.pubkey)).await.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert!(vm_node_opt.is_some());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let db::VmNode {
 | 
					 | 
				
			||||||
        avail_mem_mb,
 | 
					 | 
				
			||||||
        avail_vcpus,
 | 
					 | 
				
			||||||
        avail_storage_gbs,
 | 
					 | 
				
			||||||
        avail_ports,
 | 
					 | 
				
			||||||
        avail_ipv4,
 | 
					 | 
				
			||||||
        avail_ipv6,
 | 
					 | 
				
			||||||
        max_ports_per_vm,
 | 
					 | 
				
			||||||
        ..
 | 
					 | 
				
			||||||
    } = vm_node_opt.unwrap();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert_eq!(avail_mem_mb, req_data.avail_memory_mb);
 | 
					 | 
				
			||||||
    assert_eq!(avail_vcpus, req_data.avail_vcpus);
 | 
					 | 
				
			||||||
    assert_eq!(avail_storage_gbs, req_data.avail_storage_gb);
 | 
					 | 
				
			||||||
    assert_eq!(avail_ports, req_data.avail_ports);
 | 
					 | 
				
			||||||
    assert_eq!(avail_ipv4, req_data.avail_ipv4);
 | 
					 | 
				
			||||||
    assert_eq!(avail_ipv6, req_data.avail_ipv6);
 | 
					 | 
				
			||||||
    assert_eq!(max_ports_per_vm, req_data.max_ports_per_vm);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
accounts:
 | 
					accounts:
 | 
				
			||||||
  DXXkYSnhP3ijsHYxkedcuMomEyc122WaAbkDX7SaGuUS:
 | 
					  DXXkYSnhP3ijsHYxkedcuMomEyc122WaAbkDX7SaGuUS:
 | 
				
			||||||
    balance: 20293420000
 | 
					    balance: 20293420000
 | 
				
			||||||
@ -302,7 +300,7 @@ vm_nodes:
 | 
				
			|||||||
    max_ports_per_vm: 10
 | 
					    max_ports_per_vm: 10
 | 
				
			||||||
    price: 24000
 | 
					    price: 24000
 | 
				
			||||||
    reports: {}
 | 
					    reports: {}
 | 
				
			||||||
    offline_minutes: 1
 | 
					    offline_minutes: 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vm_contracts:
 | 
					vm_contracts:
 | 
				
			||||||
  - uuid: 958165e3-dea8-407d-8c42-dd17002ef79c
 | 
					  - uuid: 958165e3-dea8-407d-8c42-dd17002ef79c
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user