/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Moderne Source Available License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://docs.moderne.io/licensing/moderne-source-available-license
*
* 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 * as rpc from "vscode-jsonrpc/node";
import {RpcObjectData, RpcObjectState, RpcSendQueue} from "../queue";
import {ReferenceMap} from "../../reference";
import {extractSourcePath, withMetrics} from "./metrics";
export class GetObject {
constructor(private readonly id: string,
private readonly sourceFileType?: string) {
}
static handle(
connection: rpc.MessageConnection,
remoteObjects: Map,
localObjects: Map any)>,
localRefs: ReferenceMap,
batchSize: number,
trace: () => boolean,
metricsCsv?: string,
): void {
const pendingData = new Map();
connection.onRequest(
new rpc.RequestType("GetObject"),
withMetrics(
"GetObject",
metricsCsv,
(context) => async request => {
const objId = request.id;
if (!localObjects.has(objId)) {
context.target = '';
return [
{state: RpcObjectState.DELETE},
{state: RpcObjectState.END_OF_OBJECT}
];
}
const objectOrGenerator = localObjects.get(objId)!;
if (typeof objectOrGenerator === 'function') {
const obj = await objectOrGenerator(objId);
localObjects.set(objId, obj);
}
const obj = localObjects.get(objId);
context.target = extractSourcePath(obj);
let allData = pendingData.get(objId);
if (!allData) {
const after = obj;
const before = remoteObjects.get(objId);
// Snapshot ref count so we can roll back on failure.
// Ref IDs are assigned sequentially, so any ref >= savedRefCount
// was added during this exchange.
const savedRefCount = localRefs.snapshot();
try {
allData = await new RpcSendQueue(localRefs, request.sourceFileType, trace())
.generate(after, before);
pendingData.set(objId, allData);
remoteObjects.set(objId, after);
} catch (e) {
remoteObjects.delete(objId);
localRefs.rollbackTo(savedRefCount);
throw e;
}
}
const batch = allData.splice(0, batchSize);
// If we've sent all data, remove from pending
if (allData.length === 0) {
pendingData.delete(objId);
}
return batch;
}
)
);
}
}