A PLC Mirror written in Rust

Compare changes

Choose any two refs to compare.

+1
.dockerignore
··· 1 + target/
+1
Cargo.lock
··· 1406 1406 "deadpool-postgres", 1407 1407 "dropshot", 1408 1408 "eyre", 1409 + "hyper", 1409 1410 "ipld-core", 1410 1411 "reqwest", 1411 1412 "schemars",
+1
Cargo.toml
··· 7 7 chrono = { version = "0.4.39", features = ["serde"] } 8 8 deadpool-postgres = "0.14.1" 9 9 dropshot = "0.16.0" 10 + hyper = "1.6.0" 10 11 eyre = "0.6.12" 11 12 ipld-core = { version = "0.4.1", features = ["serde"] } 12 13 reqwest = { version = "0.12.12", features = ["native-tls", "json"] }
-176
LICENSE
··· 1 - Apache License 2 - Version 2.0, January 2004 3 - http://www.apache.org/licenses/ 4 - 5 - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 - 7 - 1. Definitions. 8 - 9 - "License" shall mean the terms and conditions for use, reproduction, 10 - and distribution as defined by Sections 1 through 9 of this document. 11 - 12 - "Licensor" shall mean the copyright owner or entity authorized by 13 - the copyright owner that is granting the License. 14 - 15 - "Legal Entity" shall mean the union of the acting entity and all 16 - other entities that control, are controlled by, or are under common 17 - control with that entity. For the purposes of this definition, 18 - "control" means (i) the power, direct or indirect, to cause the 19 - direction or management of such entity, whether by contract or 20 - otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 - outstanding shares, or (iii) beneficial ownership of such entity. 22 - 23 - "You" (or "Your") shall mean an individual or Legal Entity 24 - exercising permissions granted by this License. 25 - 26 - "Source" form shall mean the preferred form for making modifications, 27 - including but not limited to software source code, documentation 28 - source, and configuration files. 29 - 30 - "Object" form shall mean any form resulting from mechanical 31 - transformation or translation of a Source form, including but 32 - not limited to compiled object code, generated documentation, 33 - and conversions to other media types. 34 - 35 - "Work" shall mean the work of authorship, whether in Source or 36 - Object form, made available under the License, as indicated by a 37 - copyright notice that is included in or attached to the work 38 - (an example is provided in the Appendix below). 39 - 40 - "Derivative Works" shall mean any work, whether in Source or Object 41 - form, that is based on (or derived from) the Work and for which the 42 - editorial revisions, annotations, elaborations, or other modifications 43 - represent, as a whole, an original work of authorship. For the purposes 44 - of this License, Derivative Works shall not include works that remain 45 - separable from, or merely link (or bind by name) to the interfaces of, 46 - the Work and Derivative Works thereof. 47 - 48 - "Contribution" shall mean any work of authorship, including 49 - the original version of the Work and any modifications or additions 50 - to that Work or Derivative Works thereof, that is intentionally 51 - submitted to Licensor for inclusion in the Work by the copyright owner 52 - or by an individual or Legal Entity authorized to submit on behalf of 53 - the copyright owner. For the purposes of this definition, "submitted" 54 - means any form of electronic, verbal, or written communication sent 55 - to the Licensor or its representatives, including but not limited to 56 - communication on electronic mailing lists, source code control systems, 57 - and issue tracking systems that are managed by, or on behalf of, the 58 - Licensor for the purpose of discussing and improving the Work, but 59 - excluding communication that is conspicuously marked or otherwise 60 - designated in writing by the copyright owner as "Not a Contribution." 61 - 62 - "Contributor" shall mean Licensor and any individual or Legal Entity 63 - on behalf of whom a Contribution has been received by Licensor and 64 - subsequently incorporated within the Work. 65 - 66 - 2. Grant of Copyright License. Subject to the terms and conditions of 67 - this License, each Contributor hereby grants to You a perpetual, 68 - worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 - copyright license to reproduce, prepare Derivative Works of, 70 - publicly display, publicly perform, sublicense, and distribute the 71 - Work and such Derivative Works in Source or Object form. 72 - 73 - 3. Grant of Patent License. Subject to the terms and conditions of 74 - this License, each Contributor hereby grants to You a perpetual, 75 - worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 - (except as stated in this section) patent license to make, have made, 77 - use, offer to sell, sell, import, and otherwise transfer the Work, 78 - where such license applies only to those patent claims licensable 79 - by such Contributor that are necessarily infringed by their 80 - Contribution(s) alone or by combination of their Contribution(s) 81 - with the Work to which such Contribution(s) was submitted. If You 82 - institute patent litigation against any entity (including a 83 - cross-claim or counterclaim in a lawsuit) alleging that the Work 84 - or a Contribution incorporated within the Work constitutes direct 85 - or contributory patent infringement, then any patent licenses 86 - granted to You under this License for that Work shall terminate 87 - as of the date such litigation is filed. 88 - 89 - 4. Redistribution. You may reproduce and distribute copies of the 90 - Work or Derivative Works thereof in any medium, with or without 91 - modifications, and in Source or Object form, provided that You 92 - meet the following conditions: 93 - 94 - (a) You must give any other recipients of the Work or 95 - Derivative Works a copy of this License; and 96 - 97 - (b) You must cause any modified files to carry prominent notices 98 - stating that You changed the files; and 99 - 100 - (c) You must retain, in the Source form of any Derivative Works 101 - that You distribute, all copyright, patent, trademark, and 102 - attribution notices from the Source form of the Work, 103 - excluding those notices that do not pertain to any part of 104 - the Derivative Works; and 105 - 106 - (d) If the Work includes a "NOTICE" text file as part of its 107 - distribution, then any Derivative Works that You distribute must 108 - include a readable copy of the attribution notices contained 109 - within such NOTICE file, excluding those notices that do not 110 - pertain to any part of the Derivative Works, in at least one 111 - of the following places: within a NOTICE text file distributed 112 - as part of the Derivative Works; within the Source form or 113 - documentation, if provided along with the Derivative Works; or, 114 - within a display generated by the Derivative Works, if and 115 - wherever such third-party notices normally appear. The contents 116 - of the NOTICE file are for informational purposes only and 117 - do not modify the License. You may add Your own attribution 118 - notices within Derivative Works that You distribute, alongside 119 - or as an addendum to the NOTICE text from the Work, provided 120 - that such additional attribution notices cannot be construed 121 - as modifying the License. 122 - 123 - You may add Your own copyright statement to Your modifications and 124 - may provide additional or different license terms and conditions 125 - for use, reproduction, or distribution of Your modifications, or 126 - for any such Derivative Works as a whole, provided Your use, 127 - reproduction, and distribution of the Work otherwise complies with 128 - the conditions stated in this License. 129 - 130 - 5. Submission of Contributions. Unless You explicitly state otherwise, 131 - any Contribution intentionally submitted for inclusion in the Work 132 - by You to the Licensor shall be under the terms and conditions of 133 - this License, without any additional terms or conditions. 134 - Notwithstanding the above, nothing herein shall supersede or modify 135 - the terms of any separate license agreement you may have executed 136 - with Licensor regarding such Contributions. 137 - 138 - 6. Trademarks. This License does not grant permission to use the trade 139 - names, trademarks, service marks, or product names of the Licensor, 140 - except as required for reasonable and customary use in describing the 141 - origin of the Work and reproducing the content of the NOTICE file. 142 - 143 - 7. Disclaimer of Warranty. Unless required by applicable law or 144 - agreed to in writing, Licensor provides the Work (and each 145 - Contributor provides its Contributions) on an "AS IS" BASIS, 146 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 - implied, including, without limitation, any warranties or conditions 148 - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 - PARTICULAR PURPOSE. You are solely responsible for determining the 150 - appropriateness of using or redistributing the Work and assume any 151 - risks associated with Your exercise of permissions under this License. 152 - 153 - 8. Limitation of Liability. In no event and under no legal theory, 154 - whether in tort (including negligence), contract, or otherwise, 155 - unless required by applicable law (such as deliberate and grossly 156 - negligent acts) or agreed to in writing, shall any Contributor be 157 - liable to You for damages, including any direct, indirect, special, 158 - incidental, or consequential damages of any character arising as a 159 - result of this License or out of the use or inability to use the 160 - Work (including but not limited to damages for loss of goodwill, 161 - work stoppage, computer failure or malfunction, or any and all 162 - other commercial damages or losses), even if such Contributor 163 - has been advised of the possibility of such damages. 164 - 165 - 9. Accepting Warranty or Additional Liability. While redistributing 166 - the Work or Derivative Works thereof, You may choose to offer, 167 - and charge a fee for, acceptance of support, warranty, indemnity, 168 - or other liability obligations and/or rights consistent with this 169 - License. However, in accepting such obligations, You may act only 170 - on Your own behalf and on Your sole responsibility, not on behalf 171 - of any other Contributor, and only if You agree to indemnify, 172 - defend, and hold each Contributor harmless for any liability 173 - incurred by, or claims asserted against, such Contributor by reason 174 - of your accepting any such warranty or additional liability. 175 - 176 - END OF TERMS AND CONDITIONS
+176
LICENSE-APACHE
··· 1 + Apache License 2 + Version 2.0, January 2004 3 + http://www.apache.org/licenses/ 4 + 5 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 + 7 + 1. Definitions. 8 + 9 + "License" shall mean the terms and conditions for use, reproduction, 10 + and distribution as defined by Sections 1 through 9 of this document. 11 + 12 + "Licensor" shall mean the copyright owner or entity authorized by 13 + the copyright owner that is granting the License. 14 + 15 + "Legal Entity" shall mean the union of the acting entity and all 16 + other entities that control, are controlled by, or are under common 17 + control with that entity. For the purposes of this definition, 18 + "control" means (i) the power, direct or indirect, to cause the 19 + direction or management of such entity, whether by contract or 20 + otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 + outstanding shares, or (iii) beneficial ownership of such entity. 22 + 23 + "You" (or "Your") shall mean an individual or Legal Entity 24 + exercising permissions granted by this License. 25 + 26 + "Source" form shall mean the preferred form for making modifications, 27 + including but not limited to software source code, documentation 28 + source, and configuration files. 29 + 30 + "Object" form shall mean any form resulting from mechanical 31 + transformation or translation of a Source form, including but 32 + not limited to compiled object code, generated documentation, 33 + and conversions to other media types. 34 + 35 + "Work" shall mean the work of authorship, whether in Source or 36 + Object form, made available under the License, as indicated by a 37 + copyright notice that is included in or attached to the work 38 + (an example is provided in the Appendix below). 39 + 40 + "Derivative Works" shall mean any work, whether in Source or Object 41 + form, that is based on (or derived from) the Work and for which the 42 + editorial revisions, annotations, elaborations, or other modifications 43 + represent, as a whole, an original work of authorship. For the purposes 44 + of this License, Derivative Works shall not include works that remain 45 + separable from, or merely link (or bind by name) to the interfaces of, 46 + the Work and Derivative Works thereof. 47 + 48 + "Contribution" shall mean any work of authorship, including 49 + the original version of the Work and any modifications or additions 50 + to that Work or Derivative Works thereof, that is intentionally 51 + submitted to Licensor for inclusion in the Work by the copyright owner 52 + or by an individual or Legal Entity authorized to submit on behalf of 53 + the copyright owner. For the purposes of this definition, "submitted" 54 + means any form of electronic, verbal, or written communication sent 55 + to the Licensor or its representatives, including but not limited to 56 + communication on electronic mailing lists, source code control systems, 57 + and issue tracking systems that are managed by, or on behalf of, the 58 + Licensor for the purpose of discussing and improving the Work, but 59 + excluding communication that is conspicuously marked or otherwise 60 + designated in writing by the copyright owner as "Not a Contribution." 61 + 62 + "Contributor" shall mean Licensor and any individual or Legal Entity 63 + on behalf of whom a Contribution has been received by Licensor and 64 + subsequently incorporated within the Work. 65 + 66 + 2. Grant of Copyright License. Subject to the terms and conditions of 67 + this License, each Contributor hereby grants to You a perpetual, 68 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 + copyright license to reproduce, prepare Derivative Works of, 70 + publicly display, publicly perform, sublicense, and distribute the 71 + Work and such Derivative Works in Source or Object form. 72 + 73 + 3. Grant of Patent License. Subject to the terms and conditions of 74 + this License, each Contributor hereby grants to You a perpetual, 75 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 + (except as stated in this section) patent license to make, have made, 77 + use, offer to sell, sell, import, and otherwise transfer the Work, 78 + where such license applies only to those patent claims licensable 79 + by such Contributor that are necessarily infringed by their 80 + Contribution(s) alone or by combination of their Contribution(s) 81 + with the Work to which such Contribution(s) was submitted. If You 82 + institute patent litigation against any entity (including a 83 + cross-claim or counterclaim in a lawsuit) alleging that the Work 84 + or a Contribution incorporated within the Work constitutes direct 85 + or contributory patent infringement, then any patent licenses 86 + granted to You under this License for that Work shall terminate 87 + as of the date such litigation is filed. 88 + 89 + 4. Redistribution. You may reproduce and distribute copies of the 90 + Work or Derivative Works thereof in any medium, with or without 91 + modifications, and in Source or Object form, provided that You 92 + meet the following conditions: 93 + 94 + (a) You must give any other recipients of the Work or 95 + Derivative Works a copy of this License; and 96 + 97 + (b) You must cause any modified files to carry prominent notices 98 + stating that You changed the files; and 99 + 100 + (c) You must retain, in the Source form of any Derivative Works 101 + that You distribute, all copyright, patent, trademark, and 102 + attribution notices from the Source form of the Work, 103 + excluding those notices that do not pertain to any part of 104 + the Derivative Works; and 105 + 106 + (d) If the Work includes a "NOTICE" text file as part of its 107 + distribution, then any Derivative Works that You distribute must 108 + include a readable copy of the attribution notices contained 109 + within such NOTICE file, excluding those notices that do not 110 + pertain to any part of the Derivative Works, in at least one 111 + of the following places: within a NOTICE text file distributed 112 + as part of the Derivative Works; within the Source form or 113 + documentation, if provided along with the Derivative Works; or, 114 + within a display generated by the Derivative Works, if and 115 + wherever such third-party notices normally appear. The contents 116 + of the NOTICE file are for informational purposes only and 117 + do not modify the License. You may add Your own attribution 118 + notices within Derivative Works that You distribute, alongside 119 + or as an addendum to the NOTICE text from the Work, provided 120 + that such additional attribution notices cannot be construed 121 + as modifying the License. 122 + 123 + You may add Your own copyright statement to Your modifications and 124 + may provide additional or different license terms and conditions 125 + for use, reproduction, or distribution of Your modifications, or 126 + for any such Derivative Works as a whole, provided Your use, 127 + reproduction, and distribution of the Work otherwise complies with 128 + the conditions stated in this License. 129 + 130 + 5. Submission of Contributions. Unless You explicitly state otherwise, 131 + any Contribution intentionally submitted for inclusion in the Work 132 + by You to the Licensor shall be under the terms and conditions of 133 + this License, without any additional terms or conditions. 134 + Notwithstanding the above, nothing herein shall supersede or modify 135 + the terms of any separate license agreement you may have executed 136 + with Licensor regarding such Contributions. 137 + 138 + 6. Trademarks. This License does not grant permission to use the trade 139 + names, trademarks, service marks, or product names of the Licensor, 140 + except as required for reasonable and customary use in describing the 141 + origin of the Work and reproducing the content of the NOTICE file. 142 + 143 + 7. Disclaimer of Warranty. Unless required by applicable law or 144 + agreed to in writing, Licensor provides the Work (and each 145 + Contributor provides its Contributions) on an "AS IS" BASIS, 146 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 + implied, including, without limitation, any warranties or conditions 148 + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 + PARTICULAR PURPOSE. You are solely responsible for determining the 150 + appropriateness of using or redistributing the Work and assume any 151 + risks associated with Your exercise of permissions under this License. 152 + 153 + 8. Limitation of Liability. In no event and under no legal theory, 154 + whether in tort (including negligence), contract, or otherwise, 155 + unless required by applicable law (such as deliberate and grossly 156 + negligent acts) or agreed to in writing, shall any Contributor be 157 + liable to You for damages, including any direct, indirect, special, 158 + incidental, or consequential damages of any character arising as a 159 + result of this License or out of the use or inability to use the 160 + Work (including but not limited to damages for loss of goodwill, 161 + work stoppage, computer failure or malfunction, or any and all 162 + other commercial damages or losses), even if such Contributor 163 + has been advised of the possibility of such damages. 164 + 165 + 9. Accepting Warranty or Additional Liability. While redistributing 166 + the Work or Derivative Works thereof, You may choose to offer, 167 + and charge a fee for, acceptance of support, warranty, indemnity, 168 + or other liability obligations and/or rights consistent with this 169 + License. However, in accepting such obligations, You may act only 170 + on Your own behalf and on Your sole responsibility, not on behalf 171 + of any other Contributor, and only if You agree to indemnify, 172 + defend, and hold each Contributor harmless for any liability 173 + incurred by, or claims asserted against, such Contributor by reason 174 + of your accepting any such warranty or additional liability. 175 + 176 + END OF TERMS AND CONDITIONS
+21
LICENSE-MIT
··· 1 + MIT License 2 + 3 + Copyright (c) 2025 Parakeet Project 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 11 + 12 + The above copyright notice and this permission notice shall be included in all 13 + copies or substantial portions of the Software. 14 + 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + SOFTWARE.
+40
README.md
··· 1 + # Parakeet PLC Mirror 2 + 3 + A little Rust mirror of Bluesky Social PBC's [plc.directory](https://web.plc.directory/) 4 + for use with the [Parakeet AppView](https://gitlab.com/parakeet-social/parakeet) project. 5 + 6 + All endpoints bar `/export` and `/{did}/data` are implemented and should be functionally identical. 7 + 8 + ## Running 9 + 10 + ### Prerequisites 11 + 12 + - Either Docker, or a binary from [Compiling](#compiling) 13 + - Postgres (tested with 16, but any recent version should work) 14 + 15 + ### Running PLC Mirror 16 + 17 + A docker image is provided as `registry.gitlab.com/parakeet-social/plc-mirror`, or you can [compile](#compiling) a binary. 18 + 19 + Complete the below environment variables: 20 + 21 + | Variable | Description | Default | 22 + |-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------| 23 + | `PLC_DB_URI` | (required) Postgres DB URI in format `postgres://{user}:{pass}@{addr}/{db}` | | 24 + | `PLC_UPSTREAM` | (optional) Upstream PLC directory to import from | `https://plc.directory` | 25 + | `PLC_BIND_ADDR` | (optional) The address and port to bind to, in format `{IP}:{port}` | `127.0.0.1:8080` | 26 + | `PLC_USER_AGENT` | (recommended) The User-Agent header to set on export requests from upstream. Setting this is highly advised | `parakeet-plc` | 27 + | `PLC_START_AFTER` | (optional) Where in time to start importing from PLC. Leaving blank will trigger an import from the beginning of the directory or from the last seen TS if applicable. In format `2018-01-26T18:30:09.453Z`. | | 28 + 29 + Then, run the binary. Imports from the upstream directory will begin immediately alongside the API server. 30 + 31 + ## Compiling 32 + 33 + You'll need [Rust](https://www.rust-lang.org/), Cargo, and openssl-dev (aka libssl-dev) to build. 34 + Builds are tested on Rust 1.85. 35 + 36 + A simple `cargo b` or `cargo r` should work just fine, likewise for release options. 37 + 38 + ## License & Contributing 39 + 40 + This project is licensed under Apache-2. Contributions are welcome, but please discuss first.
+31
compose.yml
··· 1 + services: 2 + plc-mirror: 3 + image: registry.gitlab.com/parakeet-social/plc-mirror:main 4 + restart: unless-stopped 5 + ports: 6 + - 8080:8080 7 + depends_on: 8 + plc-mirror-db: 9 + condition: service_healthy 10 + environment: 11 + PLC_DB_URI: postgres://plcmirror:${PLC_MIRROR_DB_PASSWORD:?}@plc-mirror-db/plcmirror 12 + PLC_BIND_ADDR: 0.0.0.0:8080 13 + 14 + plc-mirror-db: 15 + image: postgres:18-alpine 16 + restart: unless-stopped 17 + environment: 18 + POSTGRES_USER: plcmirror 19 + POSTGRES_PASSWORD: ${PLC_MIRROR_DB_PASSWORD:?} 20 + POSTGRES_DB: plcmirror 21 + volumes: 22 + - plc-mirror-db-data:/var/lib/postgresql/data 23 + healthcheck: 24 + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] 25 + interval: 5s 26 + timeout: 5s 27 + retries: 5 28 + start_period: 10s 29 + 30 + volumes: 31 + plc-mirror-db-data:
+24 -1
src/api.rs
··· 1 1 use crate::types::{DidDocument, JsonCid, PlcEntry, PlcOperationType}; 2 2 use crate::{ApiContext, db}; 3 - use dropshot::{ClientErrorStatusCode, HttpError, HttpResponseOk, Path, RequestContext, endpoint}; 3 + use dropshot::{ 4 + Body, ClientErrorStatusCode, HttpError, HttpResponseOk, Path, RequestContext, endpoint, 5 + }; 6 + use hyper::Response; 4 7 use ipld_core::cid::Cid; 5 8 use schemars::JsonSchema; 6 9 use serde::Deserialize; ··· 18 21 ) 19 22 } 20 23 24 + #[endpoint{ 25 + method = GET, 26 + path = "/", 27 + }] 28 + // strictly this isn't the correct type, but it works 29 + pub async fn index(_rqctx: RequestContext<ApiContext>) -> Result<Response<Body>, HttpError> { 30 + Ok(Response::builder() 31 + .status(200) 32 + .header("Content-Type", "text/plain") 33 + .body(Body::with_content(include_str!("./index.txt")))?) 34 + } 35 + 21 36 #[derive(Debug, JsonSchema, Deserialize)] 22 37 pub struct DidPathParams { 23 38 pub did: String, ··· 33 48 ) -> Result<HttpResponseOk<DidDocument>, HttpError> { 34 49 let conn = rqctx.context().get_conn().await?; 35 50 let did = path.into_inner().did; 51 + 52 + if did == "favicon.ico" { 53 + return Err(HttpError::for_not_found(None, Default::default())); 54 + } 55 + 56 + if !did.starts_with("did:plc:") { 57 + return Err(HttpError::for_bad_request(None, "Invalid DID".to_string())); 58 + } 36 59 37 60 let op = db::get_latest_operation(&conn, &did) 38 61 .await
+11
src/db.rs
··· 54 54 55 55 Ok(ops.into_iter().map(Operation::from).collect()) 56 56 } 57 + 58 + pub async fn get_last_operation_ts( 59 + conn: &Object, 60 + ) -> Result<Option<DateTime<Utc>>, tokio_postgres::Error> { 61 + conn.query_opt( 62 + "SELECT created_at FROM operations ORDER BY created_at DESC LIMIT 1", 63 + &[], 64 + ) 65 + .await 66 + .map(|v| v.map(|row| row.get(0))) 67 + }
+15 -6
src/import.rs
··· 1 1 use crate::types::{PlcEntry, PlcOperationType}; 2 2 use deadpool_postgres::{Object, Pool}; 3 3 use reqwest::Client; 4 - use slog::{Logger, debug, error}; 4 + use slog::{Logger, debug, error, info}; 5 5 use std::env::var; 6 6 use std::time::{Duration, Instant}; 7 7 use tokio::sync::OnceCell; ··· 15 15 static INSERT_DID_STMT: OnceCell<Statement> = OnceCell::const_new(); 16 16 static INSERT_OP_STMT: OnceCell<Statement> = OnceCell::const_new(); 17 17 18 - pub async fn importer(log: Logger, pool: Pool) { 18 + pub async fn importer(log: Logger, pool: Pool, start_after: Option<String>) { 19 19 let plc_main = var("PLC_UPSTREAM").unwrap_or("https://plc.directory".to_string()); 20 20 let user_agent = var("PLC_USER_AGENT").unwrap_or("parakeet-plc".to_string()); 21 21 22 - let mut after = var("PLC_START_AFTER").ok(); 22 + let mut after = start_after; 23 + 24 + if let Some(after) = &after { 25 + info!(log, "starting import at {after}"); 26 + } 23 27 24 28 let client = Client::builder().user_agent(user_agent).build().unwrap(); 25 29 let conn = pool.get().await.unwrap(); ··· 36 40 errors.len() 37 41 ); 38 42 39 - // todo: report errors 43 + if !errors.is_empty() { 44 + error!(log, "{} entries failed to decode", errors.len()); 45 + } 46 + 40 47 for entry in &entries { 41 48 if let Err(e) = insert_did_and_op(&conn, entry).await { 42 49 error!(log, "failed to insert operation for did {}: {e}", entry.did); 43 50 } 44 51 } 45 52 46 - let new_after = entries.last().unwrap().created_at; 47 - after = Some(new_after.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)); 53 + if let Some(new_after) = entries.last() { 54 + let new_after = new_after.created_at; 55 + after = Some(new_after.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)); 56 + } 48 57 } 49 58 Err(err) => error!(log, "failed to export PLC directory: {err}"), 50 59 }
+11
src/index.txt
··· 1 + ____ _ _ ____ _ ____ 2 + | _ \ __ _ _ __ __ _| | _____ ___| |_ | _ \| | / ___| 3 + | |_) / _` | '__/ _` | |/ / _ \/ _ \ __| | |_) | | | | 4 + | __/ (_| | | | (_| | < __/ __/ |_ | __/| |__| |___ 5 + |_| \__,_|_| \__,_|_|\_\___|\___|\__| |_| |_____\____| 6 + 7 + A little Rust did:plc mirror for Parakeet. 8 + Use /{did} to resolve a DID. 9 + 10 + - https://gitlab.com/parakeet-social/plc-mirror 11 + - https://web.plc.directory
+14
src/lib.rs
··· 42 42 api_desc.register(api::get_plc_audit_log)?; 43 43 api_desc.register(api::get_last_op)?; 44 44 api_desc.register(api::resolve_did)?; 45 + api_desc.register(api::index)?; 45 46 46 47 Ok(api_desc) 47 48 } ··· 59 60 60 61 Ok(pool) 61 62 } 63 + 64 + pub async fn get_start_after(pool: &Pool) -> eyre::Result<Option<String>> { 65 + if let Some(env_start_after) = var("PLC_START_AFTER").ok() { 66 + return Ok(Some(env_start_after)); 67 + } 68 + 69 + let obj = pool.get().await?; 70 + let last_ts = db::get_last_operation_ts(&obj) 71 + .await? 72 + .map(|v| v.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)); 73 + 74 + Ok(last_ts) 75 + }
+7 -1
src/main.rs
··· 14 14 15 15 let pool = plc_mirror::connect_db().await?; 16 16 17 - tokio::spawn(plc_mirror::import::importer(log.clone(), pool.clone())); 17 + let start_after = plc_mirror::get_start_after(&pool).await?; 18 + 19 + tokio::spawn(plc_mirror::import::importer( 20 + log.clone(), 21 + pool.clone(), 22 + start_after, 23 + )); 18 24 19 25 let bind_address = var("PLC_BIND_ADDR") 20 26 .unwrap_or(DEFAULT_BIND.to_string())
+4 -1
src/sql/init.sql
··· 16 16 created_at timestamptz not null default now(), 17 17 18 18 primary key (did, hash) 19 - ); 19 + ); 20 + 21 + create index if not exists operations_created on operations (created_at); 22 + create index if not exists operations_nullified on operations (nullified);