Container.ts 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. import * as winston from 'winston'
  2. import { Container, interfaces } from 'inversify'
  3. import { Env } from './Env'
  4. import TYPES from './Types'
  5. import { AppDataSource } from './DataSource'
  6. import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns'
  7. import { ItemRepositoryInterface } from '../Domain/Item/ItemRepositoryInterface'
  8. import { TypeORMItemRepository } from '../Infra/TypeORM/TypeORMItemRepository'
  9. import { Repository } from 'typeorm'
  10. import { Item } from '../Domain/Item/Item'
  11. import {
  12. DirectCallDomainEventPublisher,
  13. DirectCallEventMessageHandler,
  14. SNSDomainEventPublisher,
  15. SQSDomainEventSubscriberFactory,
  16. SQSEventMessageHandler,
  17. SQSNewRelicEventMessageHandler,
  18. } from '@standardnotes/domain-events-infra'
  19. import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryInterface'
  20. import { DomainEventFactory } from '../Domain/Event/DomainEventFactory'
  21. import { Timer, TimerInterface } from '@standardnotes/time'
  22. import { ItemTransferCalculatorInterface } from '../Domain/Item/ItemTransferCalculatorInterface'
  23. import { ItemTransferCalculator } from '../Domain/Item/ItemTransferCalculator'
  24. import { ItemConflict } from '../Domain/Item/ItemConflict'
  25. import { ContentFilter } from '../Domain/Item/SaveRule/ContentFilter'
  26. import { ContentTypeFilter } from '../Domain/Item/SaveRule/ContentTypeFilter'
  27. import { OwnershipFilter } from '../Domain/Item/SaveRule/OwnershipFilter'
  28. import { TimeDifferenceFilter } from '../Domain/Item/SaveRule/TimeDifferenceFilter'
  29. import { ItemSaveValidator } from '../Domain/Item/SaveValidator/ItemSaveValidator'
  30. import { ItemSaveValidatorInterface } from '../Domain/Item/SaveValidator/ItemSaveValidatorInterface'
  31. import { SyncResponseFactory20161215 } from '../Domain/Item/SyncResponse/SyncResponseFactory20161215'
  32. import { SyncResponseFactory20200115 } from '../Domain/Item/SyncResponse/SyncResponseFactory20200115'
  33. import { SyncResponseFactoryResolver } from '../Domain/Item/SyncResponse/SyncResponseFactoryResolver'
  34. import { SyncResponseFactoryResolverInterface } from '../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface'
  35. import { CheckIntegrity } from '../Domain/UseCase/Syncing/CheckIntegrity/CheckIntegrity'
  36. import { GetItem } from '../Domain/UseCase/Syncing/GetItem/GetItem'
  37. import { SyncItems } from '../Domain/UseCase/Syncing/SyncItems/SyncItems'
  38. import { InversifyExpressAuthMiddleware } from '../Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware'
  39. import { S3Client } from '@aws-sdk/client-s3'
  40. import { SQSClient, SQSClientConfig } from '@aws-sdk/client-sqs'
  41. import { ContentDecoder } from '@standardnotes/common'
  42. import {
  43. DomainEventMessageHandlerInterface,
  44. DomainEventHandlerInterface,
  45. DomainEventSubscriberFactoryInterface,
  46. DomainEventPublisherInterface,
  47. } from '@standardnotes/domain-events'
  48. import axios, { AxiosInstance } from 'axios'
  49. import { AuthHttpServiceInterface } from '../Domain/Auth/AuthHttpServiceInterface'
  50. import { ExtensionsHttpService } from '../Domain/Extension/ExtensionsHttpService'
  51. import { ExtensionsHttpServiceInterface } from '../Domain/Extension/ExtensionsHttpServiceInterface'
  52. import { AccountDeletionRequestedEventHandler } from '../Domain/Handler/AccountDeletionRequestedEventHandler'
  53. import { DuplicateItemSyncedEventHandler } from '../Domain/Handler/DuplicateItemSyncedEventHandler'
  54. import { EmailBackupRequestedEventHandler } from '../Domain/Handler/EmailBackupRequestedEventHandler'
  55. import { ItemRevisionCreationRequestedEventHandler } from '../Domain/Handler/ItemRevisionCreationRequestedEventHandler'
  56. import { ItemBackupServiceInterface } from '../Domain/Item/ItemBackupServiceInterface'
  57. import { FSItemBackupService } from '../Infra/FS/FSItemBackupService'
  58. import { AuthHttpService } from '../Infra/HTTP/AuthHttpService'
  59. import { S3ItemBackupService } from '../Infra/S3/S3ItemBackupService'
  60. import { ControllerContainer, ControllerContainerInterface, MapperInterface } from '@standardnotes/domain-core'
  61. import { HomeServerItemsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerItemsController'
  62. import { Transform } from 'stream'
  63. import { TypeORMItem } from '../Infra/TypeORM/TypeORMItem'
  64. import { ItemPersistenceMapper } from '../Mapping/Persistence/ItemPersistenceMapper'
  65. import { ItemHttpRepresentation } from '../Mapping/Http/ItemHttpRepresentation'
  66. import { ItemHttpMapper } from '../Mapping/Http/ItemHttpMapper'
  67. import { SavedItemHttpRepresentation } from '../Mapping/Http/SavedItemHttpRepresentation'
  68. import { SavedItemHttpMapper } from '../Mapping/Http/SavedItemHttpMapper'
  69. import { ItemConflictHttpRepresentation } from '../Mapping/Http/ItemConflictHttpRepresentation'
  70. import { ItemConflictHttpMapper } from '../Mapping/Http/ItemConflictHttpMapper'
  71. import { ItemBackupRepresentation } from '../Mapping/Backup/ItemBackupRepresentation'
  72. import { ItemBackupMapper } from '../Mapping/Backup/ItemBackupMapper'
  73. import { SaveNewItem } from '../Domain/UseCase/Syncing/SaveNewItem/SaveNewItem'
  74. import { UpdateExistingItem } from '../Domain/UseCase/Syncing/UpdateExistingItem/UpdateExistingItem'
  75. import { GetItems } from '../Domain/UseCase/Syncing/GetItems/GetItems'
  76. import { SaveItems } from '../Domain/UseCase/Syncing/SaveItems/SaveItems'
  77. import { ItemHashHttpMapper } from '../Mapping/Http/ItemHashHttpMapper'
  78. import { ItemHash } from '../Domain/Item/ItemHash'
  79. import { ItemHashHttpRepresentation } from '../Mapping/Http/ItemHashHttpRepresentation'
  80. import { TypeORMKeySystemAssociation } from '../Infra/TypeORM/TypeORMKeySystemAssociation'
  81. import { SharedVaultAssociation } from '../Domain/SharedVault/SharedVaultAssociation'
  82. import { TypeORMSharedVaultAssociation } from '../Infra/TypeORM/TypeORMSharedVaultAssociation'
  83. import { SharedVaultAssociationPersistenceMapper } from '../Mapping/Persistence/SharedVaultAssociationPersistenceMapper'
  84. import { TypeORMKeySystemAssociationRepository } from '../Infra/TypeORM/TypeORMKeySystemAssociationRepository'
  85. import { SharedVaultAssociationRepositoryInterface } from '../Domain/SharedVault/SharedVaultAssociationRepositoryInterface'
  86. import { TypeORMSharedVaultAssociationRepository } from '../Infra/TypeORM/TypeORMSharedVaultAssociationRepository'
  87. import { KeySystemAssociation } from '../Domain/KeySystem/KeySystemAssociation'
  88. import { KeySystemAssociationRepositoryInterface } from '../Domain/KeySystem/KeySystemAssociationRepositoryInterface'
  89. import { KeySystemAssociationPersistenceMapper } from '../Mapping/Persistence/KeySystemAssociationPersistenceMapper'
  90. export class ContainerConfigLoader {
  91. private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000
  92. private readonly DEFAULT_MAX_ITEMS_LIMIT = 300
  93. private readonly DEFAULT_FILE_UPLOAD_PATH = `${__dirname}/../../uploads`
  94. async load(configuration?: {
  95. controllerConatiner?: ControllerContainerInterface
  96. directCallDomainEventPublisher?: DirectCallDomainEventPublisher
  97. logger?: Transform
  98. environmentOverrides?: { [name: string]: string }
  99. }): Promise<Container> {
  100. const directCallDomainEventPublisher =
  101. configuration?.directCallDomainEventPublisher ?? new DirectCallDomainEventPublisher()
  102. const env: Env = new Env(configuration?.environmentOverrides)
  103. env.load()
  104. const container = new Container({
  105. defaultScope: 'Singleton',
  106. })
  107. let logger: winston.Logger
  108. if (configuration?.logger) {
  109. logger = configuration.logger as winston.Logger
  110. } else {
  111. const winstonFormatters = [winston.format.splat(), winston.format.json()]
  112. if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
  113. await import('newrelic')
  114. // eslint-disable-next-line @typescript-eslint/no-var-requires
  115. const newrelicFormatter = require('@newrelic/winston-enricher')
  116. const newrelicWinstonFormatter = newrelicFormatter(winston)
  117. winstonFormatters.push(newrelicWinstonFormatter())
  118. }
  119. logger = winston.createLogger({
  120. level: env.get('LOG_LEVEL', true) || 'info',
  121. format: winston.format.combine(...winstonFormatters),
  122. transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
  123. defaultMeta: { service: 'syncing-server' },
  124. })
  125. }
  126. container.bind<winston.Logger>(TYPES.Sync_Logger).toConstantValue(logger)
  127. const appDataSource = new AppDataSource(env)
  128. await appDataSource.initialize()
  129. logger.debug('Database initialized')
  130. container.bind<TimerInterface>(TYPES.Sync_Timer).toConstantValue(new Timer())
  131. const isConfiguredForHomeServer = env.get('MODE', true) === 'home-server'
  132. container.bind<Env>(TYPES.Sync_Env).toConstantValue(env)
  133. if (isConfiguredForHomeServer) {
  134. container
  135. .bind<DomainEventPublisherInterface>(TYPES.Sync_DomainEventPublisher)
  136. .toConstantValue(directCallDomainEventPublisher)
  137. } else {
  138. container.bind(TYPES.Sync_SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN'))
  139. container.bind(TYPES.Sync_SNS_AWS_REGION).toConstantValue(env.get('SNS_AWS_REGION', true))
  140. container.bind(TYPES.Sync_SQS_QUEUE_URL).toConstantValue(env.get('SQS_QUEUE_URL'))
  141. container.bind(TYPES.Sync_S3_AWS_REGION).toConstantValue(env.get('S3_AWS_REGION', true))
  142. container.bind(TYPES.Sync_S3_BACKUP_BUCKET_NAME).toConstantValue(env.get('S3_BACKUP_BUCKET_NAME', true))
  143. container.bind(TYPES.Sync_EXTENSIONS_SERVER_URL).toConstantValue(env.get('EXTENSIONS_SERVER_URL', true))
  144. container.bind<SNSClient>(TYPES.Sync_SNS).toDynamicValue((context: interfaces.Context) => {
  145. const env: Env = context.container.get(TYPES.Sync_Env)
  146. const snsConfig: SNSClientConfig = {
  147. apiVersion: 'latest',
  148. region: env.get('SNS_AWS_REGION', true),
  149. }
  150. if (env.get('SNS_ENDPOINT', true)) {
  151. snsConfig.endpoint = env.get('SNS_ENDPOINT', true)
  152. }
  153. if (env.get('SNS_ACCESS_KEY_ID', true) && env.get('SNS_SECRET_ACCESS_KEY', true)) {
  154. snsConfig.credentials = {
  155. accessKeyId: env.get('SNS_ACCESS_KEY_ID', true),
  156. secretAccessKey: env.get('SNS_SECRET_ACCESS_KEY', true),
  157. }
  158. }
  159. return new SNSClient(snsConfig)
  160. })
  161. container
  162. .bind<DomainEventPublisherInterface>(TYPES.Sync_DomainEventPublisher)
  163. .toDynamicValue((context: interfaces.Context) => {
  164. return new SNSDomainEventPublisher(
  165. context.container.get(TYPES.Sync_SNS),
  166. context.container.get(TYPES.Sync_SNS_TOPIC_ARN),
  167. )
  168. })
  169. container.bind<SQSClient>(TYPES.Sync_SQS).toDynamicValue((context: interfaces.Context) => {
  170. const env: Env = context.container.get(TYPES.Sync_Env)
  171. const sqsConfig: SQSClientConfig = {
  172. region: env.get('SQS_AWS_REGION'),
  173. }
  174. if (env.get('SQS_ENDPOINT', true)) {
  175. sqsConfig.endpoint = env.get('SQS_ENDPOINT', true)
  176. }
  177. if (env.get('SQS_ACCESS_KEY_ID', true) && env.get('SQS_SECRET_ACCESS_KEY', true)) {
  178. sqsConfig.credentials = {
  179. accessKeyId: env.get('SQS_ACCESS_KEY_ID', true),
  180. secretAccessKey: env.get('SQS_SECRET_ACCESS_KEY', true),
  181. }
  182. }
  183. return new SQSClient(sqsConfig)
  184. })
  185. container.bind<S3Client | undefined>(TYPES.Sync_S3).toDynamicValue((context: interfaces.Context) => {
  186. const env: Env = context.container.get(TYPES.Sync_Env)
  187. let s3Client = undefined
  188. if (env.get('S3_AWS_REGION', true)) {
  189. s3Client = new S3Client({
  190. apiVersion: 'latest',
  191. region: env.get('S3_AWS_REGION', true),
  192. })
  193. }
  194. return s3Client
  195. })
  196. }
  197. // Mapping
  198. container
  199. .bind<MapperInterface<Item, TypeORMItem>>(TYPES.Sync_ItemPersistenceMapper)
  200. .toConstantValue(new ItemPersistenceMapper())
  201. container
  202. .bind<MapperInterface<ItemHash, ItemHashHttpRepresentation>>(TYPES.Sync_ItemHashHttpMapper)
  203. .toConstantValue(new ItemHashHttpMapper())
  204. container
  205. .bind<MapperInterface<Item, ItemHttpRepresentation>>(TYPES.Sync_ItemHttpMapper)
  206. .toConstantValue(new ItemHttpMapper(container.get(TYPES.Sync_Timer)))
  207. container
  208. .bind<MapperInterface<Item, SavedItemHttpRepresentation>>(TYPES.Sync_SavedItemHttpMapper)
  209. .toConstantValue(new SavedItemHttpMapper(container.get(TYPES.Sync_Timer)))
  210. container
  211. .bind<MapperInterface<ItemConflict, ItemConflictHttpRepresentation>>(TYPES.Sync_ItemConflictHttpMapper)
  212. .toConstantValue(
  213. new ItemConflictHttpMapper(
  214. container.get(TYPES.Sync_ItemHttpMapper),
  215. container.get(TYPES.Sync_ItemHashHttpMapper),
  216. ),
  217. )
  218. container
  219. .bind<MapperInterface<Item, ItemBackupRepresentation>>(TYPES.Sync_ItemBackupMapper)
  220. .toConstantValue(new ItemBackupMapper(container.get(TYPES.Sync_Timer)))
  221. container
  222. .bind<MapperInterface<KeySystemAssociation, TypeORMKeySystemAssociation>>(
  223. TYPES.Sync_KeySystemAssociationPersistenceMapper,
  224. )
  225. .toConstantValue(new KeySystemAssociationPersistenceMapper())
  226. container
  227. .bind<MapperInterface<SharedVaultAssociation, TypeORMSharedVaultAssociation>>(
  228. TYPES.Sync_SharedVaultAssociationPersistenceMapper,
  229. )
  230. .toConstantValue(new SharedVaultAssociationPersistenceMapper())
  231. // ORM
  232. container
  233. .bind<Repository<TypeORMItem>>(TYPES.Sync_ORMItemRepository)
  234. .toDynamicValue(() => appDataSource.getRepository(TypeORMItem))
  235. container
  236. .bind<Repository<TypeORMSharedVaultAssociation>>(TYPES.Sync_ORMSharedVaultAssociationRepository)
  237. .toConstantValue(appDataSource.getRepository(TypeORMSharedVaultAssociation))
  238. container
  239. .bind<Repository<TypeORMKeySystemAssociation>>(TYPES.Sync_ORMKeySystemAssociationRepository)
  240. .toConstantValue(appDataSource.getRepository(TypeORMKeySystemAssociation))
  241. // Repositories
  242. container
  243. .bind<KeySystemAssociationRepositoryInterface>(TYPES.Sync_KeySystemAssociationRepository)
  244. .toConstantValue(
  245. new TypeORMKeySystemAssociationRepository(
  246. container.get(TYPES.Sync_ORMKeySystemAssociationRepository),
  247. container.get(TYPES.Sync_KeySystemAssociationPersistenceMapper),
  248. ),
  249. )
  250. container
  251. .bind<SharedVaultAssociationRepositoryInterface>(TYPES.Sync_SharedVaultAssociationRepository)
  252. .toConstantValue(
  253. new TypeORMSharedVaultAssociationRepository(
  254. container.get(TYPES.Sync_ORMSharedVaultAssociationRepository),
  255. container.get(TYPES.Sync_SharedVaultAssociationPersistenceMapper),
  256. ),
  257. )
  258. container
  259. .bind<ItemRepositoryInterface>(TYPES.Sync_ItemRepository)
  260. .toConstantValue(
  261. new TypeORMItemRepository(
  262. container.get(TYPES.Sync_ORMItemRepository),
  263. container.get(TYPES.Sync_ItemPersistenceMapper),
  264. container.get(TYPES.Sync_KeySystemAssociationRepository),
  265. container.get(TYPES.Sync_SharedVaultAssociationRepository),
  266. ),
  267. )
  268. container
  269. .bind<DomainEventFactoryInterface>(TYPES.Sync_DomainEventFactory)
  270. .toDynamicValue((context: interfaces.Context) => {
  271. return new DomainEventFactory(context.container.get(TYPES.Sync_Timer))
  272. })
  273. container
  274. .bind<ItemTransferCalculatorInterface>(TYPES.Sync_ItemTransferCalculator)
  275. .toDynamicValue((context: interfaces.Context) => {
  276. return new ItemTransferCalculator(
  277. context.container.get(TYPES.Sync_ItemRepository),
  278. context.container.get(TYPES.Sync_Logger),
  279. )
  280. })
  281. // Middleware
  282. container
  283. .bind<InversifyExpressAuthMiddleware>(TYPES.Sync_AuthMiddleware)
  284. .toDynamicValue((context: interfaces.Context) => {
  285. return new InversifyExpressAuthMiddleware(
  286. context.container.get(TYPES.Sync_AUTH_JWT_SECRET),
  287. context.container.get(TYPES.Sync_Logger),
  288. )
  289. })
  290. // env vars
  291. container.bind(TYPES.Sync_AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
  292. container
  293. .bind(TYPES.Sync_REVISIONS_FREQUENCY)
  294. .toConstantValue(env.get('REVISIONS_FREQUENCY', true) ? +env.get('REVISIONS_FREQUENCY', true) : 300)
  295. container.bind(TYPES.Sync_NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true))
  296. container.bind(TYPES.Sync_VERSION).toConstantValue(env.get('VERSION', true) ?? 'development')
  297. container
  298. .bind(TYPES.Sync_CONTENT_SIZE_TRANSFER_LIMIT)
  299. .toConstantValue(
  300. env.get('CONTENT_SIZE_TRANSFER_LIMIT', true)
  301. ? +env.get('CONTENT_SIZE_TRANSFER_LIMIT', true)
  302. : this.DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT,
  303. )
  304. container
  305. .bind(TYPES.Sync_MAX_ITEMS_LIMIT)
  306. .toConstantValue(
  307. env.get('MAX_ITEMS_LIMIT', true) ? +env.get('MAX_ITEMS_LIMIT', true) : this.DEFAULT_MAX_ITEMS_LIMIT,
  308. )
  309. container.bind<OwnershipFilter>(TYPES.Sync_OwnershipFilter).toConstantValue(new OwnershipFilter())
  310. container
  311. .bind<TimeDifferenceFilter>(TYPES.Sync_TimeDifferenceFilter)
  312. .toConstantValue(new TimeDifferenceFilter(container.get(TYPES.Sync_Timer)))
  313. container.bind<ContentTypeFilter>(TYPES.Sync_ContentTypeFilter).toConstantValue(new ContentTypeFilter())
  314. container.bind<ContentFilter>(TYPES.Sync_ContentFilter).toConstantValue(new ContentFilter())
  315. container
  316. .bind<ItemSaveValidatorInterface>(TYPES.Sync_ItemSaveValidator)
  317. .toConstantValue(
  318. new ItemSaveValidator([
  319. container.get(TYPES.Sync_OwnershipFilter),
  320. container.get(TYPES.Sync_TimeDifferenceFilter),
  321. container.get(TYPES.Sync_ContentTypeFilter),
  322. container.get(TYPES.Sync_ContentFilter),
  323. ]),
  324. )
  325. // use cases
  326. container
  327. .bind<GetItems>(TYPES.Sync_GetItems)
  328. .toConstantValue(
  329. new GetItems(
  330. container.get(TYPES.Sync_ItemRepository),
  331. container.get(TYPES.Sync_CONTENT_SIZE_TRANSFER_LIMIT),
  332. container.get(TYPES.Sync_ItemTransferCalculator),
  333. container.get(TYPES.Sync_Timer),
  334. container.get(TYPES.Sync_MAX_ITEMS_LIMIT),
  335. ),
  336. )
  337. container
  338. .bind<SaveNewItem>(TYPES.Sync_SaveNewItem)
  339. .toConstantValue(
  340. new SaveNewItem(
  341. container.get(TYPES.Sync_ItemRepository),
  342. container.get(TYPES.Sync_Timer),
  343. container.get(TYPES.Sync_DomainEventPublisher),
  344. container.get(TYPES.Sync_DomainEventFactory),
  345. ),
  346. )
  347. container
  348. .bind<UpdateExistingItem>(TYPES.Sync_UpdateExistingItem)
  349. .toConstantValue(
  350. new UpdateExistingItem(
  351. container.get(TYPES.Sync_ItemRepository),
  352. container.get(TYPES.Sync_Timer),
  353. container.get(TYPES.Sync_DomainEventPublisher),
  354. container.get(TYPES.Sync_DomainEventFactory),
  355. container.get(TYPES.Sync_REVISIONS_FREQUENCY),
  356. ),
  357. )
  358. container
  359. .bind<SaveItems>(TYPES.Sync_SaveItems)
  360. .toConstantValue(
  361. new SaveItems(
  362. container.get(TYPES.Sync_ItemSaveValidator),
  363. container.get(TYPES.Sync_ItemRepository),
  364. container.get(TYPES.Sync_Timer),
  365. container.get(TYPES.Sync_SaveNewItem),
  366. container.get(TYPES.Sync_UpdateExistingItem),
  367. container.get(TYPES.Sync_Logger),
  368. ),
  369. )
  370. container
  371. .bind<SyncItems>(TYPES.Sync_SyncItems)
  372. .toConstantValue(
  373. new SyncItems(
  374. container.get(TYPES.Sync_ItemRepository),
  375. container.get(TYPES.Sync_GetItems),
  376. container.get(TYPES.Sync_SaveItems),
  377. ),
  378. )
  379. container.bind<CheckIntegrity>(TYPES.Sync_CheckIntegrity).toDynamicValue((context: interfaces.Context) => {
  380. return new CheckIntegrity(context.container.get(TYPES.Sync_ItemRepository))
  381. })
  382. container.bind<GetItem>(TYPES.Sync_GetItem).toDynamicValue((context: interfaces.Context) => {
  383. return new GetItem(context.container.get(TYPES.Sync_ItemRepository))
  384. })
  385. // Services
  386. container
  387. .bind<SyncResponseFactory20161215>(TYPES.Sync_SyncResponseFactory20161215)
  388. .toConstantValue(new SyncResponseFactory20161215(container.get(TYPES.Sync_ItemHttpMapper)))
  389. container
  390. .bind<SyncResponseFactory20200115>(TYPES.Sync_SyncResponseFactory20200115)
  391. .toConstantValue(
  392. new SyncResponseFactory20200115(
  393. container.get(TYPES.Sync_ItemHttpMapper),
  394. container.get(TYPES.Sync_ItemConflictHttpMapper),
  395. container.get(TYPES.Sync_SavedItemHttpMapper),
  396. ),
  397. )
  398. container
  399. .bind<SyncResponseFactoryResolverInterface>(TYPES.Sync_SyncResponseFactoryResolver)
  400. .toDynamicValue((context: interfaces.Context) => {
  401. return new SyncResponseFactoryResolver(
  402. context.container.get(TYPES.Sync_SyncResponseFactory20161215),
  403. context.container.get(TYPES.Sync_SyncResponseFactory20200115),
  404. )
  405. })
  406. // env vars
  407. container
  408. .bind(TYPES.Sync_EMAIL_ATTACHMENT_MAX_BYTE_SIZE)
  409. .toConstantValue(
  410. env.get('EMAIL_ATTACHMENT_MAX_BYTE_SIZE', true) ? +env.get('EMAIL_ATTACHMENT_MAX_BYTE_SIZE', true) : 10485760,
  411. )
  412. container.bind(TYPES.Sync_NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true))
  413. container
  414. .bind(TYPES.Sync_FILE_UPLOAD_PATH)
  415. .toConstantValue(
  416. env.get('FILE_UPLOAD_PATH', true) ? env.get('FILE_UPLOAD_PATH', true) : this.DEFAULT_FILE_UPLOAD_PATH,
  417. )
  418. // Handlers
  419. container
  420. .bind<DuplicateItemSyncedEventHandler>(TYPES.Sync_DuplicateItemSyncedEventHandler)
  421. .toDynamicValue((context: interfaces.Context) => {
  422. return new DuplicateItemSyncedEventHandler(
  423. context.container.get(TYPES.Sync_ItemRepository),
  424. context.container.get(TYPES.Sync_DomainEventFactory),
  425. context.container.get(TYPES.Sync_DomainEventPublisher),
  426. context.container.get(TYPES.Sync_Logger),
  427. )
  428. })
  429. container
  430. .bind<AccountDeletionRequestedEventHandler>(TYPES.Sync_AccountDeletionRequestedEventHandler)
  431. .toDynamicValue((context: interfaces.Context) => {
  432. return new AccountDeletionRequestedEventHandler(
  433. context.container.get(TYPES.Sync_ItemRepository),
  434. context.container.get(TYPES.Sync_Logger),
  435. )
  436. })
  437. container
  438. .bind<ItemRevisionCreationRequestedEventHandler>(TYPES.Sync_ItemRevisionCreationRequestedEventHandler)
  439. .toDynamicValue((context: interfaces.Context) => {
  440. return new ItemRevisionCreationRequestedEventHandler(
  441. context.container.get(TYPES.Sync_ItemRepository),
  442. context.container.get(TYPES.Sync_ItemBackupService),
  443. context.container.get(TYPES.Sync_DomainEventFactory),
  444. context.container.get(TYPES.Sync_DomainEventPublisher),
  445. )
  446. })
  447. // Services
  448. container.bind<ContentDecoder>(TYPES.Sync_ContentDecoder).toDynamicValue(() => new ContentDecoder())
  449. container.bind<AxiosInstance>(TYPES.Sync_HTTPClient).toDynamicValue(() => axios.create())
  450. container
  451. .bind<ExtensionsHttpServiceInterface>(TYPES.Sync_ExtensionsHttpService)
  452. .toDynamicValue((context: interfaces.Context) => {
  453. return new ExtensionsHttpService(
  454. context.container.get(TYPES.Sync_HTTPClient),
  455. context.container.get(TYPES.Sync_ItemRepository),
  456. context.container.get(TYPES.Sync_ContentDecoder),
  457. context.container.get(TYPES.Sync_DomainEventPublisher),
  458. context.container.get(TYPES.Sync_DomainEventFactory),
  459. context.container.get(TYPES.Sync_Logger),
  460. )
  461. })
  462. container
  463. .bind<ItemBackupServiceInterface>(TYPES.Sync_ItemBackupService)
  464. .toDynamicValue((context: interfaces.Context) => {
  465. const env: Env = context.container.get(TYPES.Sync_Env)
  466. if (env.get('S3_AWS_REGION', true)) {
  467. return new S3ItemBackupService(
  468. context.container.get(TYPES.Sync_S3_BACKUP_BUCKET_NAME),
  469. context.container.get(TYPES.Sync_ItemBackupMapper),
  470. context.container.get(TYPES.Sync_ItemHttpMapper),
  471. context.container.get(TYPES.Sync_Logger),
  472. context.container.get(TYPES.Sync_S3),
  473. )
  474. } else {
  475. return new FSItemBackupService(
  476. context.container.get(TYPES.Sync_FILE_UPLOAD_PATH),
  477. context.container.get(TYPES.Sync_ItemBackupMapper),
  478. context.container.get(TYPES.Sync_Logger),
  479. )
  480. }
  481. })
  482. const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
  483. ['DUPLICATE_ITEM_SYNCED', container.get(TYPES.Sync_DuplicateItemSyncedEventHandler)],
  484. ['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Sync_AccountDeletionRequestedEventHandler)],
  485. ['ITEM_REVISION_CREATION_REQUESTED', container.get(TYPES.Sync_ItemRevisionCreationRequestedEventHandler)],
  486. ])
  487. if (!isConfiguredForHomeServer) {
  488. container.bind(TYPES.Sync_AUTH_SERVER_URL).toConstantValue(env.get('AUTH_SERVER_URL'))
  489. container
  490. .bind<AuthHttpServiceInterface>(TYPES.Sync_AuthHttpService)
  491. .toDynamicValue((context: interfaces.Context) => {
  492. return new AuthHttpService(
  493. context.container.get(TYPES.Sync_HTTPClient),
  494. context.container.get(TYPES.Sync_AUTH_SERVER_URL),
  495. )
  496. })
  497. container
  498. .bind<EmailBackupRequestedEventHandler>(TYPES.Sync_EmailBackupRequestedEventHandler)
  499. .toDynamicValue((context: interfaces.Context) => {
  500. return new EmailBackupRequestedEventHandler(
  501. context.container.get(TYPES.Sync_ItemRepository),
  502. context.container.get(TYPES.Sync_AuthHttpService),
  503. context.container.get(TYPES.Sync_ItemBackupService),
  504. context.container.get(TYPES.Sync_DomainEventPublisher),
  505. context.container.get(TYPES.Sync_DomainEventFactory),
  506. context.container.get(TYPES.Sync_EMAIL_ATTACHMENT_MAX_BYTE_SIZE),
  507. context.container.get(TYPES.Sync_ItemTransferCalculator),
  508. context.container.get(TYPES.Sync_S3_BACKUP_BUCKET_NAME),
  509. context.container.get(TYPES.Sync_Logger),
  510. )
  511. })
  512. eventHandlers.set('EMAIL_BACKUP_REQUESTED', container.get(TYPES.Sync_EmailBackupRequestedEventHandler))
  513. }
  514. if (isConfiguredForHomeServer) {
  515. const directCallEventMessageHandler = new DirectCallEventMessageHandler(
  516. eventHandlers,
  517. container.get(TYPES.Sync_Logger),
  518. )
  519. directCallDomainEventPublisher.register(directCallEventMessageHandler)
  520. container
  521. .bind<DomainEventMessageHandlerInterface>(TYPES.Sync_DomainEventMessageHandler)
  522. .toConstantValue(directCallEventMessageHandler)
  523. } else {
  524. container
  525. .bind<DomainEventMessageHandlerInterface>(TYPES.Sync_DomainEventMessageHandler)
  526. .toConstantValue(
  527. env.get('NEW_RELIC_ENABLED', true) === 'true'
  528. ? new SQSNewRelicEventMessageHandler(eventHandlers, container.get(TYPES.Sync_Logger))
  529. : new SQSEventMessageHandler(eventHandlers, container.get(TYPES.Sync_Logger)),
  530. )
  531. }
  532. container
  533. .bind<DomainEventSubscriberFactoryInterface>(TYPES.Sync_DomainEventSubscriberFactory)
  534. .toDynamicValue((context: interfaces.Context) => {
  535. return new SQSDomainEventSubscriberFactory(
  536. context.container.get(TYPES.Sync_SQS),
  537. context.container.get(TYPES.Sync_SQS_QUEUE_URL),
  538. context.container.get(TYPES.Sync_DomainEventMessageHandler),
  539. )
  540. })
  541. container
  542. .bind<ControllerContainerInterface>(TYPES.Sync_ControllerContainer)
  543. .toConstantValue(configuration?.controllerConatiner ?? new ControllerContainer())
  544. if (isConfiguredForHomeServer) {
  545. container
  546. .bind<HomeServerItemsController>(TYPES.Sync_HomeServerItemsController)
  547. .toConstantValue(
  548. new HomeServerItemsController(
  549. container.get(TYPES.Sync_SyncItems),
  550. container.get(TYPES.Sync_CheckIntegrity),
  551. container.get(TYPES.Sync_GetItem),
  552. container.get(TYPES.Sync_ItemHttpMapper),
  553. container.get(TYPES.Sync_SyncResponseFactoryResolver),
  554. container.get(TYPES.Sync_ControllerContainer),
  555. ),
  556. )
  557. }
  558. logger.debug('Configuration complete')
  559. return container
  560. }
  561. }