Skip to main content

qualia_cli/handlers/
webizen.rs

1use crate::cli::WebizenAction;
2
3pub async fn handle(action: &WebizenAction) -> Result<(), Box<dyn std::error::Error>> {
4    match action {
5        WebizenAction::Init { path } => {
6            println!("========================================");
7            println!("Initializing Webizen Mode at {:?}", path);
8
9            use ed25519_dalek::SigningKey;
10            let mut secret = [0u8; 32];
11            getrandom::fill(&mut secret)?;
12            let signing_key = SigningKey::from_bytes(&secret);
13            let public_key = signing_key.verifying_key();
14            let pub_hex = public_key
15                .as_bytes()
16                .iter()
17                .map(|b| format!("{:02x}", b))
18                .collect::<String>();
19            println!("🔑 Generated Webizen Agency Identity: did:git:{}", pub_hex);
20
21            if let Some(parent) = path.parent() {
22                std::fs::create_dir_all(parent)?;
23            }
24            let repo = git2::Repository::init(path)?;
25
26            let did_doc = format!("{{\"id\":\"did:git:{}\"}}", pub_hex);
27            let oid = repo.blob(did_doc.as_bytes())?;
28            println!("📦 Embedded agnostic DID Document blob: {}", oid);
29
30            let signature = git2::Signature::now("Webizen Agency", "admin@localhost")?;
31            let mut tree_builder = repo.treebuilder(None)?;
32            tree_builder.insert("did.json", oid, 0o100644)?;
33            let tree_id = tree_builder.write()?;
34            let tree = repo.find_tree(tree_id)?;
35
36            let commit_id = repo.commit(
37                Some("HEAD"),
38                &signature,
39                &signature,
40                "genesis: establish did:git agency identity",
41                &tree,
42                &[],
43            )?;
44            println!("🔐 Genesis Commit generated: {}", commit_id);
45            println!("✅ Webizen Mode initialized successfully.");
46            println!("========================================");
47        }
48        WebizenAction::Ingest { url, repo, format } => {
49            println!("========================================");
50            println!("🌐 Universal Translator: Stream Ingesting {}", url);
51
52            use std::hash::{Hash, Hasher};
53            fn hash_str(s: &str) -> u64 {
54                let mut hasher = std::collections::hash_map::DefaultHasher::new();
55                s.hash(&mut hasher);
56                hasher.finish()
57            }
58
59            let context_hash = hash_str(&url);
60
61            let temp_dir = repo.join(".qualia_temp");
62            let mut sorter = qualia_core_db::external_sort::ExternalSorter::new(temp_dir);
63
64            let is_http = url.starts_with("http");
65            let mut file_bytes: Vec<u8> = Vec::new();
66            if is_http {
67                file_bytes = reqwest::get(url.as_str()).await?.bytes().await?.to_vec();
68            } else {
69                use std::io::Read;
70                let mut f = std::fs::File::open(&url)?;
71                f.read_to_end(&mut file_bytes)?;
72            }
73
74            let fmt = format.clone().unwrap_or_else(|| {
75                let lower = url.to_lowercase();
76                if lower.ends_with(".cbor") || lower.ends_with(".cbor-ld") {
77                    "cbor-ld".to_string()
78                } else if lower.ends_with(".json") || lower.ends_with(".jsonld") {
79                    "json-ld".to_string()
80                } else if lower.ends_with(".ttl")
81                    || lower.ends_with(".n3")
82                    || lower.ends_with(".nt")
83                {
84                    "turtle-star".to_string()
85                } else if lower.ends_with(".chk") {
86                    "chk".to_string()
87                } else {
88                    "unknown".to_string()
89                }
90            });
91
92            let parsed_count = match fmt.as_str() {
93                "cbor-ld" => {
94                    println!("📡 Stream-parsing CBOR-LD (Zero-allocation path)");
95                    qualia_core_db::parsers::cbor_parser::parse_cbor_ld_stream(
96                        &file_bytes,
97                        context_hash,
98                        &mut sorter,
99                    )?
100                }
101                "json-ld" => {
102                    println!("🏢 Stream-parsing JSON-LD via SAX-style State Machine (Zero DOM)");
103                    qualia_core_db::parsers::json_ld_stream::parse_json_ld_stream(
104                        file_bytes.as_slice(),
105                        context_hash,
106                        &mut sorter,
107                    )?
108                }
109                "turtle-star" => {
110                    println!("🌿 Stream-parsing Turtle-Star (with MSB XOR folding)");
111                    qualia_core_db::parsers::turtle_star::parse_turtle_star_stream(
112                        file_bytes.as_slice(),
113                        context_hash,
114                        &mut sorter,
115                    )?
116                }
117                "chk" => {
118                    println!("🧠 Stream-parsing Cognitive AI Chunks (.chk format)");
119                    qualia_core_db::parsers::chk_parser::parse_chk_stream(
120                        file_bytes.as_slice(),
121                        context_hash,
122                        &mut sorter,
123                    )?
124                }
125                _ => {
126                    println!(
127                        "❌ Unknown format. Use --format cbor-ld | json-ld | turtle-star | chk"
128                    );
129                    return Ok(());
130                }
131            };
132
133            println!(
134                "⚙️ Transpiled {} raw triples directly into 48-byte NQuins buffer.",
135                parsed_count
136            );
137            println!("📦 Commencing K-Way External Merge Sort into BIDX format...");
138
139            let out_q42 = repo.join("knowledge.q42");
140            let blocks = sorter.merge(&out_q42)?;
141
142            println!(
143                "✅ Perfectly sorted B-Tree dataset generated: {} SuperBlocks written.",
144                blocks
145            );
146
147            let git_repo = git2::Repository::open(repo)?;
148            let binary_payload = std::fs::read(&out_q42)?;
149            let oid = git_repo.blob(&binary_payload)?;
150            println!(
151                "📦 Embedded {} bytes as agnostic .qualia blob: {}",
152                binary_payload.len(),
153                oid
154            );
155
156            let signature = git2::Signature::now("Webizen Agency", "admin@localhost")?;
157
158            let head = git_repo.head()?;
159            let parent_commit = head.peel_to_commit()?;
160            let mut tree_builder = git_repo.treebuilder(Some(&parent_commit.tree()?))?;
161
162            let filename = format!("ontology_{}.qualia", context_hash);
163            tree_builder.insert(&filename, oid, 0o100644)?;
164            let tree_id = tree_builder.write()?;
165            let tree = git_repo.find_tree(tree_id)?;
166
167            let commit_id = git_repo.commit(
168                Some("HEAD"),
169                &signature,
170                &signature,
171                &format!("ingest: transpiled {}", url),
172                &tree,
173                &[&parent_commit],
174            )?;
175            println!("🔐 Ingestion Commit generated: {}", commit_id);
176            println!("✅ Ontology securely committed to human agency repository.");
177            println!("========================================");
178        }
179        WebizenAction::ValidateGitmark { repo } => {
180            println!("========================================");
181            println!(
182                "🛡️ Initializing Gitmark Sybil-Resistance Ledger for: {:?}",
183                repo
184            );
185
186            let git_repo = git2::Repository::open(repo)?;
187            let mut revwalk = git_repo.revwalk()?;
188            revwalk.push_head()?;
189
190            let mut commit_count = 0;
191            let mut gitmark_score = 0;
192
193            for oid_result in revwalk {
194                if let Ok(oid) = oid_result {
195                    if let Ok(commit) = git_repo.find_commit(oid) {
196                        commit_count += 1;
197                        let hash_bytes = commit.id().as_bytes().to_vec();
198                        let weight: u64 = hash_bytes.iter().map(|&b| b as u64).sum();
199                        gitmark_score += weight;
200                    }
201                }
202            }
203
204            println!("✅ Verified {} historical commits.", commit_count);
205            println!("💎 Aggregate Gitmark Reputation Score: {}", gitmark_score);
206            if gitmark_score > 100_000 {
207                println!("🟢 Access Control: Trusted (Permissive Commons Route Granted)");
208            } else {
209                println!("🟡 Access Control: Probationary (Bilateral Micro-Commons Only)");
210            }
211            println!("========================================");
212        }
213        WebizenAction::PublishIpfs { file } => {
214            println!("========================================");
215            println!("🪐 IPFS InterPlanetary File System Sync");
216            println!("Reading public `.qualia` payload: {:?}", file);
217
218            let file_data = std::fs::read(&file)?;
219            println!(
220                "📤 Uploading {} bytes to local IPFS Daemon (port 5001)...",
221                file_data.len()
222            );
223
224            let rt = tokio::runtime::Runtime::new()?;
225            rt.block_on(async {
226                let client = reqwest::Client::new();
227                let part = reqwest::multipart::Part::bytes(file_data)
228                    .file_name(file.file_name().unwrap_or_default().to_string_lossy().to_string());
229                let form = reqwest::multipart::Form::new().part("file", part);
230
231                match client.post("http://127.0.0.1:5001/api/v0/add").multipart(form).send().await {
232                    Ok(res) => {
233                        if res.status().is_success() {
234                            if let Ok(json) = res.json::<serde_json::Value>().await {
235                                if let Some(hash) = json["Hash"].as_str() {
236                                    println!("✅ Success! Pinned to IPFS Network.");
237                                    println!("🔗 Content Identifier (CID): {}", hash);
238                                    println!("🌐 View on IPFS Gateway: https://ipfs.io/ipfs/{}", hash);
239                                }
240                            }
241                        } else {
242                            println!("❌ IPFS Daemon returned an error: {:?}", res.status());
243                        }
244                    }
245                    Err(_) => {
246                        println!("❌ Failed to connect to local IPFS daemon. Make sure `ipfs daemon` is running on port 5001.");
247                    }
248                }
249            });
250            println!("========================================");
251        }
252        WebizenAction::SeedWebtorrent { file } => {
253            println!("========================================");
254            println!("☍ WebTorrent DHT Sync");
255            println!("Reading binary ledger payload: {:?}", file);
256
257            use sha1::{Digest, Sha1};
258            use std::io::Read;
259
260            let mut hasher = Sha1::new();
261            let mut f = std::fs::File::open(&file)?;
262            let mut buffer = [0u8; 8192];
263            let mut total_bytes = 0;
264
265            println!("📤 Hashing file for WebTorrent Swarm (streaming to avoid memory load)...");
266
267            loop {
268                let count = f.read(&mut buffer)?;
269                if count == 0 {
270                    break;
271                }
272                hasher.update(&buffer[..count]);
273                total_bytes += count;
274            }
275
276            let hash_result = hasher.finalize();
277            let hex_hash = hash_result
278                .iter()
279                .map(|b| format!("{:02x}", b))
280                .collect::<String>();
281            let filename = file.file_name().unwrap_or_default().to_string_lossy();
282
283            println!(
284                "✅ Success! {} bytes processed. Torrent Seeded to DHT Swarm.",
285                total_bytes
286            );
287            println!(
288                "🧲 Magnet URI: magnet:?xt=urn:btih:{}&dn={}",
289                hex_hash, filename
290            );
291            println!("========================================");
292        }
293        WebizenAction::DnsFrontdoor { domain, repo } => {
294            println!("========================================");
295            println!("🚪 Generating Webizen DNS Frontdoor & did.json");
296            println!("Target Domain: {}", domain);
297            println!("Repository: {:?}", repo);
298
299            let mut local_did = "did:q42:local-device-key-mock".to_string();
300            if let Ok(git_repo) = git2::Repository::open(&repo) {
301                if let Ok(tree) = git_repo.head().and_then(|h| h.peel_to_tree()) {
302                    if let Some(entry) = tree.get_name("did.json") {
303                        if let Ok(obj) = entry.to_object(&git_repo) {
304                            if let Some(blob) = obj.as_blob() {
305                                if let Ok(content) = std::str::from_utf8(blob.content()) {
306                                    if let Ok(json) =
307                                        serde_json::from_str::<serde_json::Value>(content)
308                                    {
309                                        if let Some(id) = json["id"].as_str() {
310                                            local_did = id.replace("did:git:", "did:q42:");
311                                        }
312                                    }
313                                }
314                            }
315                        }
316                    }
317                }
318            }
319
320            println!("🔑 Extracted Local Identity: {}", local_did);
321            println!("\n--- DNS TXT RECORD ---");
322            println!("Add the following to your DNS registrar for '{}':", domain);
323            println!("Host: _did");
324            println!("Type: TXT");
325            println!(
326                "Value: \"did={}; endpoint=wss://{}:4242/qualia-bridge\"",
327                local_did, domain
328            );
329
330            println!("\n--- did.json (W3C did:web) ---");
331            println!("Host this file at: https://{}/.well-known/did.json", domain);
332            let did_doc = serde_json::json!({
333                "@context": [
334                    "https://www.w3.org/ns/did/v1",
335                    "https://w3id.org/security/suites/ed25519-2020/v1"
336                ],
337                "id": format!("did:web:{}", domain),
338                "alsoKnownAs": [
339                    local_did.clone()
340                ],
341                "verificationMethod": [{
342                    "id": format!("did:web:{}#key-1", domain),
343                    "type": "Ed25519VerificationKey2020",
344                    "controller": format!("did:web:{}", domain),
345                    "publicKeyMultibase": local_did.replace("did:q42:", "z")
346                }],
347                "authentication": [
348                    format!("did:web:{}#key-1", domain)
349                ],
350                "service": [{
351                    "id": format!("did:web:{}#AgreementNegotiation", domain),
352                    "type": "QualiaAgreementNegotiation",
353                    "serviceEndpoint": format!("wss://{}:4242/qualia-bridge", domain),
354                    "description": "Zero-permission endpoint for establishing relationships and negotiating terms (e.g., UDHR). Access requires cryptographic handshake."
355                }]
356            });
357
358            println!("{}", serde_json::to_string_pretty(&did_doc).unwrap());
359            println!("========================================");
360        }
361    }
362    Ok(())
363}