A local-first private AI assistant for everyday use. Runs on-device models with encrypted P2P sync, and supports sharing chats publicly on ATProto.
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

wip: first stab at tiles-core daemon

- NOTE: working in dev more, not in release mode
possibilities of inifnite spawning process ,fix em

madclaws 0691b9c6 39f8731c

+317 -68
+1
.gitignore
··· 8 8 .DS_Store 9 9 pkgroot/ 10 10 *.pkg 11 + pkgroot_models/
+72
Cargo.lock
··· 544 544 checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 545 545 546 546 [[package]] 547 + name = "axum" 548 + version = "0.8.8" 549 + source = "registry+https://github.com/rust-lang/crates.io-index" 550 + checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" 551 + dependencies = [ 552 + "axum-core", 553 + "bytes", 554 + "form_urlencoded", 555 + "futures-util", 556 + "http", 557 + "http-body", 558 + "http-body-util", 559 + "hyper", 560 + "hyper-util", 561 + "itoa", 562 + "matchit", 563 + "memchr", 564 + "mime", 565 + "percent-encoding", 566 + "pin-project-lite", 567 + "serde_core", 568 + "serde_json", 569 + "serde_path_to_error", 570 + "serde_urlencoded", 571 + "sync_wrapper", 572 + "tokio", 573 + "tower", 574 + "tower-layer", 575 + "tower-service", 576 + "tracing", 577 + ] 578 + 579 + [[package]] 580 + name = "axum-core" 581 + version = "0.5.6" 582 + source = "registry+https://github.com/rust-lang/crates.io-index" 583 + checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" 584 + dependencies = [ 585 + "bytes", 586 + "futures-core", 587 + "http", 588 + "http-body", 589 + "http-body-util", 590 + "mime", 591 + "pin-project-lite", 592 + "sync_wrapper", 593 + "tower-layer", 594 + "tower-service", 595 + "tracing", 596 + ] 597 + 598 + [[package]] 547 599 name = "base-x" 548 600 version = "0.2.11" 549 601 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2636 2688 ] 2637 2689 2638 2690 [[package]] 2691 + name = "matchit" 2692 + version = "0.8.4" 2693 + source = "registry+https://github.com/rust-lang/crates.io-index" 2694 + checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" 2695 + 2696 + [[package]] 2639 2697 name = "memchr" 2640 2698 version = "2.8.0" 2641 2699 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3912 3970 ] 3913 3971 3914 3972 [[package]] 3973 + name = "serde_path_to_error" 3974 + version = "0.1.20" 3975 + source = "registry+https://github.com/rust-lang/crates.io-index" 3976 + checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" 3977 + dependencies = [ 3978 + "itoa", 3979 + "serde", 3980 + "serde_core", 3981 + ] 3982 + 3983 + [[package]] 3915 3984 name = "serde_spanned" 3916 3985 version = "1.0.4" 3917 3986 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4259 4328 dependencies = [ 4260 4329 "anyhow", 4261 4330 "async-std", 4331 + "axum", 4262 4332 "clap", 4263 4333 "futures-util", 4264 4334 "hf-hub", ··· 4447 4517 "tokio", 4448 4518 "tower-layer", 4449 4519 "tower-service", 4520 + "tracing", 4450 4521 ] 4451 4522 4452 4523 [[package]] ··· 4485 4556 source = "registry+https://github.com/rust-lang/crates.io-index" 4486 4557 checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" 4487 4558 dependencies = [ 4559 + "log", 4488 4560 "pin-project-lite", 4489 4561 "tracing-attributes", 4490 4562 "tracing-core",
+3 -3
server/stack/requirements/app-server/packages-app-server.txt
··· 7 7 charset-normalizer==3.4.5 8 8 click==8.3.1 9 9 fastapi==0.119.0 10 - filelock==3.25.0 10 + filelock==3.25.2 11 11 fsspec==2026.2.0 12 12 h11==0.16.0 13 - hf-xet==1.3.2 13 + hf-xet==1.4.2 14 14 huggingface-hub==0.35.0 15 15 idna==3.11 16 16 jinja2==3.1.6 17 17 markupsafe==3.0.3 18 18 mlx-lm==0.28.3 19 19 mypy-extensions==1.1.0 20 - numpy==2.4.2 20 + numpy==2.4.3 21 21 openai-harmony==0.0.8 22 22 openresponses-types==2.3.0.post1 23 23 packaging==26.0
+2 -2
server/stack/requirements/app-server/pylock.app-server.meta.json
··· 1 1 { 2 2 "lock_input_hash": "sha256:c836d5cfb697330a57241b2b8f275a804178488ec906b19866809ef33c95ba81", 3 3 "lock_version": 1, 4 - "locked_at": "2026-03-08T15:32:49.822954+00:00", 4 + "locked_at": "2026-03-13T17:42:07.680623+00:00", 5 5 "other_inputs_hash": "sha256:63b3c2cfe2ec414938e81dace7aac779c7b902bae681618cd8827e9f16880985", 6 - "requirements_hash": "sha256:579ae09437373494896b65ca902382b680f2d42170dfa57c62618ca7d5d3457a", 6 + "requirements_hash": "sha256:641adc25f61b50b1a2c832d6e2bca50ff879f623e3956bb04a5792ee8679ed57", 7 7 "version_inputs_hash": "sha256:58db986b7cd72eeded675f7c9afd8138fe024fb51451131b5562922bbde3cf43" 8 8 }
+63 -63
server/stack/requirements/app-server/pylock.app-server.toml
··· 138 138 139 139 [[packages]] 140 140 name = "filelock" 141 - version = "3.25.0" 141 + version = "3.25.2" 142 142 index = "https://pypi.org/simple" 143 143 144 144 [[packages.wheels]] 145 - url = "https://files.pythonhosted.org/packages/f9/0b/de6f54d4a8bedfe8645c41497f3c18d749f0bd3218170c667bf4b81d0cdd/filelock-3.25.0-py3-none-any.whl" 146 - upload-time = 2026-03-01T15:08:44Z 147 - size = 26427 145 + url = "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl" 146 + upload-time = 2026-03-11T20:45:37Z 147 + size = 26759 148 148 149 149 [packages.wheels.hashes] 150 - sha256 = "5ccf8069f7948f494968fc0713c10e5c182a9c9d9eef3a636307a20c2490f047" 150 + sha256 = "ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70" 151 151 152 152 [[packages]] 153 153 name = "fsspec" ··· 177 177 178 178 [[packages]] 179 179 name = "hf-xet" 180 - version = "1.3.2" 180 + version = "1.4.2" 181 181 index = "https://pypi.org/simple" 182 182 183 183 [[packages.wheels]] 184 - url = "https://files.pythonhosted.org/packages/35/56/987b0537ddaf88e17192ea09afa8eca853e55f39a4721578be436f8409df/hf_xet-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl" 185 - upload-time = 2026-02-27T17:25:47Z 186 - size = 3521565 184 + url = "https://files.pythonhosted.org/packages/66/d4/b73ebab01cbf60777323b7de9ef05550790451eb5172a220d6b9845385ec/hf_xet-1.4.2-cp313-cp313t-macosx_11_0_arm64.whl" 185 + upload-time = 2026-03-13T06:58:31Z 186 + size = 3555985 187 187 188 188 [packages.wheels.hashes] 189 - sha256 = "c1ae4d3a716afc774e66922f3cac8206bfa707db13f6a7e62dfff74bfc95c9a8" 189 + sha256 = "6d2f8ee39fa9fba9af929f8c0d0482f8ee6e209179ad14a909b6ad78ffcb7c81" 190 190 191 191 [[packages.wheels]] 192 - url = "https://files.pythonhosted.org/packages/a8/5c/7e4a33a3d689f77761156cc34558047569e54af92e4d15a8f493229f6767/hf_xet-1.3.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" 193 - upload-time = 2026-02-27T17:25:40Z 194 - size = 4176494 192 + url = "https://files.pythonhosted.org/packages/ff/e7/ded6d1bd041c3f2bca9e913a0091adfe32371988e047dd3a68a2463c15a2/hf_xet-1.4.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" 193 + upload-time = 2026-03-13T06:58:24Z 194 + size = 4212085 195 195 196 196 [packages.wheels.hashes] 197 - sha256 = "d6dbdf231efac0b9b39adcf12a07f0c030498f9212a18e8c50224d0e84ab803d" 197 + sha256 = "4642a6cf249c09da8c1f87fe50b24b2a3450b235bf8adb55700b52f0ea6e2eb6" 198 198 199 199 [[packages.wheels]] 200 - url = "https://files.pythonhosted.org/packages/e2/e1/3af961f71a40e09bf5ee909842127b6b00f5ab4ee3817599dc0771b79893/hf_xet-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl" 201 - upload-time = 2026-02-27T17:25:58Z 202 - size = 4394161 200 + url = "https://files.pythonhosted.org/packages/21/a6/cbd4188b22abd80ebd0edbb2b3e87f2633e958983519980815fb8314eae5/hf_xet-1.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl" 201 + upload-time = 2026-03-13T06:58:42Z 202 + size = 4428287 203 203 204 204 [packages.wheels.hashes] 205 - sha256 = "35b855024ca37f2dd113ac1c08993e997fbe167b9d61f9ef66d3d4f84015e508" 205 + sha256 = "fca58a2ae4e6f6755cc971ac6fcdf777ea9284d7e540e350bb000813b9a3008d" 206 206 207 207 [[packages.wheels]] 208 - url = "https://files.pythonhosted.org/packages/e4/71/b99aed3823c9d1795e4865cf437d651097356a3f38c7d5877e4ac544b8e4/hf_xet-1.3.2-cp37-abi3-macosx_11_0_arm64.whl" 209 - upload-time = 2026-02-27T17:25:50Z 210 - size = 3526171 208 + url = "https://files.pythonhosted.org/packages/64/2e/af4475c32b4378b0e92a587adb1aa3ec53e3450fd3e5fe0372a874531c00/hf_xet-1.4.2-cp37-abi3-macosx_11_0_arm64.whl" 209 + upload-time = 2026-03-13T06:58:34Z 210 + size = 3559664 211 211 212 212 [packages.wheels.hashes] 213 - sha256 = "a85d3d43743174393afe27835bde0cd146e652b5fcfdbcd624602daef2ef3259" 213 + sha256 = "e9b38d876e94d4bdcf650778d6ebbaa791dd28de08db9736c43faff06ede1b5a" 214 214 215 215 [[packages.wheels]] 216 - url = "https://files.pythonhosted.org/packages/9d/ca/907890ce6ef5598b5920514f255ed0a65f558f820515b18db75a51b2f878/hf_xet-1.3.2-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" 217 - upload-time = 2026-02-27T17:25:43Z 218 - size = 4180750 216 + url = "https://files.pythonhosted.org/packages/3c/4c/781267da3188db679e601de18112021a5cb16506fe86b246e22c5401a9c4/hf_xet-1.4.2-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" 217 + upload-time = 2026-03-13T06:58:27Z 218 + size = 4217422 219 219 220 220 [packages.wheels.hashes] 221 - sha256 = "7c2a054a97c44e136b1f7f5a78f12b3efffdf2eed3abc6746fc5ea4b39511633" 221 + sha256 = "77e8c180b7ef12d8a96739a4e1e558847002afe9ea63b6f6358b2271a8bdda1c" 222 222 223 223 [[packages.wheels]] 224 - url = "https://files.pythonhosted.org/packages/00/b3/7bc1ff91d1ac18420b7ad1e169b618b27c00001b96310a89f8a9294fe509/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_x86_64.whl" 225 - upload-time = 2026-02-27T17:26:03Z 226 - size = 4398020 224 + url = "https://files.pythonhosted.org/packages/54/75/07f6aa680575d9646c4167db6407c41340cbe2357f5654c4e72a1b01ca14/hf_xet-1.4.2-cp37-abi3-musllinux_1_2_x86_64.whl" 225 + upload-time = 2026-03-13T06:58:46Z 226 + size = 4432751 227 227 228 228 [packages.wheels.hashes] 229 - sha256 = "06cdbde243c85f39a63b28e9034321399c507bcd5e7befdd17ed2ccc06dfe14e" 229 + sha256 = "6b0932eb8b10317ea78b7da6bab172b17be03bbcd7809383d8d5abd6a2233e04" 230 230 231 231 [[packages]] 232 232 name = "huggingface-hub" ··· 358 358 359 359 [[packages]] 360 360 name = "numpy" 361 - version = "2.4.2" 361 + version = "2.4.3" 362 362 index = "https://pypi.org/simple" 363 363 364 364 [[packages.wheels]] 365 - url = "https://files.pythonhosted.org/packages/09/f0/817d03a03f93ba9c6c8993de509277d84e69f9453601915e4a69554102a1/numpy-2.4.2-cp313-cp313-macosx_11_0_arm64.whl" 366 - upload-time = 2026-01-31T23:11:19Z 367 - size = 14688322 365 + url = "https://files.pythonhosted.org/packages/27/d9/4e7c3f0e68dfa91f21c6fb6cf839bc829ec920688b1ce7ec722b1a6202fb/numpy-2.4.3-cp313-cp313-macosx_11_0_arm64.whl" 366 + upload-time = 2026-03-09T07:56:54Z 367 + size = 14691853 368 368 369 369 [packages.wheels.hashes] 370 - sha256 = "bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979" 370 + sha256 = "2629289168f4897a3c4e23dc98d6f1731f0fc0fe52fb9db19f974041e4cc12b9" 371 371 372 372 [[packages.wheels]] 373 - url = "https://files.pythonhosted.org/packages/da/b4/f805ab79293c728b9a99438775ce51885fd4f31b76178767cfc718701a39/numpy-2.4.2-cp313-cp313-macosx_14_0_arm64.whl" 374 - upload-time = 2026-01-31T23:11:22Z 375 - size = 5198157 373 + url = "https://files.pythonhosted.org/packages/3a/66/bd096b13a87549683812b53ab211e6d413497f84e794fb3c39191948da97/numpy-2.4.3-cp313-cp313-macosx_14_0_arm64.whl" 374 + upload-time = 2026-03-09T07:56:57Z 375 + size = 5198435 376 376 377 377 [packages.wheels.hashes] 378 - sha256 = "8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98" 378 + sha256 = "bb2e3cf95854233799013779216c57e153c1ee67a0bf92138acca0e429aefaee" 379 379 380 380 [[packages.wheels]] 381 - url = "https://files.pythonhosted.org/packages/04/dc/46066ce18d01645541f0186877377b9371b8fa8017fa8262002b4ef22612/numpy-2.4.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" 382 - upload-time = 2026-01-31T23:11:28Z 383 - size = 16607311 381 + url = "https://files.pythonhosted.org/packages/7e/eb/7daecbea84ec935b7fc732e18f532073064a3816f0932a40a17f3349185f/numpy-2.4.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" 382 + upload-time = 2026-03-09T07:57:04Z 383 + size = 16608916 384 384 385 385 [packages.wheels.hashes] 386 - sha256 = "d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499" 386 + sha256 = "d5f51900414fc9204a0e0da158ba2ac52b75656e7dce7e77fb9f84bfa343b4cc" 387 387 388 388 [[packages.wheels]] 389 - url = "https://files.pythonhosted.org/packages/b7/20/adb6e6adde6d0130046e6fdfb7675cc62bc2f6b7b02239a09eb58435753d/numpy-2.4.2-cp313-cp313-musllinux_1_2_x86_64.whl" 390 - upload-time = 2026-01-31T23:11:33Z 391 - size = 18334210 389 + url = "https://files.pythonhosted.org/packages/4a/ca/627a828d44e78a418c55f82dd4caea8ea4a8ef24e5144d9e71016e52fb40/numpy-2.4.3-cp313-cp313-musllinux_1_2_x86_64.whl" 390 + upload-time = 2026-03-09T07:57:09Z 391 + size = 18334581 392 392 393 393 [packages.wheels.hashes] 394 - sha256 = "c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7" 394 + sha256 = "22654fe6be0e5206f553a9250762c653d3698e46686eee53b399ab90da59bd92" 395 395 396 396 [[packages.wheels]] 397 - url = "https://files.pythonhosted.org/packages/25/a1/9510aa43555b44781968935c7548a8926274f815de42ad3997e9e83680dd/numpy-2.4.2-cp313-cp313t-macosx_11_0_arm64.whl" 398 - upload-time = 2026-01-31T23:11:42Z 399 - size = 14815866 397 + url = "https://files.pythonhosted.org/packages/62/09/d96b02a91d09e9d97862f4fc8bfebf5400f567d8eb1fe4b0cc4795679c15/numpy-2.4.3-cp313-cp313t-macosx_11_0_arm64.whl" 398 + upload-time = 2026-03-09T07:57:18Z 399 + size = 14819570 400 400 401 401 [packages.wheels.hashes] 402 - sha256 = "5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262" 402 + sha256 = "7aa4e54f6469300ebca1d9eb80acd5253cdfa36f2c03d79a35883687da430875" 403 403 404 404 [[packages.wheels]] 405 - url = "https://files.pythonhosted.org/packages/36/30/6bbb5e76631a5ae46e7923dd16ca9d3f1c93cfa8d4ed79a129814a9d8db3/numpy-2.4.2-cp313-cp313t-macosx_14_0_arm64.whl" 406 - upload-time = 2026-01-31T23:11:44Z 407 - size = 5325631 405 + url = "https://files.pythonhosted.org/packages/b5/ca/0b1aba3905fdfa3373d523b2b15b19029f4f3031c87f4066bd9d20ef6c6b/numpy-2.4.3-cp313-cp313t-macosx_14_0_arm64.whl" 406 + upload-time = 2026-03-09T07:57:21Z 407 + size = 5326113 408 408 409 409 [packages.wheels.hashes] 410 - sha256 = "d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913" 410 + sha256 = "d1b90d840b25874cf5cd20c219af10bac3667db3876d9a495609273ebe679070" 411 411 412 412 [[packages.wheels]] 413 - url = "https://files.pythonhosted.org/packages/ea/5c/08887c54e68e1e28df53709f1893ce92932cc6f01f7c3d4dc952f61ffd4e/numpy-2.4.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" 414 - upload-time = 2026-01-31T23:11:50Z 415 - size = 16655398 413 + url = "https://files.pythonhosted.org/packages/66/f1/d1c2bf1161396629701bc284d958dc1efa3a5a542aab83cf11ee6eb4cba5/numpy-2.4.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" 414 + upload-time = 2026-03-09T07:57:27Z 415 + size = 16657164 416 416 417 417 [packages.wheels.hashes] 418 - sha256 = "2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f" 418 + sha256 = "22c31dc07025123aedf7f2db9e91783df13f1776dc52c6b22c620870dc0fab22" 419 419 420 420 [[packages.wheels]] 421 - url = "https://files.pythonhosted.org/packages/2a/d5/cbade46ce97c59c6c3da525e8d95b7abe8a42974a1dc5c1d489c10433e88/numpy-2.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl" 422 - upload-time = 2026-01-31T23:11:55Z 423 - size = 18379680 421 + url = "https://files.pythonhosted.org/packages/b9/c5/9602b0cbb703a0936fb40f8a95407e8171935b15846de2f0776e08af04c7/numpy-2.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl" 422 + upload-time = 2026-03-09T07:57:33Z 423 + size = 18380290 424 424 425 425 [packages.wheels.hashes] 426 - sha256 = "0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257" 426 + sha256 = "a97cbf7e905c435865c2d939af3d93f99d18eaaa3cabe4256f4304fb51604349" 427 427 428 428 [[packages]] 429 429 name = "openai-harmony"
+1
tiles/Cargo.toml
··· 20 20 rusqlite = { version = "0.38.0", features = ["bundled"] } 21 21 rusqlite_migration = "2.4.1" 22 22 uuid = {version = "1.21.0", features = ["v7"]} 23 + axum = "0.8.8" 23 24 24 25 [dev-dependencies] 25 26 tempfile = "3"
+136
tiles/src/daemon.rs
··· 1 + //! The Demon that runs the core with his spear 2 + 3 + use std::{ 4 + process::{Command, Stdio}, 5 + sync::Arc, 6 + time::Duration, 7 + }; 8 + 9 + use anyhow::{Result, anyhow}; 10 + use axum::{Router, extract::State, routing::get}; 11 + use reqwest::Client; 12 + use std::fs::OpenOptions; 13 + use std::sync::Mutex; 14 + use tokio::sync::oneshot::{self, Receiver}; 15 + 16 + use crate::utils::config::{ConfigProvider, DefaultProvider}; 17 + 18 + struct AppState { 19 + pub shutdown_sender: Mutex<Option<oneshot::Sender<bool>>>, 20 + } 21 + 22 + pub async fn start_cmd() -> Result<()> { 23 + if cfg!(debug_assertions) { 24 + start_server().await 25 + } else { 26 + start_daemon().await 27 + } 28 + } 29 + 30 + pub async fn stop_cmd() -> Result<()> { 31 + stop_server().await 32 + } 33 + async fn root() -> &'static str { 34 + "Its me luttappi" 35 + } 36 + 37 + // allow zombie, since this process is expected to be 38 + // running in background and have commands to stop if needed 39 + #[allow(clippy::zombie_processes)] 40 + async fn start_daemon() -> Result<()> { 41 + tokio::time::sleep(Duration::from_secs(5)).await; 42 + if (ping().await).is_ok() { 43 + return Ok(()); 44 + } 45 + let data_dir = DefaultProvider.get_data_dir()?; 46 + let stdout_log = OpenOptions::new() 47 + .create(true) 48 + .append(true) 49 + .open(data_dir.join("logs/daemon.out.log"))?; 50 + let stderr_log = OpenOptions::new() 51 + .create(true) 52 + .append(true) 53 + .open(data_dir.join("logs/daemon.err.log"))?; 54 + let _process = Command::new("tiles") 55 + .arg("daemon") 56 + .stdin(Stdio::null()) 57 + .stdout(Stdio::from(stdout_log)) 58 + .stderr(Stdio::from(stderr_log)) 59 + .spawn() 60 + .expect("Failed to start daemon"); 61 + 62 + wait_until_server_is_up().await 63 + } 64 + 65 + pub async fn start_server() -> Result<()> { 66 + let (shutdown_tx, shutdown_rx) = oneshot::channel::<bool>(); 67 + 68 + let state = AppState { 69 + shutdown_sender: Mutex::new(Some(shutdown_tx)), 70 + }; 71 + let shared_state = Arc::new(state); 72 + let app = Router::new() 73 + .route("/", get(root)) 74 + .route("/shutdown", get(shutdown)) 75 + .with_state(shared_state); 76 + 77 + let listener = tokio::net::TcpListener::bind("127.0.0.1:1729").await?; 78 + 79 + println!("Daemon server started at 1729"); 80 + let _ = axum::serve(listener, app) 81 + .with_graceful_shutdown(shutdown_signal(shutdown_rx)) 82 + .await; 83 + 84 + Ok(()) 85 + } 86 + 87 + async fn shutdown_signal(rx: Receiver<bool>) { 88 + rx.await.expect("shutdown receiver paniced"); 89 + } 90 + 91 + async fn shutdown(State(state): State<Arc<AppState>>) { 92 + println!("Daemon server shutting down"); 93 + let mut sender = state.shutdown_sender.lock().unwrap(); 94 + let sender_real = sender.take().unwrap(); 95 + let _ = sender_real.send(true); 96 + } 97 + 98 + async fn stop_server() -> Result<()> { 99 + let client = Client::new(); 100 + let res = client.get("http://127.0.0.1:1729/shutdown").send().await; 101 + 102 + match res { 103 + Err(err) => Err(anyhow!("Daemon shutdown failed due to {:?}", err)), 104 + _ => Ok(()), 105 + } 106 + } 107 + pub async fn ping() -> Result<(), String> { 108 + let client = Client::new(); 109 + let res = client.get("http://127.0.0.1:1729").send().await; 110 + 111 + match res { 112 + Err(err) => Err(format!("Pong failed: {:?}", err)), 113 + _ => Ok(()), 114 + } 115 + } 116 + 117 + async fn wait_until_server_is_up() -> Result<()> { 118 + let mut retry_count = 5; 119 + let mut error: String = String::new(); 120 + loop { 121 + if retry_count < 1 { 122 + if !cfg!(debug_assertions) { 123 + println!("{:?}", error); 124 + } 125 + return Err(anyhow!(error)); 126 + } 127 + match ping().await { 128 + Ok(()) => return Ok(()), 129 + Err(err) => { 130 + retry_count -= 1; 131 + error = err; 132 + tokio::time::sleep(Duration::from_secs(5)).await; 133 + } 134 + } 135 + } 136 + }
+1
tiles/src/lib.rs
··· 1 1 pub mod core; 2 + pub mod daemon; 2 3 pub mod runtime; 3 4 pub mod utils; 4 5 #[cfg(test)]
+38
tiles/src/main.rs
··· 2 2 3 3 use clap::{Args, Parser, Subcommand}; 4 4 use tiles::{ 5 + daemon::{start_cmd, stop_cmd}, 5 6 runtime::{RunArgs, build_runtime}, 6 7 utils::installer, 7 8 }; 9 + 8 10 mod commands; 9 11 #[derive(Debug, Parser)] 10 12 #[command(name = "tiles")] ··· 55 57 56 58 /// Update Tiles to latest version 57 59 Update, 60 + 61 + /// Daemon configurations 62 + Daemon(DaemonArgs), 58 63 } 59 64 60 65 #[derive(Debug, Args)] ··· 118 123 SetNickname { nickname: String }, 119 124 } 120 125 126 + #[derive(Debug, Args)] 127 + #[command(args_conflicts_with_subcommands = true)] 128 + #[command(flatten_help = true)] 129 + struct DaemonArgs { 130 + #[command(subcommand)] 131 + command: Option<DaemonCommands>, 132 + } 133 + 134 + #[derive(Debug, Subcommand)] 135 + enum DaemonCommands { 136 + /// Start the daemon 137 + Start, 138 + 139 + /// Stops the daemon 140 + Stop, 141 + } 121 142 #[tokio::main] 122 143 pub async fn main() -> Result<(), Box<dyn Error>> { 123 144 let cli = Cli::parse(); ··· 133 154 commands::run_setup_for_ftue(&run_args) 134 155 .inspect_err(|e| eprintln!("Failed to setup Tiles due to {:?}", e))?; 135 156 let _ = commands::try_app_update().await; 157 + 158 + // trying to run the tiles daemon in background 159 + //TODO: Run this as an async process tokio::spawn 160 + if !cfg!(debug_assertions) { 161 + let _ = start_cmd().await; 162 + } 163 + 136 164 commands::run(&runtime, run_args) 137 165 .await 138 166 .inspect_err(|e| eprintln!("Tiles failed to run due to {:?}", e))?; ··· 180 208 .inspect_err(|e| eprintln!("Failed in update process due to {:?}", e))?; 181 209 println!("{}", res); 182 210 } 211 + Some(Commands::Daemon(daemon_args)) => match daemon_args.command { 212 + Some(DaemonCommands::Start) => start_cmd() 213 + .await 214 + .inspect_err(|e| eprintln!("Daemon starting failed, reason: {:?}", e))?, 215 + Some(DaemonCommands::Stop) => stop_cmd() 216 + .await 217 + .inspect_err(|e| eprintln!("{:?}", e)) 218 + .inspect(|_| println!("Daemon stopped successfully"))?, 219 + _ => start_cmd().await?, 220 + }, 183 221 } 184 222 Ok(()) 185 223 }