fetch-remote-text-by-line.js 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // @ts-check
  2. const { fetchWithRetry } = require('./fetch-retry');
  3. const decoder = new TextDecoder('utf-8');
  4. /**
  5. * @param {string} path
  6. */
  7. module.exports.readFileByLine = async function *(path) {
  8. let buf = '';
  9. for await (const chunk of Bun.file(path).stream()) {
  10. const chunkStr = decoder.decode(chunk).replaceAll('\r\n', '\n');
  11. for (let i = 0, len = chunkStr.length; i < len; i++) {
  12. const char = chunkStr[i];
  13. if (char === '\n') {
  14. yield buf;
  15. buf = '';
  16. } else {
  17. buf += char;
  18. }
  19. }
  20. }
  21. if (buf) {
  22. yield buf;
  23. }
  24. };
  25. /**
  26. * @param {import('undici').Response} resp
  27. */
  28. const createReadlineInterfaceFromResponse = async function *(resp) {
  29. if (!resp.body) {
  30. throw new Error('Failed to fetch remote text');
  31. }
  32. if (resp.bodyUsed) {
  33. throw new Error('Body has already been consumed.');
  34. }
  35. let buf = '';
  36. for await (const chunk of resp.body) {
  37. const chunkStr = decoder.decode(chunk).replaceAll('\r\n', '\n');
  38. for (let i = 0, len = chunkStr.length; i < len; i++) {
  39. const char = chunkStr[i];
  40. if (char === '\n') {
  41. yield buf;
  42. buf = '';
  43. } else {
  44. buf += char;
  45. }
  46. }
  47. }
  48. if (buf) {
  49. yield buf;
  50. }
  51. };
  52. module.exports.createReadlineInterfaceFromResponse = createReadlineInterfaceFromResponse;
  53. /**
  54. * @param {import('undici').RequestInfo} url
  55. * @param {import('undici').RequestInit} [opt]
  56. */
  57. module.exports.fetchRemoteTextAndCreateReadlineInterface = async (url, opt) => {
  58. const resp = await fetchWithRetry(url, opt);
  59. return createReadlineInterfaceFromResponse(resp);
  60. };