@@ -4,157 +4,154 @@ const { exec } = require('child_process');
44const fs = require ( 'fs' ) ;
55const path = require ( 'path' ) ;
66const https = require ( 'https' ) ;
7+ const readline = require ( 'readline' ) ;
78
8- // 获取命令行参数中的端口号和baseUrl
9+ const rl = readline . createInterface ( {
10+ input : process . stdin ,
11+ output : process . stdout ,
12+ } ) ;
13+
14+ // 获取命令行参数中的端口号
915let port = process . argv [ 2 ] || 4000 ;
10- const baseUrl = process . argv [ 3 ] || 'https://your-resource-domain.com' ;
1116
1217// 验证端口号是否有效
1318port = parseInt ( port ) ;
1419if ( isNaN ( port ) || port < 1 || port > 65535 ) {
15- console . error ( 'Invalid port number. Using default port 4000' ) ;
16- port = 4000 ;
20+ console . error ( 'Invalid port number. Using default port 4000' ) ;
21+ port = 4000 ;
1722}
1823
19- // 原来的颜色代码是 0,115,128,我们改成更亮的蓝绿色
20- const arrow = '\x1b[38;2;0;200;255m\u2192\x1b[0m' ; // 更亮的箭头颜色
21- const label = '\x1b[37m' ; // 更亮的白色文本
22- const value = '\x1b[38;2;0;255;255m' ; // 更亮的青色值
24+ // 颜色代码
25+ const arrow = '\x1b[38;2;0;200;255m\u2192\x1b[0m' ;
26+ const label = '\x1b[37m' ;
27+ const value = '\x1b[38;2;0;255;255m' ;
2328
2429console . log ( `${ arrow } ${ label } Local: ${ value } http://127.0.0.1:${ port } \x1b[0m` ) ;
25- console . log ( `${ arrow } ${ label } Base URL: ${ value } ${ baseUrl } \x1b[0m` ) ;
26- const server = exec ( `http-server -p ${ port } ` ) ;
27-
28- // 创建目录的函数
29- function ensureDirectoryExists ( filePath ) {
30- const dirname = path . dirname ( filePath ) ;
31- if ( fs . existsSync ( dirname ) ) {
32- return true ;
33- }
34- ensureDirectoryExists ( dirname ) ;
35- fs . mkdirSync ( dirname ) ;
36- }
37-
38- // 下载文件的函数
39- function downloadFile ( url , filePath , retryCount = 3 ) {
40- ensureDirectoryExists ( filePath ) ;
41-
42- // 如果文件已存在,跳过下载
43- if ( fs . existsSync ( filePath ) ) {
44- console . log ( `File already exists: ${ filePath } ` ) ;
45- return ;
46- }
47-
48- const file = fs . createWriteStream ( filePath ) ;
49- let fileSize = 0 ;
50- let currentRetry = 0 ;
51-
52- const startDownload = ( ) => {
53- fileSize = 0 ; // 重置文件大小计数
54-
55- https . get ( url , response => {
56- // 检查响应状态码
57- if ( response . statusCode !== 200 ) {
58- file . close ( ) ;
59- fs . unlink ( filePath , ( ) => { } ) ;
60- if ( currentRetry < retryCount ) {
61- currentRetry ++ ;
62- console . log ( `Retrying download (${ currentRetry } /${ retryCount } ) for ${ filePath } due to HTTP status ${ response . statusCode } ` ) ;
63- startDownload ( ) ;
64- } else {
65- console . error ( `Failed to download ${ filePath } : HTTP Status ${ response . statusCode } after ${ retryCount } retries` ) ;
66- }
67- return ;
68- }
69-
70- response . on ( 'data' , ( chunk ) => {
71- fileSize += chunk . length ;
72- } ) ;
73-
74- response . pipe ( file ) ;
75-
76- file . on ( 'finish' , ( ) => {
77- file . close ( ( ) => {
78- // 检查文件大小
79- if ( fileSize === 0 ) {
80- fs . unlink ( filePath , ( ) => {
81- if ( currentRetry < retryCount ) {
82- currentRetry ++ ;
83- console . log ( `Retrying download (${ currentRetry } /${ retryCount } ) for ${ filePath } due to empty file` ) ;
84- startDownload ( ) ;
85- } else {
86- console . error ( `Failed to download ${ filePath } : File is empty after ${ retryCount } retries` ) ;
87- }
88- } ) ;
89- } else {
90- console . log ( `Downloaded: ${ filePath } (${ fileSize } bytes)` ) ;
91- }
92- } ) ;
93- } ) ;
94- } ) . on ( 'error' , err => {
95- file . close ( ) ;
96- fs . unlink ( filePath , ( ) => {
97- if ( currentRetry < retryCount ) {
98- currentRetry ++ ;
99- console . log ( `Retrying download (${ currentRetry } /${ retryCount } ) for ${ filePath } due to error: ${ err . message } ` ) ;
100- startDownload ( ) ;
101- } else {
102- console . error ( `Download failed for ${ filePath } after ${ retryCount } retries:` , err . message ) ;
103- }
104- } ) ;
105- } ) ;
106- } ;
107-
108- // 添加文件写入错误处理
109- file . on ( 'error' , err => {
110- file . close ( ) ;
111- fs . unlink ( filePath , ( ) => {
112- if ( currentRetry < retryCount ) {
113- currentRetry ++ ;
114- console . log ( `Retrying download (${ currentRetry } /${ retryCount } ) for ${ filePath } due to file write error: ${ err . message } ` ) ;
115- startDownload ( ) ;
116- } else {
117- console . error ( `File write error for ${ filePath } after ${ retryCount } retries:` , err . message ) ;
118- }
119- } ) ;
120- } ) ;
121-
122- // 开始首次下载
123- startDownload ( ) ;
124- }
125-
126- // 获取标准输出
127- server . stdout . on ( 'data' , ( data ) => {
128- const output = data . toString ( ) ;
129-
130- // 定义正则表达式,支持任意文件后缀
131- const regex = / " G E T ( \/ .* ?\. [ a - z A - Z 0 - 9 ] + ) " E r r o r \( 4 0 4 \) : / g;
132-
133- // 使用正则表达式匹配包含 404 错误的行并提取路径
134- const matches = [ ...output . matchAll ( regex ) ] ;
135- if ( matches . length > 0 ) {
136- matches . forEach ( ( match ) => {
137- const missingFile = match [ 1 ] . replace ( / " / g, '' ) ; // 移除引号
138- console . log ( 'Missing file:' , missingFile ) ;
139-
140- // 构建完整的本地文件路径(从项目根目录开始)
141- const localPath = path . join ( process . cwd ( ) , missingFile ) ;
142-
143- // 使用命令行传入的baseUrl构建下载URL
144- const downloadUrl = `${ baseUrl } ${ missingFile } ` ;
145-
146- // 下载文件
147- downloadFile ( downloadUrl , localPath ) ;
148- } ) ;
149- }
150- } ) ;
151-
152- // 获取标准错误输出
153- server . stderr . on ( 'data' , ( data ) => {
154- console . error ( 'stderr:' , data . toString ( ) ) ;
155- } ) ;
15630
157- // 监听进程结束
158- server . on ( 'close' , ( code ) => {
159- console . log ( `http-server process exited with code ${ code } ` ) ;
31+ rl . question ( `${ arrow } ${ label } Please enter the base URL: \x1b[0m` , ( baseUrl ) => {
32+ console . log ( `${ arrow } ${ label } Base URL: ${ value } ${ baseUrl } \x1b[0m` ) ;
33+ rl . close ( ) ;
34+
35+ const server = exec ( `http-server -p ${ port } ` ) ;
36+
37+ // 创建目录的函数
38+ function ensureDirectoryExists ( filePath ) {
39+ const dirname = path . dirname ( filePath ) ;
40+ if ( fs . existsSync ( dirname ) ) {
41+ return true ;
42+ }
43+ ensureDirectoryExists ( dirname ) ;
44+ fs . mkdirSync ( dirname ) ;
45+ }
46+
47+ // 下载文件的函数
48+ function downloadFile ( url , filePath , retryCount = 3 ) {
49+ ensureDirectoryExists ( filePath ) ;
50+
51+ if ( fs . existsSync ( filePath ) ) {
52+ console . log ( `File already exists: ${ filePath } ` ) ;
53+ return ;
54+ }
55+
56+ const file = fs . createWriteStream ( filePath ) ;
57+ let fileSize = 0 ;
58+
59+ let currentRetry = 0 ;
60+
61+ const startDownload = ( ) => {
62+ fileSize = 0 ;
63+
64+ https . get ( url , ( response ) => {
65+ if ( response . statusCode !== 200 ) {
66+ file . close ( ) ;
67+ fs . unlink ( filePath , ( ) => { } ) ;
68+ if ( currentRetry < retryCount ) {
69+ currentRetry ++ ;
70+ console . log ( `Retrying download (${ currentRetry } /${ retryCount } ) for ${ filePath } due to HTTP status ${ response . statusCode } ` ) ;
71+ startDownload ( ) ;
72+ } else {
73+ console . error ( `Failed to download ${ filePath } : HTTP Status ${ response . statusCode } after ${ retryCount } retries` ) ;
74+ }
75+ return ;
76+ }
77+
78+ response . on ( 'data' , ( chunk ) => {
79+ fileSize += chunk . length ;
80+ } ) ;
81+
82+ response . pipe ( file ) ;
83+
84+ file . on ( 'finish' , ( ) => {
85+ file . close ( ( ) => {
86+ if ( fileSize === 0 ) {
87+ fs . unlink ( filePath , ( ) => {
88+ if ( currentRetry < retryCount ) {
89+ currentRetry ++ ;
90+ console . log ( `Retrying download (${ currentRetry } /${ retryCount } ) for ${ filePath } due to empty file` ) ;
91+ startDownload ( ) ;
92+ } else {
93+ console . error ( `Failed to download ${ filePath } : File is empty after ${ retryCount } retries` ) ;
94+ }
95+ } ) ;
96+ } else {
97+ console . log ( `Downloaded: ${ filePath } (${ fileSize } bytes)` ) ;
98+ }
99+ } ) ;
100+ } ) ;
101+ } ) . on ( 'error' , ( err ) => {
102+ file . close ( ) ;
103+ fs . unlink ( filePath , ( ) => {
104+ if ( currentRetry < retryCount ) {
105+ currentRetry ++ ;
106+ console . log ( `Retrying download (${ currentRetry } /${ retryCount } ) for ${ filePath } due to error: ${ err . message } ` ) ;
107+ startDownload ( ) ;
108+ } else {
109+ console . error ( `Download failed for ${ filePath } after ${ retryCount } retries:` , err . message ) ;
110+ }
111+ } ) ;
112+ } ) ;
113+ } ;
114+
115+ file . on ( 'error' , ( err ) => {
116+ file . close ( ) ;
117+ fs . unlink ( filePath , ( ) => {
118+ if ( currentRetry < retryCount ) {
119+ currentRetry ++ ;
120+ console . log ( `Retrying download (${ currentRetry } /${ retryCount } ) for ${ filePath } due to file write error: ${ err . message } ` ) ;
121+ startDownload ( ) ;
122+ } else {
123+ console . error ( `File write error for ${ filePath } after ${ retryCount } retries:` , err . message ) ;
124+ }
125+ } ) ;
126+ } ) ;
127+
128+ startDownload ( ) ;
129+ }
130+
131+ server . stdout . on ( 'data' , ( data ) => {
132+ const output = data . toString ( ) ;
133+ const regex = / " G E T ( \/ .* ?\. [ a - z A - Z 0 - 9 ] + ) " E r r o r \( 4 0 4 \) : / g;
134+ const matches = [ ...output . matchAll ( regex ) ] ;
135+
136+ if ( matches . length > 0 ) {
137+ matches . forEach ( ( match ) => {
138+ const encodedMissingFile = match [ 1 ] . replace ( / " / g, '' ) ;
139+ const decodedMissingFile = decodeURIComponent ( encodedMissingFile ) ;
140+ console . log ( 'Missing file:' , decodedMissingFile ) ;
141+
142+ const localPath = path . join ( process . cwd ( ) , decodedMissingFile ) ;
143+ const downloadUrl = `${ baseUrl } ${ encodedMissingFile } ` ;
144+
145+ downloadFile ( downloadUrl , localPath ) ;
146+ } ) ;
147+ }
148+ } ) ;
149+
150+ server . stderr . on ( 'data' , ( data ) => {
151+ console . error ( 'stderr:' , data . toString ( ) ) ;
152+ } ) ;
153+
154+ server . on ( 'close' , ( code ) => {
155+ console . log ( `http-server process exited with code ${ code } ` ) ;
156+ } ) ;
160157} ) ;
0 commit comments