1
1
/* eslint-disable @typescript-eslint/no-explicit-any */
2
2
/* eslint-disable prefer-spread */
3
- import { Cardano } from '@cardano-sdk/core' ;
3
+ import { Bootstrap , ProjectionEvent , logProjectionProgress , requestNext } from '@cardano-sdk/projection' ;
4
+ import { Cardano , ObservableCardanoNode } from '@cardano-sdk/core' ;
4
5
import { Logger } from 'ts-log' ;
5
- import { Observable , takeWhile } from 'rxjs' ;
6
+ import { Observable , concat , defer , take , takeWhile } from 'rxjs' ;
6
7
import {
7
8
PgConnectionConfig ,
8
9
TypeormDevOptions ,
10
+ TypeormOptions ,
9
11
TypeormStabilityWindowBuffer ,
10
12
WithTypeormContext ,
11
13
createObservableConnection ,
14
+ createTypeormTipTracker ,
12
15
isRecoverableTypeormError ,
13
16
typeormTransactionCommit ,
14
17
withTypeormTransaction
@@ -19,19 +22,22 @@ import {
19
22
ProjectionOptions ,
20
23
prepareTypeormProjection
21
24
} from './prepareTypeormProjection' ;
22
- import { ProjectionEvent , logProjectionProgress , requestNext } from '@cardano-sdk/projection ' ;
25
+ import { ReconnectionConfig , passthrough , shareRetryBackoff , toEmpty } from '@cardano-sdk/util-rxjs ' ;
23
26
import { migrations } from './migrations' ;
24
- import { passthrough , shareRetryBackoff } from '@cardano-sdk/util-rxjs' ;
27
+
28
+ const reconnectionConfig : ReconnectionConfig = {
29
+ initialInterval : 50 ,
30
+ maxInterval : 5000
31
+ } ;
25
32
26
33
export interface CreateTypeormProjectionProps {
27
34
projections : ProjectionName [ ] ;
28
35
blocksBufferLength : number ;
29
- buffer ?: TypeormStabilityWindowBuffer ;
30
- projectionSource$ : Observable < ProjectionEvent > ;
31
36
connectionConfig$ : Observable < PgConnectionConfig > ;
32
37
devOptions ?: TypeormDevOptions ;
33
38
exitAtBlockNo ?: Cardano . BlockNo ;
34
39
logger : Logger ;
40
+ cardanoNode : ObservableCardanoNode ;
35
41
projectionOptions ?: ProjectionOptions ;
36
42
}
37
43
@@ -54,12 +60,11 @@ const applyStores =
54
60
export const createTypeormProjection = ( {
55
61
blocksBufferLength,
56
62
projections,
57
- projectionSource$,
58
63
connectionConfig$,
59
64
logger,
60
- devOptions,
65
+ devOptions : requestedDevOptions ,
66
+ cardanoNode,
61
67
exitAtBlockNo,
62
- buffer,
63
68
projectionOptions
64
69
} : CreateTypeormProjectionProps ) => {
65
70
const { handlePolicyIds } = { handlePolicyIds : [ ] , ...projectionOptions } ;
@@ -69,32 +74,65 @@ export const createTypeormProjection = ({
69
74
70
75
const { mappers, entities, stores, extensions } = prepareTypeormProjection (
71
76
{
72
- buffer,
73
77
options : projectionOptions ,
74
78
projections
75
79
} ,
76
80
{ logger }
77
81
) ;
78
- const connection$ = createObservableConnection ( {
79
- connectionConfig$,
80
- devOptions,
81
- entities,
82
- extensions,
82
+ const connect = ( options ?: TypeormOptions , devOptions ?: TypeormDevOptions ) =>
83
+ createObservableConnection ( {
84
+ connectionConfig$,
85
+ devOptions,
86
+ entities,
87
+ extensions,
88
+ logger,
89
+ options
90
+ } ) ;
91
+
92
+ const tipTracker = createTypeormTipTracker ( {
93
+ connection$ : connect ( ) ,
94
+ reconnectionConfig
95
+ } ) ;
96
+ const buffer = new TypeormStabilityWindowBuffer ( {
97
+ connection$ : connect ( ) ,
98
+ logger,
99
+ reconnectionConfig
100
+ } ) ;
101
+ const projectionSource$ = Bootstrap . fromCardanoNode ( {
102
+ blocksBufferLength,
103
+ buffer,
104
+ cardanoNode,
83
105
logger,
84
- options : {
85
- installExtensions : true ,
86
- migrations : migrations . filter ( ( { entity } ) => entities . includes ( entity as any ) ) ,
87
- migrationsRun : ! devOptions ?. synchronize
88
- }
106
+ projectedTip$ : tipTracker . tip$
89
107
} ) ;
90
- return projectionSource$ . pipe (
91
- applyMappers ( mappers ) ,
92
- shareRetryBackoff (
93
- ( evt$ ) => evt$ . pipe ( withTypeormTransaction ( { connection$ } ) , applyStores ( stores ) , typeormTransactionCommit ( ) ) ,
94
- { shouldRetry : isRecoverableTypeormError }
95
- ) ,
96
- requestNext ( ) ,
97
- logProjectionProgress ( logger ) ,
98
- exitAtBlockNo ? takeWhile ( ( event ) => event . block . header . blockNo < exitAtBlockNo ) : passthrough ( )
108
+ return concat (
109
+ // initialize database before starting the projector
110
+ connect (
111
+ {
112
+ installExtensions : true ,
113
+ migrations : migrations . filter ( ( { entity } ) => entities . includes ( entity as any ) ) ,
114
+ migrationsRun : ! requestedDevOptions ?. synchronize
115
+ } ,
116
+ requestedDevOptions
117
+ ) . pipe ( take ( 1 ) , toEmpty ) ,
118
+ defer ( ( ) =>
119
+ projectionSource$ . pipe (
120
+ applyMappers ( mappers ) ,
121
+ shareRetryBackoff (
122
+ ( evt$ ) =>
123
+ evt$ . pipe (
124
+ withTypeormTransaction ( { connection$ : connect ( ) } ) ,
125
+ applyStores ( stores ) ,
126
+ buffer . storeBlockData ( ) ,
127
+ typeormTransactionCommit ( )
128
+ ) ,
129
+ { shouldRetry : isRecoverableTypeormError }
130
+ ) ,
131
+ tipTracker . trackProjectedTip ( ) ,
132
+ requestNext ( ) ,
133
+ logProjectionProgress ( logger ) ,
134
+ exitAtBlockNo ? takeWhile ( ( event ) => event . block . header . blockNo < exitAtBlockNo ) : passthrough ( )
135
+ )
136
+ )
99
137
) ;
100
138
} ;
0 commit comments