Files
speckle-server/packages/server/modules/core/index.ts
T
Daniel Gak Anagrov 399c998fd7 feat(multiregion): apply prepared transactions to projects (#5322)
* feat(multiregion): replace user replication

* chore(multiregion): optimise replication

* maybe it's this

* postgres is fun

* once more

* chore(multiregion): only replicate test user creation during multiregion tests

* feat: improved replicate_query logic

* fix: minor

* fix: starting issue

* feat: included user create and delete specs to multiregion

* feat: removed console logs

* fix: user defaults

* fix: multiregion test helper

* fix: update scenarios for users

* refactor(multiregion): swap replicateQuery concept to asMultiregionOperation (#5301)

feat(multiregion): introduced asMultregionOperator, refactor test to user builder classes

* chore: renamings

* fix: remove comments

* feat: remove user replication

* refactor: simplified spec usages

* chore: comments

* chore: branches and favs

* chore: more tests

* chore: more tests

* fix linting

* fix tests

* feat: dropping replication

* refactor: moved project delete to service

* fix: comment

* feat: updateStreamFactory and updateProjectFacotry

* deleteProjectFactory + replicateFactory

* deleteWorkspaceFactory

* fix: selector

* fix: tests

* fix tests, finished createStreamFactory

* feat: simplify changes

* fix: remove comment

* fix: minor strucutres

* fix: moveProjectToRegion

* fix: moved branch creation outside of multiregion scope

* fix: branch creation

* fix: tests

* fix: ci tests

* fix: removed log form test

* fix: on specs, no random regionKeys

* review fixes

* fix: mr comments

* feat: removed test

---------

Co-authored-by: Charles Driesler <chuck@speckle.systems>
2025-09-04 13:07:19 +02:00

156 lines
5.8 KiB
TypeScript

import { moduleLogger } from '@/observability/logging'
import {
setupResultListener,
shutdownResultListener
} from '@/modules/core/utils/dbNotificationListener'
import * as mp from '@/modules/shared/utils/mixpanel'
import type { SpeckleModule } from '@/modules/shared/helpers/typeHelper'
import staticRest from '@/modules/core/rest/static'
import uploadRest from '@/modules/core/rest/upload'
import downloadRest from '@/modules/core/rest/download'
import diffUpload from '@/modules/core/rest/diffUpload'
import diffDownload from '@/modules/core/rest/diffDownload'
import scopes from '@/modules/core/scopes'
import roles from '@/modules/core/roles'
import { getGenericRedis } from '@/modules/shared/redis/redis'
import { registerOrUpdateScopeFactory } from '@/modules/shared/repositories/scopes'
import db from '@/db/knex'
import { registerOrUpdateRole } from '@/modules/shared/repositories/roles'
import { isTestEnv } from '@/modules/shared/helpers/envHelper'
import type { HooksConfig, Hook, ExecuteHooks } from '@/modules/core/hooks'
import { reportSubscriptionEventsFactory } from '@/modules/core/events/subscriptionListeners'
import { getEventBus } from '@/modules/shared/services/eventBus'
import { publish } from '@/modules/shared/utils/subscriptions'
import {
getImplicitUserProjectsCountFactory,
getStreamCollaboratorsFactory
} from '@/modules/core/repositories/streams'
import { reportUserEventsFactory } from '@/modules/core/events/userTracking'
import { coreLogger } from '@/modules/core/logger'
import { updateUserMixpanelProfileFactory } from '@/modules/core/services/users/tracking'
import { getUserFactory } from '@/modules/core/repositories/users'
import {
getTotalWorkspaceCountFactory,
getUserWorkspaceCountFactory
} from '@/modules/workspacesCore/repositories/workspaces'
import { getUserAuthoredCommitCountsFactory } from '@/modules/core/repositories/commits'
import { getMixpanelClient } from '@/modules/shared/utils/mixpanel'
import { updateServerMixpanelProfileFactory } from '@/modules/core/services/server/tracking'
import { getCachedServerInfoFactory } from '@/modules/core/repositories/server'
import {
getTotalStreamCountFactory,
getTotalUserCountFactory
} from '@/modules/stats/repositories'
import { getServerTotalModelCountFactory } from '@/modules/core/services/branch/retrieval'
import { getServerTotalVersionCountFactory } from '@/modules/core/services/commit/retrieval'
import { bullMonitoringRouterFactory } from '@/modules/core/rest/monitoring'
import { projectListenersFactory } from '@/modules/core/events/projectListeners'
let stopTestSubs: (() => void) | undefined = undefined
const coreModule: SpeckleModule<{
hooks: HooksConfig
addHook: (key: keyof HooksConfig, hook: Hook) => void
executeHooks: ExecuteHooks
}> = {
hooks: {
onCreateObjectRequest: [],
onCreateVersionRequest: []
},
addHook(key: keyof HooksConfig, callback: Hook) {
this.hooks[key].push(callback)
},
async executeHooks(key: keyof HooksConfig, { projectId }: { projectId: string }) {
return await Promise.all(this.hooks[key].map(async (cb) => await cb({ projectId })))
},
async init({ app, isInitial }) {
moduleLogger.info('💥 Init core module')
// Initialize the static route
staticRest(app)
// Initialises the two main bulk upload/download endpoints
uploadRest(app, { executeHooks: this.executeHooks.bind(this) })
downloadRest(app)
// Initialises the two diff-based upload/download endpoints
diffUpload(app)
diffDownload(app)
const scopeRegisterFunc = registerOrUpdateScopeFactory({ db })
// Register core-based scoeps
for (const scope of scopes) {
await scopeRegisterFunc({ scope })
}
const roleRegisterFunc = registerOrUpdateRole({ db })
// Register core-based roles
for (const role of roles) {
await roleRegisterFunc({ role })
}
if (isInitial) {
// Setup global pg notification listener
await setupResultListener()
// Init mp
mp.initialize()
// Setup test subs
if (isTestEnv()) {
const { startEmittingTestSubs } = await import('@/test/graphqlHelper')
stopTestSubs = await startEmittingTestSubs()
}
// Setup up various eventBus listeners
reportSubscriptionEventsFactory({
eventListen: getEventBus().listen,
publish,
getStreamCollaborators: getStreamCollaboratorsFactory({ db })
})()
reportUserEventsFactory({
eventBus: getEventBus(),
logger: coreLogger,
updateUserMixpanelProfileFactory: updateUserMixpanelProfileFactory({
getUser: getUserFactory({ db }),
getImplicitUserProjectsCount: getImplicitUserProjectsCountFactory({ db }),
getUserWorkspaceCount: getUserWorkspaceCountFactory({ db }),
getUserAuthoredCommitCounts: getUserAuthoredCommitCountsFactory({ db }),
getMixpanelClient,
logger: coreLogger
})
})()
projectListenersFactory({
eventBus: getEventBus(),
logger: coreLogger
})()
}
},
async finalize({ app }) {
// Update server profile in mp
await updateServerMixpanelProfileFactory({
getServerInfo: getCachedServerInfoFactory({ db }),
getMixpanelClient,
getTotalStreamCount: getTotalStreamCountFactory({ db }),
getTotalWorkspaceCount: getTotalWorkspaceCountFactory({ db }),
getTotalUserCount: getTotalUserCountFactory({ db }),
getServerTotalModelCount: getServerTotalModelCountFactory(),
getServerTotalVersionCount: getServerTotalVersionCountFactory(),
logger: coreLogger
})()
// Run BullMQ monitor once the app is fully ready
app.use(bullMonitoringRouterFactory())
},
async shutdown() {
await shutdownResultListener()
await getGenericRedis().quit()
stopTestSubs?.()
}
}
export default coreModule