import { Account, Environment, errors, Notification } from "@kumori/aurora-interfaces"; interface HandleEnvironmentEventParams { entityId: string; eventData: any; parentParts: { [entity: string]: string }; accountsMap: Map; environmentsMap: Map; pendingCloudProviderUpdates: Array<{ environmentId: string; accountId: string }>; } interface HandleEnvironmentEventResult { environment: Environment; pendingCloudProviderUpdate: { environmentId: string; accountId: string } | null; hasTenant: boolean; tenantId: string; } interface HandleEnvironmentOperationSuccessParams { action: string; entityName: string; originalData: Environment; } interface HandleEnvironmentOperationSuccessResult { updatedEnvironment: Environment | null; shouldDelete: boolean; notification: Notification | null; eventType: "created" | "updated" | "cleaned" | null; } interface HandleEnvironmentOperationErrorParams { action: string; entityName: string; originalData: Environment; error: any; } interface HandleEnvironmentOperationErrorResult { updatedEnvironment: Environment; notification: Notification; eventType: "creationError" | "updateError" | "deletionError"; } /** * Handles the "environment" event from WebSocket messages * Processes environment data updates and cloud provider associations */ export const handleEnvironmentEvent = ({ entityId, eventData, parentParts, accountsMap, environmentsMap, pendingCloudProviderUpdates, }: HandleEnvironmentEventParams): HandleEnvironmentEventResult => { const tenantId = parentParts.tenant; const accountId = parentParts.account; const accountKey = tenantId ? `${tenantId}/${accountId}` : accountId; const relatedAccount = accountsMap.get(accountKey); let cloudProviderName = relatedAccount?.cloudProvider?.name || ""; let pendingCloudProviderUpdate: { environmentId: string; accountId: string } | null = null; if (!relatedAccount) { pendingCloudProviderUpdate = { environmentId: entityId, accountId: accountId, }; } const envKey = tenantId && accountId ? `${tenantId}/${accountId}/${entityId}` : entityId; const existingEnvironment = environmentsMap.get(envKey); const newEnvironment: Environment = { id: entityId, name: entityId, account: accountId, tenant: tenantId, logo: "", services: [], domains: [], status: (() => { const existingCode = existingEnvironment?.status?.code; const isPurging = existingCode === "PURGING" || existingCode === "CLEANING_ENVIRONMENT"; const eventCode = eventData.meta?.deleted ? "DELETING" : eventData.status?.state?.code; if (isPurging && typeof eventCode === "string" && eventCode.startsWith("DELETING")) { return { code: "PURGING", message: `Environment ${entityId} is being purged.`, timestamp: new Date().toISOString() }; } if (eventData.meta?.deleted) { return { code: "DELETING", message: `Environment ${entityId} is being deleted.`, timestamp: new Date().toISOString() }; } return { code: eventData.status.state.code, message: eventData.status.state.message, timestamp: eventData.status.state.timestamp }; })(), highAvaliable: eventData.spec.highlyAvailable || false, usage: { current: { cpu: eventData.status.marks.vcpu.current / 1000, memory: eventData.status.marks.memory.current / 1000, storage: eventData.status.marks.storage.current / 1000, volatileStorage: eventData.status.marks.vstorage.current / 1000, nonReplicatedStorage: eventData.status.marks.nrstorage.current / 1000, persistentStorage: eventData.status.marks.rstorage.current / 1000, nodes: eventData.status.nodes.length || 0, memoryConsuption: existingEnvironment?.usage.current.memoryConsuption || [], cpuConsuption: existingEnvironment?.usage.current.cpuConsuption || [], }, limit: { cpu: { max: eventData.spec.marks.vcpu.highmark / 1000, min: eventData.spec.marks.vcpu.lowmark / 1000, }, memory: { max: eventData.spec.marks.memory.highmark / 1000, min: eventData.spec.marks.memory.lowmark / 1000, }, storage: { max: eventData.spec.marks.storage.highmark / 1000, min: eventData.spec.marks.storage.lowmark / 1000, }, volatileStorage: { max: eventData.spec.marks.vstorage.highmark / 1000, min: eventData.spec.marks.vstorage.lowmark / 1000, }, nonReplicatedStorage: { max: eventData.spec.marks.nrstorage.highmark / 1000, min: eventData.spec.marks.nrstorage.lowmark / 1000, }, persistentStorage: { max: eventData.spec.marks.rstorage.highmark / 1000, min: eventData.spec.marks.rstorage.lowmark / 1000, }, }, cost: eventData.status.marks.cost.current, }, organization: "", cloudProvider: cloudProviderName, labels: Object.values(eventData.meta.labels), nodes: { max: eventData.spec.marks.nodes.highmark, min: eventData.status.minimumRequiredNodes?.ingress?.replicas || 0, }, type: eventData.spec.type || "primary", cluster: { name: eventData.spec.cluster?.name || "" }, isIsolated: eventData.spec.isolated || false, }; return { environment: newEnvironment, pendingCloudProviderUpdate, hasTenant: false, tenantId, }; }; /** * Handles successful environment operations (CREATE, UPDATE, DELETE, CLEAN) */ export const handleEnvironmentOperationSuccess = ({ action, entityName, originalData, }: HandleEnvironmentOperationSuccessParams): HandleEnvironmentOperationSuccessResult => { const envData = originalData; if (action === "DELETE") { return { updatedEnvironment: null, shouldDelete: true, notification: null, eventType: null, }; } if (action === "CLEAN") { const updatedEnvironment: Environment = { ...envData, status: { code: "CLEANING_ENVIRONMENT", message: `Environment ${envData.name} is being cleaned.`, timestamp: new Date().toISOString(), }, }; const envNotification: Notification = { type: "success", subtype: errors.environment.purged.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { environment: envData.name, account: envData.account, tenant: envData.tenant, }, }; return { updatedEnvironment, shouldDelete: false, notification: envNotification, eventType: "cleaned", }; } if (envData) { const updatedEnvironment: Environment = { ...envData, status: { code: "ENVIRONMENT_READY", message: `Environment ${envData.name} is ready.`, timestamp: new Date().toISOString(), }, }; let eventType: "created" | "updated" | null = null; if (action === "CREATE") { eventType = "created"; } else if (action === "UPDATE") { eventType = "updated"; } return { updatedEnvironment, shouldDelete: false, notification: null, eventType, }; } return { updatedEnvironment: null, shouldDelete: false, notification: null, eventType: null, }; }; /** * Handles failed environment operations (CREATE, UPDATE, DELETE) */ export const handleEnvironmentOperationError = ({ action, entityName, originalData, error, }: HandleEnvironmentOperationErrorParams): HandleEnvironmentOperationErrorResult => { const eventType: "creationError" | "updateError" | "deletionError" = action === "CREATE" ? "creationError" : action === "UPDATE" ? "updateError" : "deletionError"; const envErrEntry = action === "CREATE" ? errors.environment.creationError : action === "UPDATE" ? errors.environment.updateError : errors.environment.deletionError; const envErrorNotification: Notification = { type: "error", subtype: envErrEntry.subtype, date: Date.now().toString(), status: "unread", info_content: { code: error?.error?.code || "UNKNOWN_ERROR", message: error?.error?.content || error?.error?.message || "Unknown error", timestamp: error?.error?.timestamp || "", }, callToAction: false, data: { environment: originalData.name, account: originalData.account, tenant: originalData.tenant, }, userError: true, }; const updatedEnvironment: Environment = { ...originalData, status: { code: "ERROR", message: error?.error?.content || error?.error?.message || "Operation failed", timestamp: new Date().toISOString(), }, }; return { updatedEnvironment, notification: envErrorNotification, eventType, }; };