#!/usr/bin/env perl use strict; use warnings; use utf8; #use Smart::Comments; use FindBin; use lib "$FindBin::Bin/../lib"; use OpenResty::Dispatcher; use OpenResty::Limits; use Getopt::Std; use Getopt::Long; use Time::HiRes; use constant { MAX_STATS_CACHE_SIZE => 500, }; my $cmd; my $arg = $ARGV[0]; if ($arg && $arg !~ /^-/) { $cmd = lc(shift); } my %opts = ( port => 8000, ); if (@ARGV) { GetOptions('port=i' => \$opts{port}, 'file=s' => \$opts{conf_file}, 'root-path=s' => \$opts{root_path}, 'wrap-legacy' => \$opts{wrap_legacy} ); } $cmd = $ENV{OPENRESTY_COMMAND} if !$cmd; if ($ENV{REQUEST_URI}) { if (!$cmd) { $cmd = 'fastcgi'; $ENV{OPENRESTY_COMMAND} = $cmd; } } $cmd ||= ''; $opts{context} = $cmd; eval { OpenResty::Dispatcher->init(\%opts); }; warn $@ if $@; our @StatsCache; our $StatsDir; # XXX this part is terribly hacky... sub do_stats { my ($begin_time) = @_; if ($StatsDir ||= $OpenResty::Dispatcher::StatsLog) { my $diff = Time::HiRes::time - $begin_time; my $now = localtime; my ($sec, $min, $hour, $mday, $mon, $year) = localtime; $year += 1900; $mon += 1; #my $now = "$year-$mon-$mday $hour:$min:$sec"; #my ($sec, $min, $hour, $mday, $mon, $year) = localtime; #$year += 1900; $mon += 1; my $client = $ENV{REMOTE_ADDR}; my $meth = $ENV{REQUEST_METHOD}; my $url = $ENV{REQUEST_URI}; ### %ENV push @StatsCache, sprintf("[%04d-%02d-%02d %02d:%02d:%02d] %.03f %s \"%s %s\"\n", $year, $mon, $mday, $hour, $min, $sec, $diff, $client, $meth, $url); if (@StatsCache >= MAX_STATS_CACHE_SIZE) { write_log(); @StatsCache = (); } } } sub write_log { #my $stats_dir = shift; return unless $StatsDir; my ($sec, $min, $hour, $mday, $mon, $year) = localtime; $year += 1900; $mon += 1; my $stats_file = sprintf("$StatsDir/%04d-%02d-%02d.log", $year, $mon, $mday); open my $log, ">>$stats_file" or die "Can't open stats_log file $stats_file for writing: $!\n"; print $log @StatsCache; close $log; } END { write_log() } if ($cmd eq 'fastcgi') { require OpenResty::FastCGI; while (my $cgi = new OpenResty::FastCGI) { my $begin_time; if (defined $OpenResty::Dispatcher::StatsLog) { $begin_time = Time::HiRes::time; } eval { OpenResty::Dispatcher->process_request($cgi); }; if ($@) { warn $@; print "HTTP/1.1 200 OK\n"; # XXX don't show $@ to the end user... print qq[{"success":0,"error":"$@"}\n]; } eval { do_stats($begin_time); }; if ($@) { warn $@; } } exit; } elsif ($cmd eq 'cgi') { require CGI::Simple; my $cgi = CGI::Simple->new; OpenResty::Dispatcher->process_request($cgi); exit; } elsif ($cmd eq 'start') { require OpenResty::Server; my $server = OpenResty::Server->new; $server->port($opts{port}); $server->run; exit; } elsif ($cmd eq 'fastcgi2') { # with PL/Proxy support } my $error = $OpenResty::Dispatcher::InitFatal; if ($error) { die $error; } my $backend = $OpenResty::Backend; if ($cmd eq 'adduser') { my $user = shift or die "No user specified.\n"; if (!$opts{'wrap_legacy'} && $backend->has_user($user)) { die "User $user already exists.\n"; } eval "use Term::ReadKey;"; if ($@) { die $@; } #local $| = 1; my $password; print "Enter the password for the Admin role: "; ReadMode(2); my $key; while (not defined ($key = ReadLine(0))) { } ReadMode(0); $key =~ s/\n//s; print "\n"; my $saved_key = $key; #warn "Password: $password\n"; OpenResty::check_password($saved_key); print "Re Enter the password for the Admin role: "; ReadMode(2); while (not defined ($key = ReadLine(0))) { } ReadMode(0); $key =~ s/\n//s; print "\n"; if ($key ne $saved_key) { die "2 passwords don't match.\n"; } $password = $key; $OpenResty::Backend->add_user($user, $password, $opts{'wrap_legacy'}); my $machine = $OpenResty::Backend->has_user($user); if ($machine) { warn "User $user created on node $machine.\n"; } } elsif ($cmd eq 'deluser') { my $user = shift or die "No user specified.\n"; if ($backend->has_user($user)) { $OpenResty::Backend->drop_user($user); } else { die "User $user does not exist.\n"; } } elsif ($cmd eq 'upgrade') { my $user = shift; require OpenResty::Script::Upgrade; OpenResty::Script::Upgrade->go($backend, $user); } elsif ($cmd eq '' or $cmd eq 'shell') { require OpenResty::Shell; my $shell = OpenResty::Shell->new($backend); $shell->run; } elsif ($cmd eq 'updatekey') { my $secret=shift||$backend->random_secret(); die "Invalid captcha secret, must be exactly 16 bytes long and contains only characters in [0-9a-zA-Z].\n" unless $backend->is_valid_captcha_secret($secret); # the secret format check is done before the updating occurs unless($backend->update_captcha_secret($secret)) { die "Failed to update captcha secret.\n" } else { print "Captcha secret updated.\n"; } } elsif ($cmd eq 'compile') { require OpenResty::Script::Compile; OpenResty::Script::Compile->go(\@ARGV); } else { die "Unknown command: $cmd\n"; } __END__ =head1 NAME openresty - Command-line frontend utility for the OpenResty server =head1 SYNOPSIS # run the OpenResty server via the standalone HTTP server # provided by HTTP::Server::Simple: $ bin/openresty start # run the OpenResty server in plain old CGI mode: $ bin/openresty cgi # or equivalently: $ OPENRESTY_COMMAND=cgi bin/openresty # run the OpenResty server in FastCGI mode: $ bin/openresty fastcgi # or equivalently: $ OPENRESTY_COMMAND=fastcgi bin/openresty # enter the OpenResty shell: $ bin/openresty # add a new OpenResty account named foo $ bin/openresty adduser foo # remove an existing OpenResty account named bar $ bin/openresty deluser bar # upgrade the metamodel in the DB to the latest version $ bin/openresty upgrade # upgrade the metamodel of (only) the OpenResty account (foo) specified: $ bin/openresty upgrade foo =head1 DESCRIPTION This is the command-line frontend for the OpenResty server. The C script can server as a =over =item * OpenResty account adminstration tool (i.e., creating accounts, removing accounts, listing accounts, and etc.). =item * OpenResty server entry point (via CGI, FastCGI, or standalone server). =item * A psql-like shell tools for administrating the backend databases (either Pg or PgFarm). =item * A metamodel upgrading tool. (See L for more details about the metamodel.) =back =head1 AUTHOR Agent Zhang (agentzh) C<< >> =head1 License and Copyright Copyright (c) 2007, 2008 by Yahoo! China EEEE Works, Alibaba Inc. This module is free software; you can redistribute it and/or modify it under the Artistic License 2.0. A copy of this license can be obtained from L =head1 SEE ALSO L, L, L, L, L, L.