다운로드 창에 완료라고 적히는 것과 저장된 파일을 다음 작업에 넘길 수 있는 것은 같은 질문이 아니었다. 북극성의 자동화 다운로드는 완료 이벤트를 받은 뒤 실제 저장 위치에서 크기를 읽고 내용을 해시한다. 결과를 받았다는 말에 어떤 검사가 들어 있는지 남기려 했다.

현재 탭이 시작한 첫 전송을 기다린다

downloadFrom은 동작을 실행하기 전에 현재 프로필 세션의 will-download를 듣는다. 이벤트가 와도 source의 webContents ID가 작업 탭과 다르면 받지 않는다. 같은 탭에서 이미 추적할 item을 잡은 뒤 추가 전송이 나오면 그 추가 item은 취소한다. 페이지 전체의 최근 파일을 임의로 고르는 대신 이번 동작과 묶을 대상을 좁혔다.

이 방식은 네트워크 서버의 업무 요청 ID를 발급받아 연결한 것과는 다르다. 탭과 네이티브 이벤트가 제공하는 경계다. 파일 선택 창과 새 창 전송 같은 다른 경로의 지원은 각 경로에서 별도 확인해야 한다. 한 함수가 모든 사이트의 다운로드 방식을 자동으로 이해한다고 설명하지 않았다.

완료 상태 뒤에도 실제 파일을 읽어야 한다

done 이벤트에서는 state가 completed인지 먼저 본다. 취소나 중단을 정상 완료로 바꾸지 않는다. 이어 getSavePath가 가리키는 파일을 stat으로 읽고 실제 size와 네이티브 item의 received bytes를 비교한다. 숫자가 다르면 DOWNLOAD_SIZE_MISMATCH로 멈춘다.

그다음 저장된 파일을 스트림으로 읽어 SHA256을 계산한다. 큰 파일 전체를 한 번에 메모리로 옮기는 대신 청크마다 읽으며 작업 취소를 확인한다. 파일을 찾을 수 없거나 읽기가 실패한 경우도 성공 영수증으로 바꾸지 않는다. 완료 이벤트가 왔다는 사실은 이 검사들을 생략할 이유가 되지 못했다.

해시는 비교 대상이 있을 때 의미가 더해진다

반환값에는 기록 ID·파일 이름·실제 크기·SHA256이 담긴다. 저장 경로를 공개 결과에 그대로 넣지 않고 다음 단계가 같은 자료를 확인할 지문을 남긴다. 다만 해시를 새로 계산했다는 사실과 기대했던 원본의 해시가 일치한다는 사실을 구별해야 한다. 원본 지문을 모르면 비교까지 한 것은 아니다.

크기가 같은 서로 다른 파일을 구분하는 데 해시가 도움이 되지만 영상이 끝까지 재생되는지나 문서 내용이 맞는지는 말해 주지 않는다. 현재 함수는 다운로드 뒤 파일의 모든 변경을 계속 감시하지도 않는다. 나는 전송 결과 확인과 파일 형식·업무 내용 검사를 후속 단계가 맡을 수 있도록 영수증의 의미를 좁혔다.

늦게 온 거절과 취소도 정리할 자리가 필요했다

완료 대기의 promise에는 클릭 전에 거절 처리기를 붙인다. 동작을 기다리는 중 네이티브 이벤트가 먼저 실패해도 처리되지 않은 거절로 새는 일을 줄이기 위한 순서다. 마지막에는 타이머와 이벤트 리스너를 제거한다. 성공할 때만 정리하면 실패한 대기가 다음 작업까지 남을 수 있다.

시간 제한은 실제 전송과 해시 계산에 쓰이며 사용자가 의도적으로 멈춘 동안은 별도로 취급한다. 하지만 작업 취소 검사는 계속한다. 제한 시간이 늘었다고 새 다운로드를 시작하는 함수도 아니다. 전송의 수명과 기다리는 호출의 수명을 함께 정리하는 것이 결과 파일만큼 중요한 구현 부분이었다.

시험이 보여 주는 결과와 이 글의 검증을 나눈다

기존 파일 감사 시험에는 한글 이름, 빈 파일, 긴 이름, 위험 문자의 정리, 동명 순차·동시 다운로드의 실제 바이트 대조가 들어 있다. 나는 이번에 해당 시험의 설계를 읽었으며 원래 앱에서 다시 실행한 결과로 보고하지 않았다. 시험 코드가 존재하는 것과 현재 서비스가 통과한 것은 다르다.

공유 모듈에서는 실제로 전달된 합성 bytes를 해시하고 완료 선언·수신량·예상 해시를 비교한다. 파일을 찾아 다운로드하지 않는 작은 예제라 네트워크 출처와 디스크 내구성은 항상 미확인으로 남는다. 이 좁은 비교를 직접 실행해 보면 완료 상태, 크기 일치, 원본 지문 일치를 왜 따로 기록했는지 확인할 수 있다.