@ibgib/core-gib 0.1.27 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sync/sync-helpers.d.mts +7 -1
- package/dist/sync/sync-helpers.d.mts.map +1 -1
- package/dist/sync/sync-helpers.mjs +21 -1
- package/dist/sync/sync-helpers.mjs.map +1 -1
- package/dist/sync/sync-saga-coordinator.d.mts +23 -159
- package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +323 -130
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +12 -17
- package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
- package/dist/sync/sync-types.d.mts +6 -5
- package/dist/sync/sync-types.d.mts.map +1 -1
- package/package.json +1 -1
- package/src/sync/sync-helpers.mts +23 -4
- package/src/sync/sync-saga-coordinator.mts +367 -150
- package/src/sync/sync-saga-message/sync-saga-message-types.mts +13 -18
- package/src/sync/sync-types.mts +7 -7
|
@@ -6,7 +6,7 @@ import { putInSpace, getLatestAddrs, getFromSpace } from "../witness/space/space
|
|
|
6
6
|
import { SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN, } from "./sync-constants.mjs";
|
|
7
7
|
import { appendToTimeline, createTimeline } from "../timeline/timeline-api.mjs";
|
|
8
8
|
import { SyncConflictStrategy, SyncMode, SYNC_CONFLICT_STRATEGY_VALID_VALUES, } from "./sync-types.mjs";
|
|
9
|
-
import { getSyncIb, getTempSpaceName, isPastFrame } from "./sync-helpers.mjs";
|
|
9
|
+
import { getFullSyncSagaHistory, getSyncIb, getTempSpaceName, isPastFrame, putInSpace_dnasThenNonDnas, validateFullSyncSagaHistory } from "./sync-helpers.mjs";
|
|
10
10
|
import { getDeltaDependencyGraph, getDependencyGraph, toFlatGraph } from "../common/other/graph-helper.mjs";
|
|
11
11
|
import { getSyncSagaMessageIb } from "./sync-saga-message/sync-saga-message-helpers.mjs";
|
|
12
12
|
import { SYNC_SAGA_MSG_ATOM } from "./sync-saga-message/sync-saga-message-constants.mjs";
|
|
@@ -171,7 +171,12 @@ export class SyncSagaCoordinator {
|
|
|
171
171
|
if (logalot) {
|
|
172
172
|
console.log(`${lc} Handler returned null (Saga End). (I: 43da8bb6c846b1fe7766332643be0e26)`);
|
|
173
173
|
}
|
|
174
|
-
|
|
174
|
+
// does this ever hit now?
|
|
175
|
+
return null; /* <<<< returns early */
|
|
176
|
+
}
|
|
177
|
+
else if (contextResult.nextFrameInfo?.sagaComplete) {
|
|
178
|
+
// this is the current proper workflow I believe as of 01/22/2026
|
|
179
|
+
return null; /* <<<< returns early */
|
|
175
180
|
}
|
|
176
181
|
// #region error conditions throw
|
|
177
182
|
if (contextResult.errorMsg) {
|
|
@@ -180,9 +185,6 @@ export class SyncSagaCoordinator {
|
|
|
180
185
|
else if (!contextResult.nextFrameInfo) {
|
|
181
186
|
throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: 5740542f5eb8ccb41dfec188d87c1e26)`);
|
|
182
187
|
}
|
|
183
|
-
else if (contextResult.nextFrameInfo?.responseWasNull) {
|
|
184
|
-
throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.responseWasNull? logic flow should not have gotten here. (E: ae06748d8c0c5e70c92322c8fb0cb426)`);
|
|
185
|
-
}
|
|
186
188
|
// #endregion error conditions throw
|
|
187
189
|
// create the return context
|
|
188
190
|
const { frame, payloadIbGibsDomain } = contextResult.nextFrameInfo;
|
|
@@ -417,8 +419,8 @@ export class SyncSagaCoordinator {
|
|
|
417
419
|
else if (!contextResult.nextFrameInfo) {
|
|
418
420
|
throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: c287a82e823e662a77923278e2418826)`);
|
|
419
421
|
}
|
|
420
|
-
else if (contextResult.nextFrameInfo?.
|
|
421
|
-
throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.
|
|
422
|
+
else if (contextResult.nextFrameInfo?.sagaComplete) {
|
|
423
|
+
throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.sagaComplete? logic flow should not have gotten here. (E: 104a32381db816b7183435e805b3d626)`);
|
|
422
424
|
}
|
|
423
425
|
// #endregion error conditions throw
|
|
424
426
|
// we have another frame to process and send out, with possibly
|
|
@@ -1333,69 +1335,6 @@ export class SyncSagaCoordinator {
|
|
|
1333
1335
|
}
|
|
1334
1336
|
}
|
|
1335
1337
|
}
|
|
1336
|
-
async getPayloadsForRequestedInfos({ deltaRequestAddrInfos, mySpace, }) {
|
|
1337
|
-
const lc = `${this.lc}[${this.getPayloadsForRequestedInfos.name}]`;
|
|
1338
|
-
try {
|
|
1339
|
-
if (logalot) {
|
|
1340
|
-
console.log(`${lc} starting... (I: 4fe13d0d80050f20a8b74ba80cee5826)`);
|
|
1341
|
-
}
|
|
1342
|
-
/**
|
|
1343
|
-
* graph of ibgibs we will send to the receiver. addr-based, so will
|
|
1344
|
-
* already be unique (no need to call `unique` on the domains
|
|
1345
|
-
* ibgibs)
|
|
1346
|
-
*/
|
|
1347
|
-
const outgoingPayloadIbGibsDomainGraph = {};
|
|
1348
|
-
for (const { addr, latestAddrAlreadyHave } of deltaRequestAddrInfos) {
|
|
1349
|
-
let deltaDepGraph;
|
|
1350
|
-
if (latestAddrAlreadyHave) {
|
|
1351
|
-
// already has some, so only get the delta
|
|
1352
|
-
// remember: if we didn't have the other's latest addr, then
|
|
1353
|
-
// this would be in the conflicts not requested addrs
|
|
1354
|
-
deltaDepGraph = await getDeltaDependencyGraph({
|
|
1355
|
-
ibGibAddr: addr,
|
|
1356
|
-
latestCommonFrameAddr: latestAddrAlreadyHave,
|
|
1357
|
-
space: mySpace,
|
|
1358
|
-
live: true,
|
|
1359
|
-
});
|
|
1360
|
-
}
|
|
1361
|
-
else {
|
|
1362
|
-
// doesn't have anything, so get the entire dependency graph
|
|
1363
|
-
// INEFFICIENT: we've already gotten all of the domain
|
|
1364
|
-
// dependencies in initDomainGraph, but getDependencyGraph
|
|
1365
|
-
// only works against a space so we are going to rerun this.
|
|
1366
|
-
// an optimization would be to adapt/create a new
|
|
1367
|
-
// getDependencyGraph to work against an existing flat ibgib
|
|
1368
|
-
// map.
|
|
1369
|
-
deltaDepGraph = await getDependencyGraph({
|
|
1370
|
-
ibGibAddr: addr,
|
|
1371
|
-
space: mySpace,
|
|
1372
|
-
live: true,
|
|
1373
|
-
});
|
|
1374
|
-
}
|
|
1375
|
-
const depGraphSize = Object.keys(deltaDepGraph).length;
|
|
1376
|
-
if (depGraphSize === 0) {
|
|
1377
|
-
throw new Error(`(UNEXPECTED) couldn't get requested addrs in mySpace (${mySpace.ib})? How did the receiver know to ask for these addrs if they weren't in our original graph? (E: 281eaebcdf77dd73e8245b2872100826)`);
|
|
1378
|
-
}
|
|
1379
|
-
else {
|
|
1380
|
-
// we have dependencies!
|
|
1381
|
-
Object.values(deltaDepGraph).forEach(x => {
|
|
1382
|
-
outgoingPayloadIbGibsDomainGraph[getIbGibAddr({ ibGib: x })] = x;
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
const result = Object.values(outgoingPayloadIbGibsDomainGraph);
|
|
1387
|
-
return result;
|
|
1388
|
-
}
|
|
1389
|
-
catch (error) {
|
|
1390
|
-
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
1391
|
-
throw error;
|
|
1392
|
-
}
|
|
1393
|
-
finally {
|
|
1394
|
-
if (logalot) {
|
|
1395
|
-
console.log(`${lc} complete.`);
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
1338
|
/**
|
|
1400
1339
|
* Handles the `Delta` frame.
|
|
1401
1340
|
*
|
|
@@ -1451,25 +1390,33 @@ export class SyncSagaCoordinator {
|
|
|
1451
1390
|
// V1 timelines carry full history in `past`.
|
|
1452
1391
|
const pastAddrs = sagaIbGib.rel8ns?.past || [];
|
|
1453
1392
|
console.log(`${lc} [TEST DEBUG] pastAddrs count: ${pastAddrs.length}`);
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1393
|
+
const sagaHistory = await getFullSyncSagaHistory({
|
|
1394
|
+
sagaIbGib,
|
|
1395
|
+
space: mySpace,
|
|
1396
|
+
});
|
|
1397
|
+
// #region validate/sanity sagaHistory
|
|
1398
|
+
if (sagaHistory.length === 0) {
|
|
1399
|
+
throw new Error(`(UNEXPECTED) sagaHistory.length is 0? We're in handleDeltaFrame. So we should have at least init and ack. (E: 815735c9cf756b275719bf434f180826)`);
|
|
1400
|
+
}
|
|
1401
|
+
if (sagaHistory.length === 1) {
|
|
1402
|
+
throw new Error(`(UNEXPECTED) sagaHistory.length is 1? We're in handleDeltaFrame. So we should have at least init and ack. (E: 0e4ef8e3ed088e83b2cdcd18ecea9826)`);
|
|
1403
|
+
}
|
|
1404
|
+
// #endregion validate/sanity sagaHistory
|
|
1405
|
+
const ackGraphs = sagaHistory.filter(x => x.msgStones.at(0).data.stage === SyncStage.ack);
|
|
1406
|
+
// #region validate/sanity ackGraphs
|
|
1407
|
+
if (ackGraphs.length > 1) {
|
|
1408
|
+
throw new Error(`(UNEXPECTED) more than one ack stage found in sagaHistory? we're expecting exactly one. (E: 7150983bb3a841caf8acd60826ba4f26)`);
|
|
1409
|
+
}
|
|
1410
|
+
else if (ackGraphs.length === 0) {
|
|
1411
|
+
throw new Error(`(UNEXPECTED) couldn't find ack stage in sagaHistory? (E: 7d2da859196b86de28e7c8183af1e826)`);
|
|
1412
|
+
}
|
|
1413
|
+
if (ackGraphs[0].msgStones.length !== 1) {
|
|
1414
|
+
throw new Error(`(UNEXPECTED) ackGraph has more than one msg stone? only one expected right now. (E: f07d388abff8d26f98cbf6e8d3932826)`);
|
|
1415
|
+
}
|
|
1416
|
+
// #endregion validate/sanity ackGraphs
|
|
1417
|
+
const ackData = ackGraphs[0].msgStones[0].data;
|
|
1418
|
+
if (!ackData) {
|
|
1419
|
+
throw new Error(`(UNEXPECTED) ackData falsy? (E: f9af88427f66a8db1ba868b810e8b826)`);
|
|
1473
1420
|
}
|
|
1474
1421
|
if (ackData && ackData.conflicts) {
|
|
1475
1422
|
const optimisticConflicts = ackData.conflicts.filter(c => !c.terminal);
|
|
@@ -1529,17 +1476,7 @@ export class SyncSagaCoordinator {
|
|
|
1529
1476
|
stage: SyncStage.delta,
|
|
1530
1477
|
payloadAddrs: outgoingPayload.map(p => getIbGibAddr({ ibGib: p })),
|
|
1531
1478
|
requests: hasMyRequests ? myRequests : undefined,
|
|
1532
|
-
proposeCommit: !hasMyRequests // If we are sending data but have no requests, we VALIDATE PROPOSAL?
|
|
1533
|
-
// Wait. If we send data, we are NOT committing yet.
|
|
1534
|
-
// We are sending data. The OTHER side must ingest it.
|
|
1535
|
-
// So proposeCommit = true?
|
|
1536
|
-
// "Here is the data. I'm done. If you are good, let's commit."
|
|
1537
|
-
// Yes.
|
|
1538
1479
|
};
|
|
1539
|
-
// BUT if `peerProposesCommit` was true, and we are sending data, we are effectively rejecting/delaying it.
|
|
1540
|
-
// We just send the Delta. Peer receives it, ingests, sees ProposeCommit=True (from us), and then Commits.
|
|
1541
|
-
// So yes, proposeCommit = true.
|
|
1542
|
-
responseDeltaData.proposeCommit = true;
|
|
1543
1480
|
const deltaStone = await this.createSyncMsgStone({
|
|
1544
1481
|
data: responseDeltaData,
|
|
1545
1482
|
localSpace: mySpace,
|
|
@@ -1552,41 +1489,43 @@ export class SyncSagaCoordinator {
|
|
|
1552
1489
|
localSpace: mySpace,
|
|
1553
1490
|
metaspace,
|
|
1554
1491
|
});
|
|
1555
|
-
// Build control payloads: frame + its dependencies (msg stone, identity)
|
|
1556
|
-
const payloadIbGibsControl = [deltaFrame, deltaStone];
|
|
1557
|
-
if (identity) {
|
|
1558
|
-
payloadIbGibsControl.push(identity);
|
|
1559
|
-
}
|
|
1560
|
-
// return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: outgoingPayload };
|
|
1561
1492
|
return { frame: deltaFrame, payloadIbGibsDomain: outgoingPayload };
|
|
1562
|
-
// throw new Error(`not implemented (E: 2b38a8afb6d84efcee5ab51673387826)`);
|
|
1563
1493
|
}
|
|
1564
1494
|
else {
|
|
1565
1495
|
// We have nothing to send.
|
|
1566
1496
|
if (peerProposesCommit) {
|
|
1567
1497
|
// Peer is done. We are done. -> Commit.
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
};
|
|
1573
|
-
const commitStone = await this.createSyncMsgStone({
|
|
1574
|
-
data: commitData,
|
|
1575
|
-
localSpace: mySpace,
|
|
1576
|
-
metaspace
|
|
1498
|
+
// one last validate entire history?
|
|
1499
|
+
const history = await getFullSyncSagaHistory({
|
|
1500
|
+
sagaIbGib,
|
|
1501
|
+
space: mySpace,
|
|
1577
1502
|
});
|
|
1578
|
-
const
|
|
1579
|
-
|
|
1580
|
-
msgStones: [commitStone],
|
|
1581
|
-
sessionIdentity: identity,
|
|
1582
|
-
localSpace: mySpace,
|
|
1583
|
-
metaspace
|
|
1503
|
+
const validationErrors = await validateFullSyncSagaHistory({
|
|
1504
|
+
history,
|
|
1584
1505
|
});
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1506
|
+
if (validationErrors.length > 0) {
|
|
1507
|
+
const errorCommitFrame = await this.createCommitFrame({
|
|
1508
|
+
sagaIbGib,
|
|
1509
|
+
errors: validationErrors,
|
|
1510
|
+
metaspace, mySpace,
|
|
1511
|
+
identity,
|
|
1512
|
+
});
|
|
1513
|
+
return { frame: errorCommitFrame, }; /* <<<< returns early */
|
|
1589
1514
|
}
|
|
1515
|
+
await this.executeLocalCommit({
|
|
1516
|
+
sagaHistory: history,
|
|
1517
|
+
deltaFrame: sagaIbGib,
|
|
1518
|
+
localTempSpace: myTempSpace,
|
|
1519
|
+
localSpace: mySpace,
|
|
1520
|
+
metaspace,
|
|
1521
|
+
});
|
|
1522
|
+
const commitFrame = await this.createCommitFrame({
|
|
1523
|
+
sagaIbGib,
|
|
1524
|
+
errors: undefined,
|
|
1525
|
+
metaspace,
|
|
1526
|
+
mySpace,
|
|
1527
|
+
identity,
|
|
1528
|
+
});
|
|
1590
1529
|
return { frame: commitFrame, };
|
|
1591
1530
|
}
|
|
1592
1531
|
else {
|
|
@@ -1660,28 +1599,219 @@ export class SyncSagaCoordinator {
|
|
|
1660
1599
|
}
|
|
1661
1600
|
}
|
|
1662
1601
|
}
|
|
1602
|
+
/**
|
|
1603
|
+
* should throw if fails
|
|
1604
|
+
*/
|
|
1605
|
+
async executeLocalCommit({ deltaFrame, sagaHistory, metaspace, localSpace, localTempSpace, identity, }) {
|
|
1606
|
+
const lc = `${this.lc}[${this.executeLocalCommit.name}]`;
|
|
1607
|
+
try {
|
|
1608
|
+
if (logalot) {
|
|
1609
|
+
console.log(`${lc} starting... (I: 6734980446b86a63c1af6e2e206de826)`);
|
|
1610
|
+
}
|
|
1611
|
+
// #region validate/sanity
|
|
1612
|
+
if (!deltaFrame.data) {
|
|
1613
|
+
throw new Error(`(UNEXPECTED) deltaFrame.data falsy? (E: a8be68d48668d93d992d793834823826)`);
|
|
1614
|
+
}
|
|
1615
|
+
// #endregion validate/sanity
|
|
1616
|
+
// * move all payload addrs from temp space to local space
|
|
1617
|
+
// * register each and every iteration of each timeline (including
|
|
1618
|
+
// stones, which are like their own sealed timeline of length 1)
|
|
1619
|
+
const allPayloadAddrsDomainTransferred = [];
|
|
1620
|
+
const fnAddPayloadAddr = (addr) => {
|
|
1621
|
+
if (!allPayloadAddrsDomainTransferred.includes(addr)) {
|
|
1622
|
+
allPayloadAddrsDomainTransferred.push(addr);
|
|
1623
|
+
}
|
|
1624
|
+
};
|
|
1625
|
+
sagaHistory.forEach(x => {
|
|
1626
|
+
if (!x.sagaIbGib.data) {
|
|
1627
|
+
throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: 34d7f8cdee14717ce828878d98f89826)`);
|
|
1628
|
+
}
|
|
1629
|
+
x.msgStones.forEach(msgStone => {
|
|
1630
|
+
if (!msgStone.data) {
|
|
1631
|
+
throw new Error(`(UNEXPECTED) msgStone.data falsy? (E: 21406101f91847514cc759c8a7382f26)`);
|
|
1632
|
+
}
|
|
1633
|
+
if (msgStone.data.stage === SyncStage.ack) {
|
|
1634
|
+
const ackData = msgStone.data;
|
|
1635
|
+
if (ackData.pushOfferInfos && ackData.pushOfferInfos.length > 0) {
|
|
1636
|
+
ackData.pushOfferInfos.forEach(info => {
|
|
1637
|
+
info.addrs.forEach(addr => fnAddPayloadAddr(addr));
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
else if (msgStone.data.stage === SyncStage.delta) {
|
|
1642
|
+
const deltaData = msgStone.data;
|
|
1643
|
+
if (deltaData.payloadAddrsDomain && deltaData.payloadAddrsDomain.length > 0) {
|
|
1644
|
+
deltaData.payloadAddrsDomain.forEach(addr => fnAddPayloadAddr(addr));
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
});
|
|
1648
|
+
});
|
|
1649
|
+
// at this point, we have a list of ALL payload addrs retrieved.
|
|
1650
|
+
let allPayloadIbGibsDomainTransferred = [];
|
|
1651
|
+
const resGetAllTransferred = await getFromSpace({ addrs: allPayloadAddrsDomainTransferred, space: localTempSpace });
|
|
1652
|
+
if (resGetAllTransferred.success && resGetAllTransferred.ibGibs && resGetAllTransferred.ibGibs.length === allPayloadAddrsDomainTransferred.length) {
|
|
1653
|
+
allPayloadIbGibsDomainTransferred = resGetAllTransferred.ibGibs.concat();
|
|
1654
|
+
}
|
|
1655
|
+
else {
|
|
1656
|
+
// errored out, gather info
|
|
1657
|
+
if (!resGetAllTransferred.rawResultIbGib) {
|
|
1658
|
+
throw new Error(`(UNEXPECTED) !resGetAllTransferred.rawResultIbGib falsy? (E: dc6cf8729668f4fbe8c024f887d97a26)`);
|
|
1659
|
+
}
|
|
1660
|
+
const { addrsNotFound, addrsErrored, errors } = resGetAllTransferred.rawResultIbGib.data;
|
|
1661
|
+
throw new Error(`(UNEXPECTED) we couldn't get all addrs transferred throughout the saga from the tempspace (${localTempSpace.ib})? addrsNotFound: ${addrsNotFound ?? []}. addrsErrored: ${addrsErrored ?? []}. errors: ${errors ?? []}(E: 222e341e634862b4d88ae7282584d826)`);
|
|
1662
|
+
}
|
|
1663
|
+
// now we have all ibgibs transferred, first put them all the local space
|
|
1664
|
+
const { payload_Dnas, payload_NonDnas } = await putInSpace_dnasThenNonDnas({
|
|
1665
|
+
ibGibs: allPayloadIbGibsDomainTransferred,
|
|
1666
|
+
space: localSpace
|
|
1667
|
+
});
|
|
1668
|
+
const { mapWithTjp_NoDna, mapWithTjp_YesDna, mapWithoutTjps } = splitPerTjpAndOrDna({ ibGibs: payload_NonDnas, filterPrimitives: true });
|
|
1669
|
+
// first register all non-tjp stones
|
|
1670
|
+
const nontjps = Object.values(mapWithoutTjps);
|
|
1671
|
+
for (const nontjp of nontjps) {
|
|
1672
|
+
await metaspace.registerNewIbGib({
|
|
1673
|
+
ibGib: nontjp,
|
|
1674
|
+
space: localSpace,
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
// next register each timeline in order...
|
|
1678
|
+
// ...first the ones without dna...
|
|
1679
|
+
const timelinesByTjpAddr_NoDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_NoDna) });
|
|
1680
|
+
const tjpAddrs_NoDna = Object.keys(timelinesByTjpAddr_NoDna);
|
|
1681
|
+
for (const tjpAddr_NoDna of tjpAddrs_NoDna) {
|
|
1682
|
+
const timelineIbGibs = timelinesByTjpAddr_NoDna[tjpAddr_NoDna];
|
|
1683
|
+
for (const ibGib of timelineIbGibs) {
|
|
1684
|
+
await metaspace.registerNewIbGib({
|
|
1685
|
+
ibGib,
|
|
1686
|
+
space: localSpace,
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
// ...then the ones WITH dna.
|
|
1691
|
+
const timelinesByTjpAddr_YesDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_YesDna) });
|
|
1692
|
+
const tjpAddrs_YesDna = Object.keys(timelinesByTjpAddr_YesDna);
|
|
1693
|
+
for (const tjpAddr_YesDna of tjpAddrs_YesDna) {
|
|
1694
|
+
const timelineIbGibs = timelinesByTjpAddr_YesDna[tjpAddr_YesDna];
|
|
1695
|
+
for (const ibGib of timelineIbGibs) {
|
|
1696
|
+
await metaspace.registerNewIbGib({
|
|
1697
|
+
ibGib,
|
|
1698
|
+
space: localSpace,
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
catch (error) {
|
|
1704
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
1705
|
+
throw error;
|
|
1706
|
+
}
|
|
1707
|
+
finally {
|
|
1708
|
+
if (logalot) {
|
|
1709
|
+
console.log(`${lc} complete.`);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
async createCommitFrame({ sagaIbGib, errors, metaspace, mySpace, identity, }) {
|
|
1714
|
+
const lc = `[${this.createCommitFrame.name}]`;
|
|
1715
|
+
try {
|
|
1716
|
+
if (logalot) {
|
|
1717
|
+
console.log(`${lc} starting... (I: 48fc57c023f80122135a284855757526)`);
|
|
1718
|
+
}
|
|
1719
|
+
const commitData = errors && errors.length > 0 ?
|
|
1720
|
+
{
|
|
1721
|
+
// errored
|
|
1722
|
+
sagaId: sagaIbGib.data.uuid,
|
|
1723
|
+
stage: SyncStage.commit,
|
|
1724
|
+
success: false,
|
|
1725
|
+
errors,
|
|
1726
|
+
} :
|
|
1727
|
+
{
|
|
1728
|
+
// not errored
|
|
1729
|
+
sagaId: sagaIbGib.data.uuid,
|
|
1730
|
+
stage: SyncStage.commit,
|
|
1731
|
+
success: true,
|
|
1732
|
+
};
|
|
1733
|
+
const commitStone = await this.createSyncMsgStone({
|
|
1734
|
+
data: commitData,
|
|
1735
|
+
localSpace: mySpace,
|
|
1736
|
+
metaspace
|
|
1737
|
+
});
|
|
1738
|
+
const commitFrame = await this.evolveSyncSagaIbGib({
|
|
1739
|
+
prevSagaIbGib: sagaIbGib,
|
|
1740
|
+
msgStones: [commitStone],
|
|
1741
|
+
sessionIdentity: identity,
|
|
1742
|
+
localSpace: mySpace,
|
|
1743
|
+
metaspace,
|
|
1744
|
+
});
|
|
1745
|
+
return commitFrame;
|
|
1746
|
+
}
|
|
1747
|
+
catch (error) {
|
|
1748
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
1749
|
+
throw error;
|
|
1750
|
+
}
|
|
1751
|
+
finally {
|
|
1752
|
+
if (logalot) {
|
|
1753
|
+
console.log(`${lc} complete.`);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1663
1757
|
async handleCommitFrame({ sagaIbGib, mySpace, myTempSpace, metaspace, identity, }) {
|
|
1664
1758
|
const lc = `${this.lc}[${this.handleCommitFrame.name}]`;
|
|
1665
1759
|
try {
|
|
1666
1760
|
if (logalot) {
|
|
1667
1761
|
console.log(`${lc} starting... (I: e179573bdd881202f8ba3168da1c3826)`);
|
|
1668
1762
|
}
|
|
1763
|
+
let resNextSagaFrameInfo;
|
|
1669
1764
|
// Sender Logic (Finalizing):
|
|
1670
1765
|
// If we are here, we received a Commit frame from the Peer.
|
|
1671
1766
|
// This implies the Peer has successfully committed.
|
|
1672
1767
|
// We should now:
|
|
1673
1768
|
// 1. Validate (implicitly done by receiving valid frame)
|
|
1674
1769
|
// 2. Perform our own cleanup (Temp -> Dest, if applicable)
|
|
1675
|
-
// 3. Return
|
|
1676
|
-
//
|
|
1770
|
+
// 3. Return saga completion.
|
|
1771
|
+
// one last validate entire history?
|
|
1772
|
+
const history = await getFullSyncSagaHistory({
|
|
1773
|
+
sagaIbGib,
|
|
1774
|
+
space: mySpace,
|
|
1775
|
+
});
|
|
1776
|
+
const validationErrors = await validateFullSyncSagaHistory({
|
|
1777
|
+
history,
|
|
1778
|
+
});
|
|
1779
|
+
if (validationErrors.length > 0) {
|
|
1780
|
+
const errorCommitFrame = await this.createCommitFrame({
|
|
1781
|
+
sagaIbGib,
|
|
1782
|
+
metaspace,
|
|
1783
|
+
mySpace,
|
|
1784
|
+
identity,
|
|
1785
|
+
errors: validationErrors,
|
|
1786
|
+
});
|
|
1787
|
+
return { frame: errorCommitFrame, }; /* <<<< returns early */
|
|
1788
|
+
}
|
|
1789
|
+
await this.executeLocalCommit({
|
|
1790
|
+
deltaFrame: sagaIbGib,
|
|
1791
|
+
sagaHistory: history,
|
|
1792
|
+
localSpace: mySpace,
|
|
1793
|
+
localTempSpace: myTempSpace,
|
|
1794
|
+
metaspace,
|
|
1795
|
+
});
|
|
1796
|
+
// todo: implement explicit cleanup logic here and in peer
|
|
1797
|
+
console.error(`${lc} NAG ERROR (NOT THROWN): implement cleanup logic, including add a cleanup method to the peer (E: 3a9a24befb98a981a88fbdbf52920e26)`);
|
|
1677
1798
|
if (logalot) {
|
|
1678
1799
|
console.log(`${lc} Peer committed. Finalizing saga locally. Saga Complete.`);
|
|
1679
1800
|
}
|
|
1680
|
-
|
|
1801
|
+
// the holy grail!
|
|
1802
|
+
return { sagaComplete: true };
|
|
1681
1803
|
}
|
|
1682
1804
|
catch (error) {
|
|
1683
|
-
|
|
1684
|
-
|
|
1805
|
+
const emsg = `${lc} ${extractErrorMsg(error)}`;
|
|
1806
|
+
console.error(emsg);
|
|
1807
|
+
const errorCommitFrame = await this.createCommitFrame({
|
|
1808
|
+
sagaIbGib,
|
|
1809
|
+
errors: [emsg],
|
|
1810
|
+
metaspace,
|
|
1811
|
+
mySpace,
|
|
1812
|
+
identity,
|
|
1813
|
+
});
|
|
1814
|
+
return { frame: errorCommitFrame };
|
|
1685
1815
|
}
|
|
1686
1816
|
finally {
|
|
1687
1817
|
if (logalot) {
|
|
@@ -1720,6 +1850,69 @@ export class SyncSagaCoordinator {
|
|
|
1720
1850
|
}
|
|
1721
1851
|
}
|
|
1722
1852
|
}
|
|
1853
|
+
async getPayloadsForRequestedInfos({ deltaRequestAddrInfos, mySpace, }) {
|
|
1854
|
+
const lc = `${this.lc}[${this.getPayloadsForRequestedInfos.name}]`;
|
|
1855
|
+
try {
|
|
1856
|
+
if (logalot) {
|
|
1857
|
+
console.log(`${lc} starting... (I: 4fe13d0d80050f20a8b74ba80cee5826)`);
|
|
1858
|
+
}
|
|
1859
|
+
/**
|
|
1860
|
+
* graph of ibgibs we will send to the receiver. addr-based, so will
|
|
1861
|
+
* already be unique (no need to call `unique` on the domains
|
|
1862
|
+
* ibgibs)
|
|
1863
|
+
*/
|
|
1864
|
+
const outgoingPayloadIbGibsDomainGraph = {};
|
|
1865
|
+
for (const { addr, latestAddrAlreadyHave } of deltaRequestAddrInfos) {
|
|
1866
|
+
let deltaDepGraph;
|
|
1867
|
+
if (latestAddrAlreadyHave) {
|
|
1868
|
+
// already has some, so only get the delta
|
|
1869
|
+
// remember: if we didn't have the other's latest addr, then
|
|
1870
|
+
// this would be in the conflicts not requested addrs
|
|
1871
|
+
deltaDepGraph = await getDeltaDependencyGraph({
|
|
1872
|
+
ibGibAddr: addr,
|
|
1873
|
+
latestCommonFrameAddr: latestAddrAlreadyHave,
|
|
1874
|
+
space: mySpace,
|
|
1875
|
+
live: true,
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
else {
|
|
1879
|
+
// doesn't have anything, so get the entire dependency graph
|
|
1880
|
+
// INEFFICIENT: we've already gotten all of the domain
|
|
1881
|
+
// dependencies in initDomainGraph, but getDependencyGraph
|
|
1882
|
+
// only works against a space so we are going to rerun this.
|
|
1883
|
+
// an optimization would be to adapt/create a new
|
|
1884
|
+
// getDependencyGraph to work against an existing flat ibgib
|
|
1885
|
+
// map.
|
|
1886
|
+
deltaDepGraph = await getDependencyGraph({
|
|
1887
|
+
ibGibAddr: addr,
|
|
1888
|
+
space: mySpace,
|
|
1889
|
+
live: true,
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
const depGraphSize = Object.keys(deltaDepGraph).length;
|
|
1893
|
+
if (depGraphSize === 0) {
|
|
1894
|
+
throw new Error(`(UNEXPECTED) couldn't get requested addrs in mySpace (${mySpace.ib})? How did the receiver know to ask for these addrs if they weren't in our original graph? (E: 281eaebcdf77dd73e8245b2872100826)`);
|
|
1895
|
+
}
|
|
1896
|
+
else {
|
|
1897
|
+
// we have dependencies!
|
|
1898
|
+
Object.values(deltaDepGraph).forEach(x => {
|
|
1899
|
+
outgoingPayloadIbGibsDomainGraph[getIbGibAddr({ ibGib: x })] = x;
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
const result = Object.values(outgoingPayloadIbGibsDomainGraph);
|
|
1904
|
+
return result;
|
|
1905
|
+
}
|
|
1906
|
+
catch (error) {
|
|
1907
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
1908
|
+
throw error;
|
|
1909
|
+
}
|
|
1910
|
+
finally {
|
|
1911
|
+
if (logalot) {
|
|
1912
|
+
console.log(`${lc} complete.`);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1723
1916
|
/**
|
|
1724
1917
|
* Evolves the saga timeline with a new frame.
|
|
1725
1918
|
*/
|