Files
gtav-src/tools_ng/lib/util/Assetbuilder/source/builder/shell/web.rb
T
2025-09-29 00:52:08 +02:00

248 lines
7.7 KiB
Ruby
Executable File

#
# File:: web.rb
# Description:: Web shell
#
# Author:: David Muir <david.muir@rockstarnorth.com>
# Date:: 28 February 2009
#
#----------------------------------------------------------------------------
# Uses
#----------------------------------------------------------------------------
require 'builder/shell/command'
require 'builder/shell/shell'
require 'os/path'
require 'erb'
require 'webrick'
require 'webrick/httpservlet/erbhandler.rb'
#----------------------------------------------------------------------------
# Implementation
#----------------------------------------------------------------------------
module Pipeline
module Builder
module Shell
#
# == Description
# Custom HTTP request/response class so we can spit out ERB pages and
# process POST forms to enqueue commands onto the server.
#
# It is expected that HTML form submit buttons are called the name of
# the command to execute and the value set to any parameters to be sent
# to that command.
#
# === References
# http://microjet.ath.cx/webrickguide/html/
# c:\ruby\lib\ruby\1.8\webrick\httpservlet\erbhandler.rb
#
# === Example Usage
# WEBrick::HTTPServlet::FileHandler.add_handler( 'rhtml', WebShellServlet )
#
module WebShellServlet
#
# Respond to HTTP GET requests. We steal the ERBHandler's do_GET
# method as we want to use ERB templates for ease.
#
def do_GET( req, resp )
unless defined?( ERB )
@logger.warn( "#{self.class}: ERB not defined." )
throw HTTPStatus::Forbidden, "WebShellServlet cannot work."
end
begin
filename = OS::Path::combine( Dir::pwd, req.path )
data = nil
if ( File::exists?( filename ) && File::file?( filename ) ) then
data = File::open( filename, 'r' ) do |io| io.read; end
else
# Default to @web_page
filename = @web_page
data = File::open( @web_page, 'r' ) do |io| io.read; end
end
# Process everything with ERB
resp.body = evaluate( ERB.new( data ), req, resp )
resp['Content-Type'] = WEBrick::HTTPUtils::mime_type( filename, @server.config[:MimeTypes] )
rescue StandardError => ex
puts "Ex: #{ex.message}"
ex.backtrace.each do |m| puts m; end
throw
rescue Exception => ex
@logger.error( ex )
throw HTTPStatus::InternalServerError, ex.message
end
end
#
# Respond to HTTP POST requests. We steal the ERBHandler's do_GET
# method as we want to use ERB templates for ease.
#
# We differ from the GET request processing by processing form
# data.
#
def do_POST( req, resp )
unless defined?( ERB )
@logger.warn( "#{self.class}: ERB not defined." )
throw HTTPStatus::Forbidden, "WebShellServlet cannot work."
end
puts "POST body: #{req.body}"
cmd = CommandInst::from_POST( req.body, @@commands )
enqueue_command( cmd, WebShell::HOST, WebShell::USER )
begin
filename = OS::Path::combine( Dir::pwd, req.path )
data = nil
if ( File::exists?( filename ) && File::file?( filename ) ) then
data = File::open( filename, 'r' ) do |io| io.read; end
else
# Default to @web_page
filename = @web_page
data = File::open( @web_page, 'r' ) do |io| io.read; end
end
# Process everything with ERB
resp.body = evaluate( ERB.new( data ), req, resp )
resp['Content-Type'] = WEBrick::HTTPUtils::mime_type( filename, @server.config[:MimeTypes] )
rescue StandardError => ex
puts "Ex: #{ex.message}"
ex.backtrace.each do |m| puts m; end
throw
rescue Exception => ex
@logger.error( ex )
throw HTTPStatus::InternalServerError, ex.message
end
end
#--------------------------------------------------------------------
# Class Methods
#--------------------------------------------------------------------
#
# Override self.get_instance to reload this file for each request.
# This saves us restarting the server/builder during testing.
#
def WebShellServlet::get_instance( config, *options )
load( __FILE__ )
WebShellServlet.new( config, *options )
end
#
# To parse POST String objects into CommandInst objects to enqueue
# we need to validate against an Array of Command objects. We store
# that here.
#
def WebShellServlet::set_commands( commands )
throw ArgumentError.new( "Invalid Hash of valid commands (#{commands.class})." ) \
unless ( commands.is_a?( Hash ) )
@@commands = commands
end
#--------------------------------------------------------------------
# Private Methods
#--------------------------------------------------------------------
private
def evaluate( erb, servlet_request, servlet_response )
Module.new.module_eval do
meta_vars = servlet_request.meta_vars
query = servlet_request.query
erb.result( binding )
end
end
end
#
# == Description
# Web implementation of the Builder Shell. This shell creates an
# internal Webrick HTTP server and allows users to send commands to
# the builder application.
#
# === Example Usage
#
# commands = [
# Command.new( 'sync', Command::NO_SHORTCUTS, 'Sync special directory.', [ Param.new( 'dir', String ) ], sync_proc ),
# Command.new( 'enable', [ 'e' ], 'Enable internal feature.', [ Param.new( 'flag', String ) ], enable_proc ),
# Command.new( 'disable', [ 'd' ], 'Disable internal feature.', [ Param.new( 'flag', String ) ], disable_proc ),
# Command.new( 'status', [ 's' ], 'Display status information.', Param::NONE, status_proc )
# ]
# shell = Console.new( commands )
# server = WebShell.new( commands )
# ...
# server.start( )
# # Start up our interactive shell in calling thread.
# shell.start( )
#
class WebShell < ShellBase
include WebShellServlet
DEFAULT_WEB_PORT = 81
HOST = ENV['COMPUTERNAME']
USER = ENV['USERNAME']
attr_reader :active
attr_reader :web_port
attr_reader :web_page
def initialize( commands,
web_port = DEFAULT_WEB_PORT,
web_page = './index.rhtml',
server = '127.0.0.1',
port = CommandQueue::DEFAULT_PORT )
super( commands, server, port )
@web_port = web_port
@web_page = File::expand_path( web_page )
@active = false
WebShellServlet::set_commands( @commands )
end
#
# Start the HTTP server and web UI so we can display status
# information.
#
def start( &block )
@active = true
mime_file = OS::Path::combine( OS::Path::get_directory( __FILE__ ), 'mime.types' )
@mime_types = WEBrick::HTTPUtils::load_mime_types( mime_file )
@mime_types.store( 'rhtml', 'text/html' )
Thread.new() do
Thread.current[:name] = THREAD_NAME
begin
# Start Webrick HTTP Server
# WEBrick::HTTPServlet::FileHandler.add_handler( 'rhtml', WebShellServlet )
@server = WEBrick::HTTPServer.new(
:Port => @web_port,
:DocumentRoot => @web_page,
:MimeTypes => @mime_types
)
@server.mount_proc( '/' ) do |req, resp|
case req.request_method
when 'GET'
do_GET( req, resp )
when 'POST'
do_POST( req, resp )
end
end
trap( 'INT' ) do @server.shutdown() end
@server.start( )
puts "WEBrick started."
rescue Exception => ex
puts "WebShell Exception: #{ex.message}"
ex.backtrace.each do |msg| puts msg; end
end
end
end
#--------------------------------------------------------------------
# Private
#--------------------------------------------------------------------
private
THREAD_NAME = '__BuilderFramework_WebShell'
end
end # Shell module
end # Builder module
end # Pipeline module
# web.rb