mirror of
				https://github.com/openresty/openresty.git
				synced 2024-10-13 00:29:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			309 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env perl
 | |
| 
 | |
| # Copyright (C) Yichun Zhang (agentzh)
 | |
| 
 | |
| # TODO: port this script into the nginx core for greater flexibility
 | |
| # and better performance.
 | |
| 
 | |
| use strict;
 | |
| use warnings;
 | |
| 
 | |
| use File::Spec ();
 | |
| use FindBin ();
 | |
| use Getopt::Std qw( getopts );
 | |
| use File::Temp qw( tempdir );
 | |
| use POSIX qw( WNOHANG );
 | |
| 
 | |
| my %opts;
 | |
| getopts("he:c:VI:", \%opts)
 | |
|     or usage(1);
 | |
| 
 | |
| if ($opts{h}) {
 | |
|     usage(0);
 | |
| }
 | |
| 
 | |
| my $nginx_path = File::Spec->catfile($FindBin::Bin, "..", "nginx", "sbin", "nginx");
 | |
| #warn $nginx_path;
 | |
| if (!-f $nginx_path) {
 | |
|     $nginx_path = "nginx";  # find in PATH
 | |
| }
 | |
| 
 | |
| if ($opts{V}) {
 | |
|     my $cmd = "$nginx_path -V";
 | |
|     exec $cmd or die "Failed to run command \"$cmd\": $!\n";
 | |
| }
 | |
| 
 | |
| my $lua_package_path_config = '';
 | |
| if ($opts{I}) {
 | |
|     my $dir = $opts{I};
 | |
|     if (!-d $dir) {
 | |
|         die "Search directory $dir is not found.\n";
 | |
|     }
 | |
|     $lua_package_path_config = <<_EOC_;
 | |
|     lua_package_path "$dir/?.lua;;";
 | |
|     lua_package_cpath "$dir/?.so;;";
 | |
| _EOC_
 | |
| }
 | |
| 
 | |
| my $luafile;
 | |
| if (!defined $opts{e}) {
 | |
|     $luafile = shift
 | |
|         or die qq{No Lua input file nor -e "" option specified.\n};
 | |
| }
 | |
| 
 | |
| if (@ARGV) {
 | |
|     die "unknown arguments: @ARGV\n";
 | |
| }
 | |
| 
 | |
| my $conns = $opts{c} || 64;
 | |
| 
 | |
| my @nameservers;
 | |
| 
 | |
| # try to read the nameservers used by the system resolver:
 | |
| if (open my $in, "/etc/resolv.conf") {
 | |
|     while (<$in>) {
 | |
|         if (/^\s*nameserver\s+(\d+(?:\.\d+){3})(?:\s+|$)/) {
 | |
|             push @nameservers, $1;
 | |
|             if (@nameservers > 10) {
 | |
|                 last;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     close $in;
 | |
| }
 | |
| 
 | |
| if (!@nameservers) {
 | |
|     # default to Google's open DNS servers
 | |
|     push @nameservers, "8.8.8.8", "8.8.4.4";
 | |
| }
 | |
| 
 | |
| #warn "@nameservers\n";
 | |
| 
 | |
| my $prefix_dir = tempdir(CLEANUP => 1);
 | |
| #warn "prefix dir: $prefix_dir\n";
 | |
| 
 | |
| my $logs_dir = File::Spec->catfile($prefix_dir, "logs");
 | |
| mkdir $logs_dir or die "failed to mkdir $logs_dir: $!";
 | |
| 
 | |
| my $conf_dir = File::Spec->catfile($prefix_dir, "conf");
 | |
| mkdir $conf_dir or die "failed to mkdir $conf_dir: $!";
 | |
| 
 | |
| my $chunk_name;
 | |
| if (defined $opts{e}) {
 | |
|     $luafile = File::Spec->catfile($conf_dir, "a.lua");
 | |
|     open my $out, ">$luafile"
 | |
|         or die "Cannot open $luafile for writing: $!\n";
 | |
|     print $out $opts{e};
 | |
|     close $out;
 | |
|     $chunk_name = "=(command line -e)";
 | |
| 
 | |
| } else {
 | |
|     $chunk_name = "\@$luafile";
 | |
| }
 | |
| 
 | |
| my $loader = <<_EOC_;
 | |
|             local gen
 | |
|             do
 | |
|                 local fname = "$luafile"
 | |
|                 local f = assert(io.open(fname, "r"))
 | |
|                 local chunk = f:read("*a")
 | |
|                 gen = assert(loadstring(chunk, "$chunk_name"))
 | |
|             end
 | |
| _EOC_
 | |
| 
 | |
| my $env_list = '';
 | |
| for my $var (sort keys %ENV) {
 | |
|     #warn $var;
 | |
|     $env_list .= "env $var;\n";
 | |
| }
 | |
| 
 | |
| my $conf_file = File::Spec->catfile($conf_dir, "nginx.conf");
 | |
| open my $out, ">$conf_file"
 | |
|     or die "Cannot open $conf_file for writing: $!\n";
 | |
| 
 | |
| print $out <<_EOC_;
 | |
| daemon off;
 | |
| master_process off;
 | |
| worker_processes 1;
 | |
| 
 | |
| $env_list
 | |
| 
 | |
| error_log /dev/stderr warn;
 | |
| #error_log /dev/stderr debug;
 | |
| 
 | |
| events {
 | |
|     worker_connections $conns;
 | |
| }
 | |
| 
 | |
| http {
 | |
|     access_log off;
 | |
|     lua_socket_log_errors off;
 | |
|     resolver @nameservers;
 | |
| $lua_package_path_config
 | |
|     init_by_lua '
 | |
|         local stdout = io.stdout
 | |
|         local ngx_null = ngx.null
 | |
|         local maxn = table.maxn
 | |
|         local unpack = unpack
 | |
|         local concat = table.concat
 | |
| 
 | |
|         local expand_table
 | |
|         function expand_table(src, inplace)
 | |
|             local n = maxn(src)
 | |
|             local dst = inplace and src or {}
 | |
|             for i = 1, n do
 | |
|                 local arg = src[i]
 | |
|                 local typ = type(arg)
 | |
|                 if arg == nil then
 | |
|                     dst[i] = "nil"
 | |
| 
 | |
|                 elseif typ == "boolean" then
 | |
|                     if arg then
 | |
|                         dst[i] = "true"
 | |
|                     else
 | |
|                         dst[i] = "false"
 | |
|                     end
 | |
| 
 | |
|                 elseif arg == ngx_null then
 | |
|                     dst[i] = "null"
 | |
| 
 | |
|                 elseif typ == "table" then
 | |
|                     dst[i] = expand_table(arg, false)
 | |
| 
 | |
|                 elseif typ ~= "string" then
 | |
|                     dst[i] = tostring(arg)
 | |
| 
 | |
|                 else
 | |
|                     dst[i] = arg
 | |
|                 end
 | |
|             end
 | |
|             return concat(dst)
 | |
|         end
 | |
| 
 | |
|         local function output(...)
 | |
|             local args = {...}
 | |
| 
 | |
|             return stdout:write(expand_table(args, true))
 | |
|         end
 | |
| 
 | |
|         ngx.print = output
 | |
|         ngx.say = function (...)
 | |
|                 local ok, err = output(...)
 | |
|                 if ok then
 | |
|                     return output("\\\\n")
 | |
|                 end
 | |
|                 return ok, err
 | |
|             end
 | |
|         print = ngx.say
 | |
| 
 | |
|         ngx.flush = function (...) return stdout:flush() end
 | |
|         -- we cannot close stdout here due to a bug in Lua:
 | |
|         ngx.eof = function (...) return true end
 | |
|         ngx.exit = os.exit
 | |
|     ';
 | |
| 
 | |
|     init_worker_by_lua '
 | |
|         local exit = os.exit
 | |
|         local stderr = io.stderr
 | |
| 
 | |
|         local function handle_err(err)
 | |
|             if err then
 | |
|                 err = string.gsub(err, "^init_worker_by_lua:%d+: ", "")
 | |
|                 stderr:write(err, "\\\\n")
 | |
|             end
 | |
|             return exit(1)
 | |
|         end
 | |
| 
 | |
|         local ok, err = pcall(function ()
 | |
|             if not ngx.config
 | |
|                or not ngx.config.ngx_lua_version
 | |
|                or ngx.config.ngx_lua_version < 9011
 | |
|             then
 | |
|                 error("at least ngx_lua 0.9.12 is required")
 | |
|             end
 | |
| 
 | |
| $loader
 | |
|             -- print("calling timer.at...")
 | |
|             local ok, err = ngx.timer.at(0, function ()
 | |
|                 -- io.stderr:write("timer firing")
 | |
|                 local ok, err = pcall(gen)
 | |
|                 if not ok then
 | |
|                     return handle_err(err)
 | |
|                 end
 | |
|                 local rc = err
 | |
|                 if rc and type(rc) ~= "number" then
 | |
|                     return handle_err("bad return value of type " .. type(rc))
 | |
|                 end
 | |
|                 return exit(rc)
 | |
|             end)
 | |
|             if not ok then
 | |
|                 return handle_err(err)
 | |
|             end
 | |
|             -- print("timer created")
 | |
|         end)
 | |
| 
 | |
|         if not ok then
 | |
|             return handle_err(err)
 | |
|         end
 | |
|     ';
 | |
| }
 | |
| _EOC_
 | |
| 
 | |
| close $out;
 | |
| 
 | |
| my $cmd = "$nginx_path -p $prefix_dir/";
 | |
| 
 | |
| my $child_pid;
 | |
| 
 | |
| sub sigint {
 | |
|     $SIG{INT} = \&sigint;
 | |
|     if ($child_pid) {
 | |
|         kill INT => $child_pid;
 | |
|     }
 | |
| }
 | |
| $SIG{INT} = \&sigint;
 | |
| 
 | |
| my $pid = fork();
 | |
| 
 | |
| if (!defined $pid) {
 | |
|     die "fork() failed: $!\n";
 | |
| }
 | |
| 
 | |
| if ($pid == 0) {  # child process
 | |
|     #warn "exec $cmd...";
 | |
|     exec $cmd or die "Failed to run command \"$cmd\": $!\n";
 | |
| 
 | |
| } else {
 | |
|     $child_pid = $pid;
 | |
|     waitpid($child_pid, 0);
 | |
|     my $rc = 0;
 | |
|     if (defined $?) {
 | |
|         $rc = ($? >> 8);
 | |
|     }
 | |
|     exit($rc);
 | |
| }
 | |
| 
 | |
| sub usage {
 | |
|     my $rc = shift;
 | |
|     my $msg = <<_EOC_;
 | |
| resty [-I dir] [-h] [-c num] [-e prog] [-V] [lua-file]
 | |
| 
 | |
| Options:
 | |
|     -c num      set maximal connection count (default: 64).
 | |
|     -e prog     run the inlined Lua code in "prog".
 | |
|     -h          print this help.
 | |
|     -I dir      Add dir to the search paths for Lua libraries.
 | |
|     -V          print the underlying nginx version and configurations.
 | |
| 
 | |
| For bug reporting instructions, please see:
 | |
| <http://openresty.org/#Community>
 | |
| _EOC_
 | |
|     if ($rc == 0) {
 | |
|         print $msg;
 | |
|         exit(0);
 | |
|     }
 | |
| 
 | |
|     warn $msg;
 | |
|     exit($rc);
 | |
| }
 |