fetch-remote-text-by-line.ts 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. import type { BunFile } from 'bun';
  2. import { fetchWithRetry } from './fetch-retry';
  3. const decoder = new TextDecoder('utf-8');
  4. export async function* readFileByLine(file: string | BunFile): AsyncGenerator<string> {
  5. if (typeof file === 'string') {
  6. file = Bun.file(file);
  7. }
  8. let buf = '';
  9. for await (const chunk of file.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. export async function* createReadlineInterfaceFromResponse(resp: Response): AsyncGenerator<string> {
  26. if (!resp.body) {
  27. throw new Error('Failed to fetch remote text');
  28. }
  29. if (resp.bodyUsed) {
  30. throw new Error('Body has already been consumed.');
  31. }
  32. let buf = '';
  33. for await (const chunk of resp.body) {
  34. const chunkStr = decoder.decode(chunk).replaceAll('\r\n', '\n');
  35. for (let i = 0, len = chunkStr.length; i < len; i++) {
  36. const char = chunkStr[i];
  37. if (char === '\n') {
  38. yield buf;
  39. buf = '';
  40. } else {
  41. buf += char;
  42. }
  43. }
  44. }
  45. if (buf) {
  46. yield buf;
  47. }
  48. }
  49. export async function fetchRemoteTextAndCreateReadlineInterface(url: string | URL, opt?: RequestInit): Promise<AsyncGenerator<string>> {
  50. const resp = await fetchWithRetry(url, opt);
  51. return createReadlineInterfaceFromResponse(resp);
  52. }