Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit (moved from original repo)

  • Loading branch information...
commit d19470a459441a5fd8b1a3b4acb2e9b42c274798 0 parents
@lestrrat authored
3  .gitmodules
@@ -0,0 +1,3 @@
+[submodule "modules/core"]
+ path = modules/core
+ url = git@github.com:/lestrrat/Lyra-Core.git
16 Makefile.PL
@@ -0,0 +1,16 @@
+use inc::Module::Install;
+
+name 'Lyra-Server-Click';
+all_from 'lib/Lyra/Server/Click.pm';
+
+requires 'AnyEvent';
+requires 'Cwd';
+requires 'File::Basename';
+requires 'File::Spec';
+requires 'Moose';
+requires 'Twiggy';
+requires 'URI';
+requires 'namespace::autoclean';
+
+auto_set_repository;
+WriteAll;
12 bin/lyra_click_server
@@ -0,0 +1,12 @@
+#!/usr/bin/env perl
+use strict;
+BEGIN {
+ if (-d '.git') {
+ require blib;
+ blib->import;
+ }
+}
+use lib "lib";
+use App::Lyra::Click;
+
+App::Lyra::Click->new_with_options()->run();
55 lib/App/Lyra/Click.pm
@@ -0,0 +1,55 @@
+package App::Lyra::Click;
+use Moose;
+use Lyra::Server::Click;
+use Lyra::Log::Storage::File;
+use File::Spec;
+use namespace::autoclean;
+
+with 'Lyra::Trait::StandaloneServer';
+
+has '+psgi_server' => (
+ default => 'Twiggy'
+);
+
+has dsn => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+);
+
+has user => (
+ is => 'ro',
+ isa => 'Str',
+);
+
+has password => (
+ is => 'ro',
+ isa => 'Str',
+);
+
+sub build_app {
+ my $self = shift;
+
+ # XXX Make this configurable
+ my $storage = Lyra::Log::Storage::File->new(
+ prefix => File::Spec->catfile(File::Spec->tmpdir, 'click.CHANGEME')
+ );
+
+ my $dbh = AnyEvent::DBI->new(
+ $self->dsn,
+ $self->user,
+ $self->password,
+ exec_server => 1,
+ RaiseError => 1,
+ AutoCommit => 1,
+ );
+ Lyra::Server::Click->new(
+ dbh => $dbh,
+ log_storage => $storage,
+ )->psgi_app;
+}
+
+__PACKAGE__->meta->make_immutable();
+
+1;
+
65 lib/Lyra/Extlib.pm
@@ -0,0 +1,65 @@
+package Lyra::Extlib;
+use strict;
+use Cwd ();
+use File::Spec;
+use File::Basename ();
+our $BASE;
+
+sub find_base {
+ my $package = __PACKAGE__;
+ $package =~ s/::/\//g;
+ $package =~ s/$/\.pm/;
+
+ my $path = $INC{ $package };
+ my $base;
+
+ if ($ENV{HARNESS_ACTIVE}) {
+ # I'm at $HOME/blib/lib/Lyra
+ # (0) (1) (2) (3)
+ # that's 4 directories up
+ $base = File::Spec->catdir(
+ File::Basename::dirname($path),
+ File::Spec->updir,
+ File::Spec->updir,
+ File::Spec->updir,
+ );
+ } else {
+ # I'm at $HOME/lib/Lyra
+ # (0) (1) (2)
+ # that's 3 directories up
+ $base = File::Spec->catdir(
+ File::Basename::dirname($path),
+ File::Spec->updir,
+ File::Spec->updir,
+ );
+ }
+ return Cwd::realpath( $base );
+}
+
+sub extlib (&;$) {
+ local $BASE = @_ >= 2 ? pop : find_base();
+ $_[0]->();
+ unshift @INC, File::Spec->catfile($BASE, 'lib');
+}
+
+sub submodule (@) {
+ unshift @INC,
+ map { File::Spec->catdir( $BASE, 'modules', $_, 'lib' ) } @_;
+}
+
+sub locallib (@) {
+ my @paths = @_ ? @_ : (File::Spec->catdir( $BASE, 'extlib' ) );
+ require local::lib;
+ foreach my $path (@paths) {
+ local::lib->import( $path );
+ }
+}
+
+BEGIN {
+ extlib {
+ submodule 'core';
+ locallib;
+ };
+}
+
+1;
111 lib/Lyra/Server/Click.pm
@@ -0,0 +1,111 @@
+package Lyra::Server::Click;
+use Moose;
+use AnyEvent;
+use Lyra::Extlib;
+use URI;
+use namespace::autoclean;
+
+our $VERSION = '0.00001';
+
+with qw(
+ Lyra::Trait::Async::WithMemcached
+ Lyra::Trait::Async::WithDBI
+ Lyra::Trait::Async::PsgiApp
+);
+
+has ad_id_query_key => (
+ is => 'ro',
+ isa => 'Str',
+ default => 'ad',
+);
+
+has log_storage => (
+ is => 'ro',
+ handles => {
+ log_click => 'store',
+ },
+);
+
+sub process {
+ my ($self, $start_response, $env) = @_;
+
+ # Stuff that gets logged at the end goes here
+ my %log_info = (
+ remote_addr => $env->{REMOTE_ADDR},
+ query => $env->{QUERY_STRING},
+ );
+
+ # This is the CV that gets called at the end
+ my $cv = AE::cv {
+ my ($status, $header, $content) = $_[0]->recv;
+ respond_cb($start_response, $status, $header, $content);
+ if ($status eq 302) { # which is success for us
+ $self->log_click( \%log_info );
+ }
+ undef %log_info;
+ undef $status;
+ undef $header;
+ undef $content;
+ };
+
+ # check for some conditions
+ my ($status, @headers, $content);
+
+ if ($env->{REQUEST_METHOD} ne 'GET') {
+ $cv->send( 400 );
+ return;
+ }
+
+ # if we got here, then we're just going to redirect to the
+ # landing page.
+ my %query = URI->new('http://dummy/?' . ($env->{QUERY_STRING} || ''))->query_form;
+
+ my $ad_id = $query{ $self->ad_id_query_key };
+
+ $self->load_ad( $ad_id, $cv );
+}
+
+sub _load_ad_from_memd_cb {
+ my ($self, $final_cv, $ad_id, $ad) = @_;
+
+ if ($ad) {
+ $final_cv->send( 302, [ Location => $ad->[0] ] );
+ } else {
+ $self->load_ad_from_db( $final_cv, $ad_id );
+ }
+}
+
+sub _load_ad_from_db_cb {
+ my ($self, $final_cv, $ad_id, $rows) = @_;
+ if (! defined $rows) {
+ confess "PANIC: loading from DB returned undef";
+ }
+
+ if (@$rows > 0) {
+ $self->cache->set( $ad_id, $rows->[0], \&Lyra::_NOOP );
+
+ $final_cv->send( 302, [ Location => $rows->[0]->[0] ] );
+ } else {
+ $final_cv->send( 404 );
+ }
+}
+
+# Ad retrieval. Try memcached, if you failed, load from DB
+*load_ad = \&load_ad_from_memd;
+
+sub load_ad_from_memd {
+ my ($self, $ad_id, $final_cv) = @_;
+ $self->cache->get( $ad_id, sub { _load_ad_from_memd_cb( $self, $final_cv, $ad_id, @_ ) } );
+}
+
+sub load_ad_from_db {
+ my ($self, $final_cv, $ad_id) = @_;
+
+ $self->execsql(
+ "SELECT landing_uri FROM lyra_ads_master WHERE id = ?",
+ $ad_id,
+ sub { _load_ad_from_db_cb( $self, $final_cv, $ad_id, $_[1] ) }
+ );
+}
+
+1;
1  modules/core
@@ -0,0 +1 @@
+Subproject commit 4b0d5e581d526275e1b40846ed35a4a8798844a6
Please sign in to comment.
Something went wrong with that request. Please try again.