X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=angular-server.pl;h=ba1cc101f376a7688152f3ee31bace5537210fb4;hb=0e09fa1776827477c55a7716826555ff51e67848;hp=62c2651ee534407e2a553a5a13c48be1be860c87;hpb=c15679f515296efdd50e57430638c22532afd692;p=angular-drzb diff --git a/angular-server.pl b/angular-server.pl index 62c2651..ba1cc10 100755 --- a/angular-server.pl +++ b/angular-server.pl @@ -1,19 +1,22 @@ #!/usr/bin/env perl -use lib 'common/mojo/lib'; - use Mojolicious::Lite; use Data::Dump qw(dump); use Time::HiRes; use Clone qw(clone); use Mojo::UserAgent; +our $VERSION = `git describe`; +chomp $VERSION; + sub new_uuid { Time::HiRes::time * 100000 } -push @{app->static->paths}, 'app'; # default angular-seed app directory +#push @{app->static->paths}, 'app'; # default angular-seed app directory my $couchdb = $ENV{COUCHDB} || 'http://localhost:5984'; +my $couchdb_database = 'drzb2013v2'; +my $couchdb_view = "http://10.60.0.92:5984/_utils/document.html?$couchdb_database"; my $client = Mojo::UserAgent->new; sub _couchdb_put { @@ -32,7 +35,7 @@ sub _couchdb_put { sub _couchdb_get { my ( $url ) = @_; my $return = $client->get( "$couchdb/$url" )->res->json; - warn "# _couchdb_get $url = ",dump($return); +# warn "# _couchdb_get $url = ",dump($return); return $return; } @@ -44,15 +47,71 @@ sub _render_jsonp { my ( $self, $json ) = @_; #warn "## _render_json ",dump($json); my $data = $self->render( json => $json, partial => 1 ); -warn "## _render_json $data"; +#warn "## _render_json $data"; if ( my $callback = $self->param('callback') ) { $data = "$callback($data)"; } $self->render( data => $data, format => 'js' ); } -#get '/' => 'index'; +get '/' => sub { + my $self = shift; + $self->render_text("..."); +}; + +# define languages + +helper locale => sub { + my $self = shift; + my %locale = @_; + my $lang = $self->stash('lang'); + $lang =~ s/-dev$//; + return $locale{ $lang } || "MISSING $lang $_[1]"; +}; + +helper ip => sub { + my $self = shift; + return + $self->req->headers->header('X-Forwarded-For') + || $self->req->headers->header('X-Real-IP') + || $self->tx->{remote_address} + ; +}; + +get '/js/services.js' => sub { + my $self = shift; + $self->stash( VERSION => $VERSION ); + $self->stash( couchdb_database => $couchdb_database ); + $self->render( 'js/services', format => 'js' ); +}; + +# short public URLs +get '/hr' => sub { shift->redirect_to('/lang/hr/drzb2013') }; +get '/en' => sub { shift->redirect_to('/lang/en/drzb2013') }; + +get '/lang/:lang/:template' => sub { + my $self = shift; + $self->render( $self->stash('template') , lang => $self->stash('lang') ); +}; + +get '/lang/:lang/partials/:template' => sub { + my $self = shift; + $self->stash( couchdb_view => $couchdb_view ); + $self->render( 'partials/' . $self->stash('template') , lang => $self->stash('lang') ); +}; + +get '/lang/:lang/.template' => sub { + my $self = shift; + $self->render( $self->stash('template') , lang => $self->stash('lang') ); +}; + +get '/lang/:lang/template/*template' => sub { # angular-ui templates + my $self = shift; + my $path = '/lib/angular-ui/bootstrap/template/' . $self->stash('template'); + warn "# render_static $path"; + $self->render_static( $path ); +}; get '/data/' => sub { my $self = shift; @@ -103,7 +162,7 @@ get '/data/:database/:entity' => sub { $endkey++; my $counts = _couchdb_get qq|/$database/_all_docs?startkey="$entity";endkey="$endkey";include_docs=true|; - warn "# counts ",dump($counts); +# warn "# counts ",dump($counts); _render_jsonp( $self, [ map { $_->{doc} } @{ $counts->{rows} } ] ) }; @@ -123,8 +182,21 @@ any [ 'post' ] => '/data/:database/:entity' => sub { my $database = $self->param('database'); my $entity = $self->param('entity'); my $json = $self->req->json; - my $id = $1 if $json->{'_id'} =~ m/^\Q$entity\E\.(.+)$/; - $id ||= new_uuid; + my $id; + if ( exists $json->{'id'} ) { # @id in resource + $id = $json->{'id'}; + warn "EXISTING $id\n"; + } else { + $id = $json->{'id'} = new_uuid; + $json->{entity} = $entity; + warn "NEW $id\n"; + } + + $json->{x_audit} = { + t => Time::HiRes::time, + ip => $self->ip(), + }; + warn "## $database $entity $id body ",dump($self->req->body, $json); my $new = _couchdb_put "/$database/$entity.$id" => $json; @@ -144,86 +216,95 @@ any [ 'post' ] => '/data/:database/:entity' => sub { # CouchDB proxy for _design _view +our $view_cache; + get '/:database/_design/:design/_view/:view' => sub { my $self = shift; + my $format = $self->param('format'); my $url = join('/', $self->param('database'),'_design',$self->param('design'),'_view',$self->param('view') ); - my $param = $self->req->url->query->clone->remove('callback')->to_string; - $url .= '?' . $param if $param; + if ( my $param = $self->req->url->query->clone->remove('callback')->remove('format')->to_string ) { + $url .= '?' . $param + } + + if ( exists $view_cache->{$url}->{time} ) { + if ( time() - $view_cache->{$url}->{time} < 60 ) { + warn "HIT CouchDB cache $url"; + $view_cache->{$url}->{hit}++; + return _render_jsonp( $self, $view_cache->{$url}->{json} ); + } else { + warn "REFRESH CouchDB cache $url"; + $view_cache->{$url}->{refresh}++; + } + } else { + $view_cache->{$url}->{miss}++; + } warn "CouchDB proxy $url"; - _render_jsonp( $self, _couchdb_get($url)); -}; + my $json = _couchdb_get($url); -# static JSON files from public/json/database/entity/json + if ( exists $json->{error} ) { + warn "creating CouchDB view because of ", dump($json); + my $url = "/" . $self->param('database') . "/_design/registration"; + _couchdb_put $url, { + _id => '_design/registration', + language => 'javascript', + views => { + organizations => { + map => q| function(doc) { +if ( doc.user.organization != '' ) { + if ( doc.user.organization ) + emit(doc.user.organization, 1); + if ( doc.user.persons ) { + doc.user.persons.forEach( function(person) { + if ( person.organization ) + emit(person.organization, 1); + }); + } +} + }q|, + reduce => q| function(keys,values,rereduce) { return sum(values); } |, + } + } + }; + $json = _couchdb_get($url) + || die "give up!"; + } + + if ( $format eq 'key_array' ) { # array of keys sorted by value + $json->{rows} = [ map { $_->{key} } sort { $b->{value} <=> $a->{value} } @{ $json->{rows} } ]; + } + + $view_cache->{$url}->{time} = time(); + $view_cache->{$url}->{json} = $json; -get '/json' => sub { - _render_jsonp( shift, [ map { s{public/json/}{}; $_ } glob 'public/json/*' ] ); + warn "# view_cache ",dump($view_cache); + + _render_jsonp( $self, $json ); }; -get '/json/:database' => sub { +# http://showmetheco.de/articles/2010/10/adding-etag-caching-to-your-mojolicious-app.html + +hook after_dispatch => sub { my $self = shift; - my $database = $self->param('database'); - my $status = { - document_counts => 0, - name => $database, - }; + return unless $self->req->method eq 'GET'; - foreach my $path ( glob "public/json/$database/*" ) { - my @entities = glob "$path/*"; - $path =~ s{public/json/$database/}{}; - $status->{entities}->{$path} = scalar @entities; - $status->{document_counts}++; - } + my $body = $self->res->body; + return unless defined $body; - _render_jsonp( $self, $status ); -}; + return if $self->res->headers->header('ETag'); -get '/json/:database/:entity' => sub { - my $self = shift; + my $our_etag = Mojo::ByteStream->new($body . $VERSION)->md5_sum; + $self->res->headers->header('ETag' => $our_etag); - my $database = $self->param('database'); - my $entity = $self->param('entity'); + my $browser_etag = $self->req->headers->header('If-None-Match'); + return unless $browser_etag && $browser_etag eq $our_etag; - my $path = "public/json/$database/$entity"; - die "$path: $!" unless -d $path; - - my $docs; - foreach my $path ( sort glob "$path/*" ) { - open(my $fh, '<', $path) || die $!; - local $/ = undef; - my $str = <$fh>; - warn "# $path $str"; - my $data = Mojo::JSON->new->decode( $str ); - $data->{_key} = $1 if $path =~ m{/([^/]+$)}; - push @$docs, $data; - } + $self->app->log->debug("HTTP cache hit " . $self->req->url->to_string . " $our_etag" ); - _render_jsonp( $self, $docs ) + $self->res->code(304); + $self->res->body(''); }; -get '/_utils/script/(*url)' => sub { $_[0]->proxy_to( "$couchdb/_utils/script/" . $_[0]->param('url') , with_query_params => 1 ) }; app->start; -__DATA__ - -@@ index.html.ep -% layout 'funky'; -Yea baby! - -@@ layouts/funky.html.ep - - Funky! - <%== content %> - - -@@ layouts/angular.html.ep - - - - -% my $ANGULAR_JS = $ENV{ANGULAR_JS} || ( -e 'public/angular/build/angular.js' ? '/angular/build/angular.js' : '/angular/src/angular-bootstrap.js' ); - - - <%== content %> - +