Class: Pindo::Command::Web::Run

Inherits:
Pindo::Command::Web show all
Defined in:
lib/pindo/command/web/run.rb

Defined Under Namespace

Modules: UI

Constant Summary

Constants inherited from Pindo::Command

DEFAULT_OPTIONS, DEFAULT_ROOT_OPTIONS

Instance Attribute Summary

Attributes inherited from Pindo::Command

#args_help_flag

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Pindo::Command

run

Methods included from Funlog::Mixin

#pindo_log_instance

Methods included from Pindoconfig::Mixin

#pindo_single_config

Methods included from Githelper

#add_branch, #add_tag, #add_tag_with_check, #clone_clang_repo, #clone_devclang_repo, #clone_pindo_common_config_repo, #clone_pindo_env_config_repo, #clong_buildconfig_repo, #get_repo_base_name, #getcode_to_dir, #git_addpush_repo, #git_latest_commit_id, #git_root_directory, #is_git_directory?, #local_branch_exists?, #local_tag_exists?, #prepare_gitenv, #process_need_add_files, #remote_branch_exists?, #remote_tag_exists?, #remove_branch, #remove_tag

Methods included from Executable

capture_command, #executable, execute_command, which, which!

Constructor Details

#initialize(argv) ⇒ Run

Returns a new instance of Run.



46
47
48
49
50
51
52
# File 'lib/pindo/command/web/run.rb', line 46

def initialize(argv)
    @args_port = argv.option('port', '8000').to_i  # 添加端口参数,默认8000
    @args_debug = argv.flag?('debug', false)  # 是否显示调试信息

    super
    @additional_args = argv.remainder!
end

Class Method Details

.optionsObject

命令的选项列表



37
38
39
40
41
42
43
44
# File 'lib/pindo/command/web/run.rb', line 37

def self.options
    [
        # 添加HTTP服务器端口选项
        ['--port',   '指定HTTP服务器的端口,默认为8000'],
        # 添加调试选项
        ['--debug',  '显示详细的调试信息']
    ].concat(super)
end

Instance Method Details

#get_local_ipObject

获取本机局域网IP地址



71
72
73
74
75
76
77
78
79
80
# File 'lib/pindo/command/web/run.rb', line 71

def get_local_ip
    ip = nil
    Socket.ip_address_list.each do |addr_info|
        if addr_info.ipv4? && !addr_info.ipv4_loopback?
            ip = addr_info.ip_address
            break
        end
    end
    return ip || 'localhost'
end

#runObject



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/pindo/command/web/run.rb', line 233

def run
    pindo_project_dir = Dir.pwd
    build_helper = Pindo::BuildHelper.share_instance
    project_type = build_helper.project_type(pindo_project_dir)

    webgl_res_dir = Dir.pwd
    case project_type
    when :unity
        webgl_res_dir = File.join(pindo_project_dir, "GoodPlatform/WebGL/build")
    end

    # 确保路径规范化
    webgl_res_dir = File.expand_path(webgl_res_dir)
    
    # 只在调试模式下显示这些信息
    UI.debug("WebGL资源目录: #{webgl_res_dir}", @args_debug)
    UI.debug("目录存在: #{File.directory?(webgl_res_dir)}", @args_debug)
    
    # 启动HTTP服务器而不是简单打开目录
    server = start_http_server(webgl_res_dir, @args_port)
    
    if server
        # 打开浏览器展示WebGL内容 - 使用根路径,会自动重定向到响应式预览
        system("open http://localhost:#{@args_port}/")
        
        # 捕获Ctrl+C信号来优雅地关闭服务器
        trap('INT') { server.shutdown }
        trap('TERM') { server.shutdown }
        
        # 启动服务器主循环
        UI.puts("服务器运行中,按Ctrl+C停止...")
        server.start
    else
        # 如果服务器启动失败,回退到简单打开目录
        UI.puts("无法启动HTTP服务器,将直接打开WebGL目录")
        system "open #{webgl_res_dir}"
    end
end

#start_http_server(webgl_dir, port) ⇒ Object

启动HTTP服务器



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/pindo/command/web/run.rb', line 83

def start_http_server(webgl_dir, port)
    begin
        # 确保目录存在
        unless File.directory?(webgl_dir)
            UI.puts("错误: WebGL目录不存在: #{webgl_dir}")
            return nil
        end

        # 检查index.html是否存在
        if !File.exist?(File.join(webgl_dir, "index.html"))
            UI.puts("警告: WebGL目录中未找到index.html文件")
        end

        # 创建自定义日志格式器,只记录错误
        custom_log = [
            [:error, WEBrick::AccessLog::COMMON_LOG_FORMAT],
        ]

        # 采用直接的方法配置服务器
        server = WEBrick::HTTPServer.new(
            :Port => port,
            :DocumentRoot => webgl_dir,
            :Logger => WEBrick::Log.new(nil, WEBrick::Log::ERROR),
            :AccessLog => @args_debug ? nil : [],
            :DoNotReverseLookup => true,
            :BindAddress => '0.0.0.0'  # 绑定到所有网络接口,使其在局域网可访问
        )

        # 挂载一个特殊的处理器专门处理原始的index.html
        server.mount_proc("/rawindex.html") { |req, res|
            index_path = File.join(webgl_dir, "index.html")
            if File.exist?(index_path)
                # 读取原始HTML内容
                original_html = File.read(index_path)
                
                # 添加base标签以修复相对路径问题
                if !original_html.include?('<base href=')
                    # 在<head>标签后插入base标签
                    modified_html = original_html.gsub(/<head>/, '<head><base href="./">')
                    res.body = modified_html
                else 
                    res.body = original_html
                end
                
                res.content_type = "text/html"
                res.status = 200
            else
                res.status = 404
                res.body = "WebGL index.html not found"
            end
        }
        
        # 设置根路径重定向处理器
        server.mount_proc("/") { |req, res|
            # 仅对根路径请求进行重定向
            if req.path == "/" || req.path == "/index.html"
                res.set_redirect(WEBrick::HTTPStatus::Found, "/responsive")
            else
                # 对于非根路径,使用普通的静态文件处理
                path = req.path
                file_path = File.join(webgl_dir, path[1..-1])
                
                if File.exist?(file_path) && !File.directory?(file_path)
                    # 确定内容类型
                    ext = File.extname(file_path)
                    content_type = case ext
                        when ".html" then "text/html"
                        when ".js" then "application/javascript"
                        when ".css" then "text/css"
                        when ".png" then "image/png"
                        when ".jpg", ".jpeg" then "image/jpeg"
                        when ".gif" then "image/gif"
                        when ".ico" then "image/x-icon"
                        when ".wasm" then "application/wasm"
                        when ".data" then "application/octet-stream"
                        when ".json" then "application/json"
                        else "application/octet-stream"
                    end
                    
                    # 设置Brotli压缩相关的响应头
                    if file_path.end_with?('.br')
                        res.header["Content-Encoding"] = "br"
                        file_content = File.binread(file_path)
                    else
                        file_content = File.read(file_path)
                    end
                    
                    res.content_type = content_type
                    res.body = file_content
                    res.status = 200
                else
                    res.status = 404
                    res.body = "File not found: #{path}"
                end
            end
        }
        
        # 挂载响应式预览页面处理器
        server.mount("/responsive", Pindo::WebServer::ResponsivePreviewHandler, webgl_dir, port, @args_debug)
        
        # 挂载Brotli处理器(后缀为.br的文件)
        paths_with_br = []
        Find.find(webgl_dir) do |path|
            if path.end_with?('.br') && File.file?(path)
                rel_path = path.sub(webgl_dir, '')
                paths_with_br << rel_path
            end
        end
        
        # 挂载每个.br文件
        paths_with_br.each do |br_path|
            server.mount(br_path, Pindo::WebServer::BrotliFileHandler, webgl_dir, @args_debug)
        end
        
        # 只在调试模式下显示详细信息
        if @args_debug
            UI.puts("找到.br文件: #{paths_with_br.join(', ')}")
            
            UI.puts("WebGL目录内容:")
            Dir.entries(webgl_dir).each do |entry|
                next if entry == "." || entry == ".."
                UI.puts("  - #{entry}")
                
                # 递归显示子目录中的文件(限制为一级)
                entry_path = File.join(webgl_dir, entry)
                if File.directory?(entry_path)
                    Dir.entries(entry_path).each do |subentry|
                        next if subentry == "." || subentry == ".."
                        UI.puts("    - #{entry}/#{subentry}")
                    end
                end
            end
        end
        
        # 启动服务器并返回
        local_ip = get_local_ip
        UI.puts("启动WebGL HTTP服务器,端口: #{port},目录: #{webgl_dir}")
        
        UI.puts("本地访问地址: http://localhost:#{port}/")
        UI.puts("局域网访问地址: http://#{local_ip}:#{port}/")
        UI.puts("原始WebGL地址: http://localhost:#{port}/index.html")
        
        return server
    rescue Exception => e
        UI.puts("启动HTTP服务器失败: #{e.message}")
        UI.debug(e.backtrace.join("\n"), @args_debug)
        return nil
    end
end

#validate!Object



54
55
56
# File 'lib/pindo/command/web/run.rb', line 54

def validate!
    super
end