merge: server architecture modularization
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
import {
|
||||
resolveAnalyticsOwnerLabel,
|
||||
resolveAnalyticsOwnerSegment,
|
||||
sendMindSpaceAnalyticsEvent,
|
||||
} from '../mindspace-analytics.mjs';
|
||||
import { createPageEditSessionService } from '../mindspace-page-edit-session.mjs';
|
||||
import { resolveMindSpaceRuntimeConfig } from '../mindspace-runtime-config.mjs';
|
||||
import { createNotificationDispatcher } from '../notification-dispatcher.mjs';
|
||||
import { startScheduleReminderWorker } from '../schedule-reminder-worker.mjs';
|
||||
import { loadWechatMpModule } from '../wechat-mp-loader.mjs';
|
||||
|
||||
export async function bootstrapPortalIntegrationServices({
|
||||
pool,
|
||||
h5Root,
|
||||
env = process.env,
|
||||
usersRoot,
|
||||
wechatMpConfig,
|
||||
authPool,
|
||||
userAuth,
|
||||
sessionAccess,
|
||||
tkmindProxy,
|
||||
scheduleService,
|
||||
wechatScheduleLlmConfigService,
|
||||
llmProviderService,
|
||||
chatIntentRouter,
|
||||
systemDisclosurePolicyService,
|
||||
sessionSnapshotService,
|
||||
mindSpaceAnalyticsConfig,
|
||||
subscriptionService,
|
||||
apiTarget,
|
||||
apiSecret,
|
||||
mindSpacePages,
|
||||
mindSpacePageLiveEdit,
|
||||
logger = console,
|
||||
loadWechatMpModuleFn = loadWechatMpModule,
|
||||
resolveMindSpaceRuntimeConfigFn =
|
||||
resolveMindSpaceRuntimeConfig,
|
||||
resolveAnalyticsOwnerSegmentFn =
|
||||
resolveAnalyticsOwnerSegment,
|
||||
resolveAnalyticsOwnerLabelFn =
|
||||
resolveAnalyticsOwnerLabel,
|
||||
sendMindSpaceAnalyticsEventFn =
|
||||
sendMindSpaceAnalyticsEvent,
|
||||
createNotificationDispatcherFn =
|
||||
createNotificationDispatcher,
|
||||
startScheduleReminderWorkerFn =
|
||||
startScheduleReminderWorker,
|
||||
createPageEditSessionServiceFn =
|
||||
createPageEditSessionService,
|
||||
setIntervalFn = setInterval,
|
||||
} = {}) {
|
||||
if (
|
||||
!pool ||
|
||||
!h5Root ||
|
||||
!usersRoot ||
|
||||
!userAuth ||
|
||||
!sessionAccess ||
|
||||
!tkmindProxy ||
|
||||
!llmProviderService
|
||||
) {
|
||||
throw new Error(
|
||||
'bootstrapPortalIntegrationServices requires Portal integration dependencies',
|
||||
);
|
||||
}
|
||||
|
||||
const wechatMp = await loadWechatMpModuleFn(h5Root);
|
||||
const wechatMpService =
|
||||
wechatMp.createWechatMpService({
|
||||
config: wechatMpConfig,
|
||||
userAuth,
|
||||
sessionAccess,
|
||||
pageDataFinishGuard: authPool
|
||||
? {
|
||||
pool: authPool,
|
||||
h5Root,
|
||||
storageRoot:
|
||||
resolveMindSpaceRuntimeConfigFn(
|
||||
h5Root,
|
||||
env,
|
||||
).storageRoot,
|
||||
}
|
||||
: null,
|
||||
apiFetch: tkmindProxy.apiFetch,
|
||||
startAgentSession: ({
|
||||
userId,
|
||||
workingDir,
|
||||
sessionPolicy,
|
||||
}) =>
|
||||
tkmindProxy.startSessionForUser(userId, {
|
||||
workingDir,
|
||||
sessionPolicy,
|
||||
}),
|
||||
sessionApiFetch: async (
|
||||
sessionId,
|
||||
pathname,
|
||||
init,
|
||||
) => {
|
||||
const target =
|
||||
await tkmindProxy.resolveTarget(sessionId);
|
||||
return tkmindProxy.apiFetchTo(
|
||||
target,
|
||||
pathname,
|
||||
init,
|
||||
);
|
||||
},
|
||||
submitSessionReply: ({
|
||||
userId,
|
||||
sessionId,
|
||||
requestId,
|
||||
userMessage,
|
||||
options,
|
||||
}) =>
|
||||
tkmindProxy.submitSessionReplyForUser(
|
||||
userId,
|
||||
sessionId,
|
||||
requestId,
|
||||
userMessage,
|
||||
options,
|
||||
),
|
||||
scheduleService:
|
||||
env.H5_SCHEDULE_ENABLED === '1'
|
||||
? scheduleService
|
||||
: null,
|
||||
wechatScheduleLlmConfigService,
|
||||
llmProviderService,
|
||||
chatIntentRouter,
|
||||
systemDisclosurePolicyService,
|
||||
sessionIntentClassifier: ({ text }) =>
|
||||
chatIntentRouter?.classifySessionAction({
|
||||
text,
|
||||
}),
|
||||
onPageGenerated: async ({
|
||||
userId,
|
||||
sessionId,
|
||||
artifacts = [],
|
||||
}) => {
|
||||
for (const artifact of artifacts) {
|
||||
void sendMindSpaceAnalyticsEventFn({
|
||||
config: mindSpaceAnalyticsConfig,
|
||||
eventName: 'page_generated',
|
||||
ownerId: userId,
|
||||
ownerSegment:
|
||||
resolveAnalyticsOwnerSegmentFn(
|
||||
(await userAuth
|
||||
?.getUserById(userId)
|
||||
.catch(() => null)) ?? {},
|
||||
),
|
||||
ownerLabel: resolveAnalyticsOwnerLabelFn(
|
||||
(await userAuth
|
||||
?.getUserById(userId)
|
||||
.catch(() => null)) ?? {},
|
||||
),
|
||||
pageId: artifact.relativePath,
|
||||
publicationId: sessionId,
|
||||
agentRunId: sessionId,
|
||||
channel: 'wechat_mp',
|
||||
url:
|
||||
artifact.url ||
|
||||
artifact.relativePath ||
|
||||
'/',
|
||||
});
|
||||
}
|
||||
},
|
||||
applySessionLlmProvider: (sessionId) =>
|
||||
tkmindProxy.applySessionLlmProvider(sessionId),
|
||||
refreshSessionSnapshot:
|
||||
sessionSnapshotService?.isEnabled()
|
||||
? (sessionId, userId) =>
|
||||
sessionSnapshotService.refresh(
|
||||
sessionId,
|
||||
userId,
|
||||
async (pathname, init) => {
|
||||
const target =
|
||||
await tkmindProxy.resolveTarget(
|
||||
sessionId,
|
||||
);
|
||||
return tkmindProxy.apiFetchTo(
|
||||
target,
|
||||
pathname,
|
||||
init,
|
||||
);
|
||||
},
|
||||
)
|
||||
: null,
|
||||
});
|
||||
|
||||
const notificationDispatcher =
|
||||
createNotificationDispatcherFn({
|
||||
sendWechatTextToUser: wechatMpService?.enabled
|
||||
? (userId, text) =>
|
||||
wechatMpService.sendTextToUser(
|
||||
userId,
|
||||
text,
|
||||
)
|
||||
: null,
|
||||
});
|
||||
userAuth.setRechargeNotifier(
|
||||
async ({ userId, title, body, dedupeKey }) => {
|
||||
await notificationDispatcher.sendRechargeSuccess({
|
||||
userId,
|
||||
title,
|
||||
body,
|
||||
dedupeKey,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let scheduleReminderWorker = null;
|
||||
if (
|
||||
env.H5_REMINDER_WORKER_ENABLED === '1' &&
|
||||
wechatMpService?.enabled &&
|
||||
scheduleService
|
||||
) {
|
||||
scheduleReminderWorker =
|
||||
startScheduleReminderWorkerFn({
|
||||
scheduleService,
|
||||
notificationDispatcher,
|
||||
});
|
||||
logger.log('Schedule reminder worker enabled');
|
||||
}
|
||||
|
||||
let subscriptionExpiryTimer = null;
|
||||
if (subscriptionService) {
|
||||
subscriptionExpiryTimer = setIntervalFn(
|
||||
async () => {
|
||||
try {
|
||||
const { renewed, failed } =
|
||||
await subscriptionService.processAutoRenewals();
|
||||
if (renewed > 0) {
|
||||
logger.log(
|
||||
`Auto-renewed ${renewed} subscription(s)`,
|
||||
);
|
||||
}
|
||||
if (failed > 0) {
|
||||
logger.log(
|
||||
`Auto-renew failed for ${failed} subscription(s) (balance insufficient)`,
|
||||
);
|
||||
}
|
||||
const expired =
|
||||
await subscriptionService.expireStaleSubscriptions();
|
||||
if (expired > 0) {
|
||||
logger.log(
|
||||
`Expired ${expired} stale subscription(s)`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
'Subscription expiry check failed:',
|
||||
error,
|
||||
);
|
||||
}
|
||||
},
|
||||
60 * 60 * 1000,
|
||||
);
|
||||
subscriptionExpiryTimer.unref?.();
|
||||
}
|
||||
|
||||
const mindSpacePageEditSession =
|
||||
createPageEditSessionServiceFn({
|
||||
apiTarget,
|
||||
apiSecret,
|
||||
userAuth,
|
||||
sessionAccess,
|
||||
pageService: mindSpacePages,
|
||||
pageLiveEdit: mindSpacePageLiveEdit,
|
||||
llmProviderService,
|
||||
});
|
||||
if (wechatMpService?.enabled) {
|
||||
logger.log('WeChat MP webhook enabled');
|
||||
}
|
||||
logger.log(
|
||||
`User auth enabled (MySQL), workspace root: ${usersRoot}`,
|
||||
);
|
||||
|
||||
return {
|
||||
wechatMpService,
|
||||
notificationDispatcher,
|
||||
scheduleReminderWorker,
|
||||
subscriptionExpiryTimer,
|
||||
mindSpacePageEditSession,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user