-
Notifications
You must be signed in to change notification settings - Fork 128
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into stateManagerPrivate-cdb-2751
- Loading branch information
Showing
6 changed files
with
222 additions
and
90 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { LogSyncer } from './log-syncer.js' | ||
import { ApplyLogToStateOpts, StateManipulator } from './state-manipulator.js' | ||
import { AnchorTimestampExtractor } from './anchor-timestamp-extractor.js' | ||
import { StreamState, StreamUtils } from '@ceramicnetwork/common' | ||
import { CID } from 'multiformats/cid' | ||
|
||
/** | ||
* Helper function for taking a StreamState and a tip CID and returning the new StreamState that | ||
* results from applying that tip to the state. | ||
* @param logSyncer | ||
* @param anchorTimestampExtractor | ||
* @param stateManipulator | ||
* @param state | ||
* @param tip | ||
* @param opts | ||
*/ | ||
export async function applyTipToState( | ||
logSyncer: LogSyncer, | ||
anchorTimestampExtractor: AnchorTimestampExtractor, | ||
stateManipulator: StateManipulator, | ||
state: StreamState, | ||
tip: CID, | ||
opts: ApplyLogToStateOpts | ||
): Promise<StreamState> { | ||
const streamID = StreamUtils.streamIdFromState(state) | ||
const logWithoutTimestamps = await logSyncer.syncLogUntilMatch( | ||
streamID, | ||
tip, | ||
state.log.map((logEntry) => logEntry.cid) | ||
) | ||
const logWithTimestamps = await anchorTimestampExtractor.verifyAnchorAndApplyTimestamps( | ||
logWithoutTimestamps | ||
) | ||
return stateManipulator.applyLogToState(state, logWithTimestamps, opts) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { LogSyncer } from './log-syncer.js' | ||
import { StateManipulator } from './state-manipulator.js' | ||
import { AnchorTimestampExtractor } from './anchor-timestamp-extractor.js' | ||
import { CeramicCommit, DiagnosticsLogger, StreamState, StreamUtils } from '@ceramicnetwork/common' | ||
import { StreamID } from '@ceramicnetwork/streamid' | ||
import { CID } from 'multiformats/cid' | ||
import { applyTipToState } from './apply-tip-helper.js' | ||
|
||
interface CommitStorer { | ||
storeCommit(data: any, streamId?: StreamID): Promise<CID> | ||
} | ||
|
||
/** | ||
* Class to contain all the logic for updating new commits to a stream. It notably however does not | ||
* manage the persistence of the state information, nor updating the cache or indexing. It is | ||
* purely stateless. | ||
*/ | ||
export class StreamUpdater { | ||
constructor( | ||
private readonly logger: DiagnosticsLogger, | ||
private readonly commitStorer: CommitStorer, | ||
private readonly logSyncer: LogSyncer, | ||
private readonly anchorTimestampExtractor: AnchorTimestampExtractor, | ||
private readonly stateManipulator: StateManipulator | ||
) {} | ||
|
||
/** | ||
* Applies a tip that was learned about via the p2p network (ie from pubsub, ReCon, HDS, etc) to | ||
* the given StreamState. Because it came from the network, we cannot trust that the tip is | ||
* actually a valid tip for the stream. If it is not, we just return the same StreamState | ||
* unmodified. | ||
* @param state | ||
* @param tip | ||
*/ | ||
async applyTipFromNetwork(state: StreamState, tip: CID): Promise<StreamState> { | ||
return applyTipToState( | ||
this.logSyncer, | ||
this.anchorTimestampExtractor, | ||
this.stateManipulator, | ||
state, | ||
tip, | ||
{ | ||
throwOnInvalidCommit: false, | ||
throwIfStale: false, | ||
throwOnConflict: false, | ||
} | ||
) | ||
} | ||
|
||
/** | ||
* Apply a commit that came in from an active application request via the HTTP client. Because | ||
* this write comes in from an active application session, we apply stricter rules to it and | ||
* throw errors in cases that might indicate an application bug - for instance if the write | ||
* is built on stale state in the client relative to what the server knows is the most current | ||
* state for the Stream. | ||
* @param state | ||
* @param commit | ||
*/ | ||
async applyCommitFromUser(state: StreamState, commit: CeramicCommit): Promise<StreamState> { | ||
const tip = await this.commitStorer.storeCommit(commit, StreamUtils.streamIdFromState(state)) | ||
|
||
return applyTipToState( | ||
this.logSyncer, | ||
this.anchorTimestampExtractor, | ||
this.stateManipulator, | ||
state, | ||
tip, | ||
{ | ||
throwOnInvalidCommit: true, | ||
throwIfStale: true, | ||
throwOnConflict: true, | ||
} | ||
) | ||
} | ||
} |