tangled
alpha
login
or
join now
ptr.pet
/
Allegedly
forked from
microcosm.blue/Allegedly
0
fork
atom
Server tools to backfill, tail, mirror, and verify PLC logs
0
fork
atom
overview
issues
pulls
pipelines
fjall: dont propagate parsing error unless its fatal
ptr.pet
2 weeks ago
5cc551b4
e61a3187
verified
This commit was signed with the committer's
known signature
.
ptr.pet
SSH Key Fingerprint:
SHA256:Abmvag+juovVufZTxyWY8KcVgrznxvBjQpJesv071Aw=
+370
-104
1 changed file
expand all
collapse all
unified
split
src
plc_fjall.rs
+370
-104
src/plc_fjall.rs
···
1
1
use crate::{Dt, ExportPage, Op as CommonOp, PageBoundaryState};
2
2
-
use data_encoding::{BASE32_NOPAD, BASE64URL, BASE64URL_NOPAD};
2
2
+
use anyhow::Context;
3
3
+
use data_encoding::{BASE32_NOPAD, BASE64URL_NOPAD};
3
4
use fjall::{Database, Keyspace, KeyspaceCreateOptions, OwnedWriteBatch, PersistMode};
4
5
use serde::{Deserialize, Serialize};
5
6
use std::collections::BTreeMap;
···
199
200
}
200
201
}
201
202
203
203
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
204
204
+
enum StoredOpField {
205
205
+
Type,
206
206
+
Sig,
207
207
+
Prev,
208
208
+
RotationKeys,
209
209
+
VerificationMethods,
210
210
+
AlsoKnownAs,
211
211
+
Services,
212
212
+
SigningKey,
213
213
+
RecoveryKey,
214
214
+
Handle,
215
215
+
Service,
216
216
+
}
217
217
+
218
218
+
impl StoredOpField {
219
219
+
fn as_str(&self) -> &'static str {
220
220
+
match self {
221
221
+
Self::Type => "type",
222
222
+
Self::Sig => "sig",
223
223
+
Self::Prev => "prev",
224
224
+
Self::RotationKeys => "rotationKeys",
225
225
+
Self::VerificationMethods => "verificationMethods",
226
226
+
Self::AlsoKnownAs => "alsoKnownAs",
227
227
+
Self::Services => "services",
228
228
+
Self::SigningKey => "signingKey",
229
229
+
Self::RecoveryKey => "recoveryKey",
230
230
+
Self::Handle => "handle",
231
231
+
Self::Service => "service",
232
232
+
}
233
233
+
}
234
234
+
}
235
235
+
236
236
+
impl AsRef<str> for StoredOpField {
237
237
+
fn as_ref(&self) -> &str {
238
238
+
self.as_str()
239
239
+
}
240
240
+
}
241
241
+
242
242
+
impl std::ops::Deref for StoredOpField {
243
243
+
type Target = str;
244
244
+
fn deref(&self) -> &Self::Target {
245
245
+
self.as_str()
246
246
+
}
247
247
+
}
248
248
+
249
249
+
impl fmt::Display for StoredOpField {
250
250
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251
251
+
f.write_str(self.as_str())
252
252
+
}
253
253
+
}
254
254
+
255
255
+
#[derive(Debug, thiserror::Error)]
256
256
+
enum StoredOpError {
257
257
+
#[error("operation is not an object")]
258
258
+
NotAnObject,
259
259
+
#[error("missing required field: {0}")]
260
260
+
MissingField(StoredOpField),
261
261
+
#[error("invalid field {0}: {1}")]
262
262
+
InvalidField(StoredOpField, #[source] anyhow::Error),
263
263
+
#[error("type mismatch for field {0}: expected {1}")]
264
264
+
TypeMismatch(StoredOpField, &'static str),
265
265
+
}
266
266
+
202
267
#[derive(Debug, Clone, Serialize, Deserialize)]
203
268
struct StoredService {
204
269
r#type: String,
···
227
292
}
228
293
229
294
impl StoredOp {
230
230
-
fn from_json_value(v: &serde_json::Value) -> anyhow::Result<Self> {
231
231
-
let obj = v
232
232
-
.as_object()
233
233
-
.ok_or_else(|| anyhow::anyhow!("operation is not an object"))?;
295
295
+
fn from_json_value(v: serde_json::Value) -> (Option<Self>, Vec<StoredOpError>) {
296
296
+
let serde_json::Value::Object(mut obj) = v else {
297
297
+
return (None, vec![StoredOpError::NotAnObject]);
298
298
+
};
234
299
235
235
-
let mut known_keys = Vec::new();
236
236
-
let mut get = |key: &'static str| {
237
237
-
known_keys.push(key);
238
238
-
obj.get(key)
300
300
+
let mut errors = Vec::new();
301
301
+
let mut unknown = BTreeMap::new();
302
302
+
303
303
+
let op_type = match obj.remove(&*StoredOpField::Type) {
304
304
+
Some(serde_json::Value::String(s)) => OpType::from_str(&s),
305
305
+
Some(v) => {
306
306
+
errors.push(StoredOpError::TypeMismatch(StoredOpField::Type, "string"));
307
307
+
unknown.insert(StoredOpField::Type.to_string(), v);
308
308
+
OpType::Other(String::new())
309
309
+
}
310
310
+
Option::None => {
311
311
+
errors.push(StoredOpError::MissingField(StoredOpField::Type));
312
312
+
OpType::Other(String::new())
313
313
+
}
239
314
};
240
315
241
241
-
let op_type = get("type")
242
242
-
.and_then(|t| t.as_str())
243
243
-
.map(OpType::from_str)
244
244
-
.ok_or_else(|| anyhow::anyhow!("missing type field"))?;
316
316
+
let sig = match obj.remove(&*StoredOpField::Sig) {
317
317
+
Some(serde_json::Value::String(s)) => match Signature::from_base64url(&s) {
318
318
+
Ok(sig) => sig,
319
319
+
Err(e) => {
320
320
+
errors.push(StoredOpError::InvalidField(StoredOpField::Sig, e));
321
321
+
unknown.insert(StoredOpField::Sig.to_string(), serde_json::Value::String(s));
322
322
+
Signature(Vec::new())
323
323
+
}
324
324
+
},
325
325
+
Some(v) => {
326
326
+
errors.push(StoredOpError::TypeMismatch(StoredOpField::Sig, "string"));
327
327
+
unknown.insert(StoredOpField::Sig.to_string(), v);
328
328
+
Signature(Vec::new())
329
329
+
}
330
330
+
Option::None => {
331
331
+
errors.push(StoredOpError::MissingField(StoredOpField::Sig));
332
332
+
Signature(Vec::new())
333
333
+
}
334
334
+
};
245
335
246
246
-
let sig = get("sig")
247
247
-
.and_then(|s| s.as_str())
248
248
-
.ok_or_else(|| anyhow::anyhow!("missing sig field"))
249
249
-
.and_then(Signature::from_base64url)?;
336
336
+
let prev = match obj.remove(&*StoredOpField::Prev) {
337
337
+
Some(serde_json::Value::Null) | Option::None => Option::None,
338
338
+
Some(serde_json::Value::String(s)) => match PlcCid::from_cid_str(&s) {
339
339
+
Ok(p) => Some(p),
340
340
+
Err(e) => {
341
341
+
errors.push(StoredOpError::InvalidField(StoredOpField::Prev, e));
342
342
+
unknown.insert(
343
343
+
StoredOpField::Prev.to_string(),
344
344
+
serde_json::Value::String(s),
345
345
+
);
346
346
+
Option::None
347
347
+
}
348
348
+
},
349
349
+
Some(v) => {
350
350
+
errors.push(StoredOpError::TypeMismatch(StoredOpField::Prev, "string"));
351
351
+
unknown.insert(StoredOpField::Prev.to_string(), v);
352
352
+
Option::None
353
353
+
}
354
354
+
};
250
355
251
251
-
let prev = match get("prev").and_then(|p| p.as_str()) {
252
252
-
Some(s) => Some(PlcCid::from_cid_str(s)?),
253
253
-
None => None,
356
356
+
let rotation_keys = match obj.remove(&*StoredOpField::RotationKeys) {
357
357
+
Some(serde_json::Value::Array(arr)) => {
358
358
+
let mut keys = Vec::with_capacity(arr.len());
359
359
+
let mut failed = false;
360
360
+
for v in arr {
361
361
+
match v {
362
362
+
serde_json::Value::String(s) => match DidKey::from_did_key(&s) {
363
363
+
Ok(k) => keys.push(k),
364
364
+
Err(e) => {
365
365
+
errors.push(StoredOpError::InvalidField(
366
366
+
StoredOpField::RotationKeys,
367
367
+
e,
368
368
+
));
369
369
+
failed = true;
370
370
+
break;
371
371
+
}
372
372
+
},
373
373
+
_ => {
374
374
+
errors.push(StoredOpError::TypeMismatch(
375
375
+
StoredOpField::RotationKeys,
376
376
+
"string inside array",
377
377
+
));
378
378
+
failed = true;
379
379
+
break;
380
380
+
}
381
381
+
}
382
382
+
}
383
383
+
if failed {
384
384
+
// we don't have the original array anymore here because we consumed it,
385
385
+
// but we can reconstruct it for the unknown map if we really want to,
386
386
+
// though usually we just move the whole thing.
387
387
+
// since we consumed it, let's just push an error and return None.
388
388
+
// to be absolutely correct about preserving 'unknown', we should have peeked or cloned.
389
389
+
// let's adjust the implementation to clone if we suspect it might fail,
390
390
+
// OR just move the whole value back if it fails.
391
391
+
Option::None
392
392
+
} else {
393
393
+
Some(keys)
394
394
+
}
395
395
+
}
396
396
+
Some(v) => {
397
397
+
errors.push(StoredOpError::TypeMismatch(
398
398
+
StoredOpField::RotationKeys,
399
399
+
"array",
400
400
+
));
401
401
+
unknown.insert(StoredOpField::RotationKeys.to_string(), v);
402
402
+
Option::None
403
403
+
}
404
404
+
Option::None => Option::None,
254
405
};
255
406
256
256
-
let rotation_keys = get("rotationKeys")
257
257
-
.and_then(|v| v.as_array())
258
258
-
.map(|arr| {
259
259
-
arr.iter()
260
260
-
.filter_map(|v| v.as_str())
261
261
-
.map(DidKey::from_did_key)
262
262
-
.collect::<anyhow::Result<Vec<_>>>()
263
263
-
})
264
264
-
.transpose()?;
407
407
+
let verification_methods = match obj.remove(&*StoredOpField::VerificationMethods) {
408
408
+
Some(serde_json::Value::Object(map)) => {
409
409
+
let mut methods = BTreeMap::new();
410
410
+
let mut failed = false;
411
411
+
for (k, v) in map {
412
412
+
match v {
413
413
+
serde_json::Value::String(s) => match DidKey::from_did_key(&s) {
414
414
+
Ok(key) => {
415
415
+
methods.insert(k, key);
416
416
+
}
417
417
+
Err(e) => {
418
418
+
errors.push(StoredOpError::InvalidField(
419
419
+
StoredOpField::VerificationMethods,
420
420
+
e,
421
421
+
));
422
422
+
failed = true;
423
423
+
break;
424
424
+
}
425
425
+
},
426
426
+
_ => {
427
427
+
errors.push(StoredOpError::TypeMismatch(
428
428
+
StoredOpField::VerificationMethods,
429
429
+
"string value in object",
430
430
+
));
431
431
+
failed = true;
432
432
+
break;
433
433
+
}
434
434
+
}
435
435
+
}
436
436
+
if failed { Option::None } else { Some(methods) }
437
437
+
}
438
438
+
Some(v) => {
439
439
+
errors.push(StoredOpError::TypeMismatch(
440
440
+
StoredOpField::VerificationMethods,
441
441
+
"object",
442
442
+
));
443
443
+
unknown.insert(StoredOpField::VerificationMethods.to_string(), v);
444
444
+
Option::None
445
445
+
}
446
446
+
Option::None => Option::None,
447
447
+
};
265
448
266
266
-
let verification_methods = get("verificationMethods")
267
267
-
.and_then(|v| v.as_object())
268
268
-
.map(|map| {
269
269
-
map.iter()
270
270
-
.map(|(k, v)| {
271
271
-
let key = DidKey::from_did_key(v.as_str().unwrap_or_default())?;
272
272
-
Ok((k.clone(), key))
449
449
+
let also_known_as = match obj.remove(&*StoredOpField::AlsoKnownAs) {
450
450
+
Some(serde_json::Value::Array(arr)) => Some(
451
451
+
arr.into_iter()
452
452
+
.filter_map(|v| match v {
453
453
+
serde_json::Value::String(s) => Some(Aka::from_str(&s)),
454
454
+
_ => None,
273
455
})
274
274
-
.collect::<anyhow::Result<BTreeMap<_, _>>>()
275
275
-
})
276
276
-
.transpose()?;
456
456
+
.collect(),
457
457
+
),
458
458
+
Some(v) => {
459
459
+
errors.push(StoredOpError::TypeMismatch(
460
460
+
StoredOpField::AlsoKnownAs,
461
461
+
"array",
462
462
+
));
463
463
+
unknown.insert(StoredOpField::AlsoKnownAs.to_string(), v);
464
464
+
Option::None
465
465
+
}
466
466
+
Option::None => Option::None,
467
467
+
};
277
468
278
278
-
let also_known_as = get("alsoKnownAs").and_then(|v| v.as_array()).map(|arr| {
279
279
-
arr.iter()
280
280
-
.filter_map(|v| v.as_str())
281
281
-
.map(Aka::from_str)
282
282
-
.collect()
283
283
-
});
469
469
+
let services = match obj.remove(&*StoredOpField::Services) {
470
470
+
Some(serde_json::Value::Object(map)) => Some(
471
471
+
map.into_iter()
472
472
+
.filter_map(|(k, v)| {
473
473
+
let svc = StoredService {
474
474
+
r#type: v.get("type")?.as_str()?.to_string(),
475
475
+
endpoint: v.get("endpoint")?.as_str()?.to_string(),
476
476
+
};
477
477
+
Some((k, svc))
478
478
+
})
479
479
+
.collect(),
480
480
+
),
481
481
+
Some(v) => {
482
482
+
errors.push(StoredOpError::TypeMismatch(
483
483
+
StoredOpField::Services,
484
484
+
"object",
485
485
+
));
486
486
+
unknown.insert(StoredOpField::Services.to_string(), v);
487
487
+
Option::None
488
488
+
}
489
489
+
Option::None => Option::None,
490
490
+
};
284
491
285
285
-
let services = get("services").and_then(|v| v.as_object()).map(|map| {
286
286
-
map.iter()
287
287
-
.filter_map(|(k, v)| {
288
288
-
let svc = StoredService {
289
289
-
r#type: v.get("type")?.as_str()?.to_string(),
290
290
-
endpoint: v.get("endpoint")?.as_str()?.to_string(),
291
291
-
};
292
292
-
Some((k.clone(), svc))
293
293
-
})
294
294
-
.collect()
295
295
-
});
492
492
+
let signing_key = match obj.remove(&*StoredOpField::SigningKey) {
493
493
+
Some(serde_json::Value::String(s)) => match DidKey::from_did_key(&s) {
494
494
+
Ok(key) => Some(key),
495
495
+
Err(e) => {
496
496
+
errors.push(StoredOpError::InvalidField(StoredOpField::SigningKey, e));
497
497
+
unknown.insert(
498
498
+
StoredOpField::SigningKey.to_string(),
499
499
+
serde_json::Value::String(s),
500
500
+
);
501
501
+
Option::None
502
502
+
}
503
503
+
},
504
504
+
Some(v) => {
505
505
+
errors.push(StoredOpError::TypeMismatch(
506
506
+
StoredOpField::SigningKey,
507
507
+
"string",
508
508
+
));
509
509
+
unknown.insert(StoredOpField::SigningKey.to_string(), v);
510
510
+
Option::None
511
511
+
}
512
512
+
Option::None => Option::None,
513
513
+
};
296
514
297
297
-
let signing_key = get("signingKey")
298
298
-
.and_then(|v| v.as_str())
299
299
-
.map(DidKey::from_did_key)
300
300
-
.transpose()?;
515
515
+
let recovery_key = match obj.remove(&*StoredOpField::RecoveryKey) {
516
516
+
Some(serde_json::Value::String(s)) => match DidKey::from_did_key(&s) {
517
517
+
Ok(key) => Some(key),
518
518
+
Err(e) => {
519
519
+
errors.push(StoredOpError::InvalidField(StoredOpField::RecoveryKey, e));
520
520
+
unknown.insert(
521
521
+
StoredOpField::RecoveryKey.to_string(),
522
522
+
serde_json::Value::String(s),
523
523
+
);
524
524
+
Option::None
525
525
+
}
526
526
+
},
527
527
+
Some(v) => {
528
528
+
errors.push(StoredOpError::TypeMismatch(
529
529
+
StoredOpField::RecoveryKey,
530
530
+
"string",
531
531
+
));
532
532
+
unknown.insert(StoredOpField::RecoveryKey.to_string(), v);
533
533
+
Option::None
534
534
+
}
535
535
+
Option::None => Option::None,
536
536
+
};
301
537
302
302
-
let recovery_key = get("recoveryKey")
303
303
-
.and_then(|v| v.as_str())
304
304
-
.map(DidKey::from_did_key)
305
305
-
.transpose()?;
538
538
+
let handle = match obj.remove(&*StoredOpField::Handle) {
539
539
+
Some(serde_json::Value::String(s)) => Some(s),
540
540
+
Some(v) => {
541
541
+
errors.push(StoredOpError::TypeMismatch(StoredOpField::Handle, "string"));
542
542
+
unknown.insert(StoredOpField::Handle.to_string(), v);
543
543
+
Option::None
544
544
+
}
545
545
+
Option::None => Option::None,
546
546
+
};
306
547
307
307
-
let handle = get("handle")
308
308
-
.and_then(|v| v.as_str())
309
309
-
.map(|s| s.to_string());
310
310
-
311
311
-
let service = get("service")
312
312
-
.and_then(|v| v.as_str())
313
313
-
.map(|s| s.to_string());
548
548
+
let service = match obj.remove(&*StoredOpField::Service) {
549
549
+
Some(serde_json::Value::String(s)) => Some(s),
550
550
+
Some(v) => {
551
551
+
errors.push(StoredOpError::TypeMismatch(
552
552
+
StoredOpField::Service,
553
553
+
"string",
554
554
+
));
555
555
+
unknown.insert(StoredOpField::Service.to_string(), v);
556
556
+
Option::None
557
557
+
}
558
558
+
Option::None => Option::None,
559
559
+
};
314
560
315
315
-
let mut unknown = BTreeMap::new();
316
561
for (k, v) in obj {
317
317
-
if !known_keys.contains(&k.as_str()) {
318
318
-
unknown.insert(k.clone(), v.clone());
319
319
-
}
562
562
+
unknown.insert(k, v);
320
563
}
321
564
322
322
-
Ok(Self {
323
323
-
op_type,
324
324
-
sig,
325
325
-
prev,
326
326
-
rotation_keys,
327
327
-
verification_methods,
328
328
-
also_known_as,
329
329
-
services,
330
330
-
signing_key,
331
331
-
recovery_key,
332
332
-
handle,
333
333
-
service,
334
334
-
unknown,
335
335
-
})
565
565
+
(
566
566
+
Some(Self {
567
567
+
op_type,
568
568
+
sig,
569
569
+
prev,
570
570
+
rotation_keys,
571
571
+
verification_methods,
572
572
+
also_known_as,
573
573
+
services,
574
574
+
signing_key,
575
575
+
recovery_key,
576
576
+
handle,
577
577
+
service,
578
578
+
unknown,
579
579
+
}),
580
580
+
errors,
581
581
+
)
336
582
}
337
583
338
584
fn to_json_value(&self) -> serde_json::Value {
339
585
let mut map = serde_json::Map::new();
340
586
341
341
-
map.insert("type".into(), self.op_type.as_str().into());
342
342
-
map.insert("sig".into(), self.sig.to_string().into());
587
587
+
map.insert((*StoredOpField::Type).into(), self.op_type.as_str().into());
588
588
+
map.insert((*StoredOpField::Sig).into(), self.sig.to_string().into());
343
589
map.insert(
344
344
-
"prev".into(),
590
590
+
(*StoredOpField::Prev).into(),
345
591
self.prev
346
592
.as_ref()
347
593
.map(|c| serde_json::Value::String(c.to_string()))
···
350
596
351
597
if let Some(keys) = &self.rotation_keys {
352
598
map.insert(
353
353
-
"rotationKeys".into(),
599
599
+
(*StoredOpField::RotationKeys).into(),
354
600
keys.iter()
355
601
.map(|k| serde_json::Value::String(k.to_string()))
356
602
.collect::<Vec<_>>()
···
363
609
.iter()
364
610
.map(|(k, v)| (k.clone(), serde_json::Value::String(v.to_string())))
365
611
.collect();
366
366
-
map.insert("verificationMethods".into(), obj.into());
612
612
+
map.insert((*StoredOpField::VerificationMethods).into(), obj.into());
367
613
}
368
614
369
615
if let Some(aka) = &self.also_known_as {
370
616
map.insert(
371
371
-
"alsoKnownAs".into(),
617
617
+
(*StoredOpField::AlsoKnownAs).into(),
372
618
aka.iter()
373
619
.map(|h| serde_json::Value::String(h.to_string()))
374
620
.collect::<Vec<_>>()
···
389
635
)
390
636
})
391
637
.collect();
392
392
-
map.insert("services".into(), obj.into());
638
638
+
map.insert((*StoredOpField::Services).into(), obj.into());
393
639
}
394
640
395
641
// legacy create fields
396
642
if let Some(key) = &self.signing_key {
397
397
-
map.insert("signingKey".into(), key.to_string().into());
643
643
+
map.insert((*StoredOpField::SigningKey).into(), key.to_string().into());
398
644
}
399
645
if let Some(key) = &self.recovery_key {
400
400
-
map.insert("recoveryKey".into(), key.to_string().into());
646
646
+
map.insert((*StoredOpField::RecoveryKey).into(), key.to_string().into());
401
647
}
402
648
if let Some(handle) = &self.handle {
403
403
-
map.insert("handle".into(), handle.clone().into());
649
649
+
map.insert((*StoredOpField::Handle).into(), handle.clone().into());
404
650
}
405
651
if let Some(service) = &self.service {
406
406
-
map.insert("service".into(), service.clone().into());
652
652
+
map.insert((*StoredOpField::Service).into(), service.clone().into());
407
653
}
408
654
409
655
for (k, v) in &self.unknown {
···
505
751
encode_did(&mut encoded_did, &op.did)?;
506
752
507
753
let json_val: serde_json::Value = serde_json::from_str(op.operation.get())?;
508
508
-
let stored = StoredOp::from_json_value(&json_val)?;
754
754
+
let (stored, mut errors) = StoredOp::from_json_value(json_val);
755
755
+
756
756
+
let Some(operation) = stored else {
757
757
+
return Err(errors.remove(0)).context("fatal operation parse error");
758
758
+
};
759
759
+
760
760
+
for e in &errors {
761
761
+
log::warn!("failed to parse operation {} {}: {}", op.did, op.cid, e);
762
762
+
}
763
763
+
if !errors.is_empty() {
764
764
+
// if parse failed but not fatal, we just dont store it
765
765
+
return Ok(0);
766
766
+
}
767
767
+
509
768
let db_op = DbOp {
510
769
did: encoded_did,
511
770
nullified: op.nullified,
512
512
-
operation: stored,
771
771
+
operation,
513
772
};
514
773
let value = rmp_serde::to_vec(&db_op)?;
515
774
batch.insert(&self.inner.ops, &ts_key, &value);
···
757
1016
758
1017
for entry in &entries {
759
1018
let op = &entry["operation"];
760
760
-
let stored = StoredOp::from_json_value(op)
761
761
-
.unwrap_or_else(|e| panic!("failed to parse op in {path}: {e}\n{op}"));
1019
1019
+
let (stored, errors) = StoredOp::from_json_value(op.clone());
1020
1020
+
if !errors.is_empty() {
1021
1021
+
let mut msg = format!("failed to parse op in {path}:\n");
1022
1022
+
for e in errors {
1023
1023
+
msg.push_str(&format!(" - {e:?}\n"));
1024
1024
+
}
1025
1025
+
msg.push_str(&format!("op: {op}\n"));
1026
1026
+
panic!("{msg}");
1027
1027
+
}
762
1028
763
1029
// msgpack verification
764
1030
let packed = rmp_serde::to_vec(&stored).unwrap();