blob: cd2beefa0943e46ad587f8770ae13f37316713ad [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 { open } from "node:fs/promises";
import { resolve } from "node:path";
import { pipeline } from "node:stream/promises";
import { Writable, type TransformCallback } from "node:stream";
import { HeaderValue, HeaderKeyFactory } from "../index.js";
import { getClient } from "./utils.js";
export const fileToTopic = async (
filepath: string,
streamName: string,
topicName: string,
highWaterMark = 512 * 1024,
) => {
const cli = getClient();
await cli.stream.ensure(streamName);
await cli.topic.ensure(streamName, topicName);
const fd = await open(filepath);
const fname = filepath.split("/").pop() || filepath;
const st = await fd.stat();
console.log(
"FILE/STAT",
fname,
"~",
(st.size / (1024 * 1024)).toFixed(2),
"mb",
st,
);
const dStart = Date.now();
try {
let idx = 0;
await pipeline(
fd.createReadStream({ highWaterMark }),
new Writable({
async write(
chunks: Buffer,
encoding: BufferEncoding,
cb: TransformCallback,
) {
const messages = [
{
headers: [
{
key: HeaderKeyFactory.String("fileindex"),
value: HeaderValue.Uint32(idx++),
},
{
key: HeaderKeyFactory.String("filename"),
value: HeaderValue.String(fname),
},
],
payload: chunks,
},
];
try {
await cli.message.send({
streamId: streamName,
topicId: topicName,
messages,
});
cb();
} catch (err) {
console.log("WRITE ERR", err, chunks);
cb(err as Error);
}
},
}),
);
console.log(`Finished ! took ${Date.now() - dStart}ms`);
} catch (err) {
console.error("Pipeline failed !", err);
throw err;
}
};
const argz = process.argv.slice(2);
const [rPath, streamIdStr, topicIdStr] = argz;
if (argz.length < 3 || ["-h", "--help", "?"].includes(argz[0])) {
console.log(
`Usage: node stream-file-to-topic.js filePath streamName topicName`,
);
console.log("got", argz);
console.log("note: this script only accept numerical stream/topic id");
process.exit(1);
}
const filepath = resolve(rPath);
const streamName = streamIdStr;
const topicName = topicIdStr;
console.log("running with params:", { filepath, streamName, topicName });
try {
await fileToTopic(filepath, streamName, topicName, 512 * 1024);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (err) {
process.exit(1);
}
process.exit(0);