| 271 | * @category Parsers |
| 272 | */ |
| 273 | export const makeChannel = <IE>( |
| 274 | headers: Record<string, string>, |
| 275 | bufferSize = 16 |
| 276 | ): Channel.Channel< |
| 277 | Chunk.Chunk<Part>, |
| 278 | Chunk.Chunk<Uint8Array>, |
| 279 | MultipartError | IE, |
| 280 | IE, |
| 281 | unknown, |
| 282 | unknown |
| 283 | > => |
| 284 | Channel.acquireUseRelease( |
| 285 | Effect.all([ |
| 286 | makeConfig(headers), |
| 287 | Mailbox.make<Chunk.Chunk<Uint8Array>>(bufferSize) |
| 288 | ]), |
| 289 | ([config, mailbox]) => { |
| 290 | let partsBuffer: Array<Part> = [] |
| 291 | let exit = Option.none<Exit.Exit<void, IE | MultipartError>>() |
| 292 | |
| 293 | const input: AsyncInput.AsyncInputProducer<IE, Chunk.Chunk<Uint8Array>, unknown> = { |
| 294 | awaitRead: () => Effect.void, |
| 295 | emit(element) { |
| 296 | return mailbox.offer(element) |
| 297 | }, |
| 298 | error(cause) { |
| 299 | exit = Option.some(Exit.failCause(cause)) |
| 300 | return mailbox.end |
| 301 | }, |
| 302 | done(_value) { |
| 303 | return mailbox.end |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | const parser = MP.make({ |
| 308 | ...config, |
| 309 | onField(info, value) { |
| 310 | partsBuffer.push(new FieldImpl(info.name, info.contentType, MP.decodeField(info, value))) |
| 311 | }, |
| 312 | onFile(info) { |
| 313 | let chunks: Array<Uint8Array> = [] |
| 314 | let finished = false |
| 315 | const take: Channel.Channel<Chunk.Chunk<Uint8Array>> = Channel.suspend(() => { |
| 316 | if (chunks.length === 0) { |
| 317 | return finished ? Channel.void : Channel.zipRight(pump, take) |
| 318 | } |
| 319 | const chunk = Chunk.unsafeFromArray(chunks) |
| 320 | chunks = [] |
| 321 | return finished ? Channel.write(chunk) : Channel.zipRight( |
| 322 | Channel.write(chunk), |
| 323 | Channel.zipRight(pump, take) |
| 324 | ) |
| 325 | }) |
| 326 | partsBuffer.push(new FileImpl(info, take)) |
| 327 | return function(chunk) { |
| 328 | if (chunk === null) { |
| 329 | finished = true |
| 330 | } else { |