11import * as dns from "node:dns/promises" ;
22import * as net from "node:net" ;
33import * as tls from "node:tls" ;
4+ import { createHash } from "node:crypto" ;
45import { headers } from "../library/http" ;
56import { LinkInformation } from "./linkValidation" ;
67
@@ -154,6 +155,7 @@ export interface DownloadResult {
154155 avgBytesPerSecond : number ;
155156 statusCode : number | null ;
156157 connections : number ;
158+ md5 : string | null ;
157159}
158160
159161export interface DownloadProgress {
@@ -166,6 +168,7 @@ async function downloadOnce(
166168 link : string ,
167169 range : { start : number ; end : number } | undefined ,
168170 onBytes : ( delta : number ) => void ,
171+ onChunk ?: ( chunk : Buffer ) => void ,
169172) : Promise < { statusCode : number | null ; bytes : number } > {
170173 const url = new URL ( link ) ;
171174 const isHttps = url . protocol === "https:" ;
@@ -225,12 +228,14 @@ async function downloadOnce(
225228 const bodyChunk = headerBuf . subarray ( bodyStart ) ;
226229 bytes += bodyChunk . length ;
227230 onBytes ( bodyChunk . length ) ;
231+ onChunk ?.( bodyChunk ) ;
228232 }
229233 headerBuf = Buffer . alloc ( 0 ) ;
230234 }
231235 } else {
232236 bytes += chunk . length ;
233237 onBytes ( chunk . length ) ;
238+ onChunk ?.( chunk ) ;
234239 }
235240 } ) ;
236241
@@ -269,6 +274,7 @@ export async function downloadFull(
269274 } ;
270275
271276 let statusCode : number | null = null ;
277+ let md5 : string | null = null ;
272278
273279 try {
274280 if ( useMulti ) {
@@ -279,13 +285,22 @@ export async function downloadFull(
279285 const e = Math . floor ( ( size * ( i + 1 ) ) / connections ) - 1 ;
280286 ranges . push ( { start : s , end : e } ) ;
281287 }
288+ const hashers = ranges . map ( ( ) => createHash ( "md5" ) ) ;
282289 const results = await Promise . all (
283- ranges . map ( ( r ) => downloadOnce ( link , r , onBytes ) ) ,
290+ ranges . map ( ( r , i ) =>
291+ downloadOnce ( link , r , onBytes , ( chunk ) => hashers [ i ] ! . update ( chunk ) ) ,
292+ ) ,
284293 ) ;
285294 statusCode = results [ 0 ] ?. statusCode ?? null ;
295+ const joined = hashers . map ( ( h ) => h . digest ( "hex" ) ) . join ( "" ) ;
296+ md5 = createHash ( "md5" ) . update ( joined ) . digest ( "hex" ) ;
286297 } else {
287- const result = await downloadOnce ( link , undefined , onBytes ) ;
298+ const hasher = createHash ( "md5" ) ;
299+ const result = await downloadOnce ( link , undefined , onBytes , ( chunk ) =>
300+ hasher . update ( chunk ) ,
301+ ) ;
288302 statusCode = result . statusCode ;
303+ md5 = hasher . digest ( "hex" ) ;
289304 }
290305 } catch ( err ) {
291306 const message = err instanceof Error ? err . message : String ( err ) ;
@@ -300,5 +315,6 @@ export async function downloadFull(
300315 avgBytesPerSecond : durationMs > 0 ? bytes / ( durationMs / 1000 ) : 0 ,
301316 statusCode,
302317 connections : useMulti ? connections : 1 ,
318+ md5,
303319 } ;
304320}
0 commit comments