blob: 8656ff61481548dc046114b8fca77e08f8c7bfc0 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { connect, type Socket } from 'node:net';
import { resolveExistingStorageRootControlDirectory } from '@maka/storage/root-authority';
import { readHostRegistration } from '../control/registration.js';
import { resolveRuntimeHostManagedDeployment } from '../operator/managed-deployment.js';
import {
activateRuntimeHostManagedDeployment,
type ActivateRuntimeHostManagedDeploymentInput,
} from './managed-activation.js';
const BRIDGE_CONNECT_TIMEOUT_MS = 5_000;
export async function openRuntimeHostManagedStdioBridge(
input: ActivateRuntimeHostManagedDeploymentInput,
overrides: {
readonly activate?: (
input: ActivateRuntimeHostManagedDeploymentInput,
) => ReturnType<typeof activateRuntimeHostManagedDeployment>;
readonly openSocket?: (endpoint: string) => Promise<Socket>;
} = {},
): Promise<Socket> {
const activation = await (overrides.activate ?? activateRuntimeHostManagedDeployment)(input);
const resolved = await resolveRuntimeHostManagedDeployment(input.rootId, input.authority);
const { controlDirectory } = await resolveExistingStorageRootControlDirectory(
resolved.capability,
);
const registration = await readHostRegistration(controlDirectory);
if (
!registration ||
registration.rootId !== activation.rootId ||
registration.hostEpoch !== activation.hostEpoch
) {
throw new Error('The activated Runtime Host registration changed before bridge connection');
}
return (overrides.openSocket ?? openBridgeSocket)(registration.endpoint);
}
function openBridgeSocket(endpoint: string): Promise<Socket> {
return new Promise((resolve, reject) => {
const socket = connect(endpoint);
const timer = setTimeout(() => {
cleanup();
socket.destroy();
reject(new Error('Timed out connecting the Runtime Host stdio bridge'));
}, BRIDGE_CONNECT_TIMEOUT_MS);
const cleanup = () => {
clearTimeout(timer);
socket.off('connect', onConnect);
socket.off('error', onError);
};
const onConnect = () => {
cleanup();
resolve(socket);
};
const onError = (error: Error) => {
cleanup();
reject(error);
};
socket.once('connect', onConnect);
socket.once('error', onError);
});
}