human/
softwareengineer/
programmer/
hacker lee carmichael software engineer consulting programmer Perl Perl5 Javascript JavaScript PHP C web application developer cakephp

Blog

My blog is where I keep my notes. Most of the time updates will happen in bursts of activity. All links go offsite to blog.leecarmichael.com at Blogger since Google has a very good service.

Altering TT's INCLUDE_PATH in Dancer with Custom View

16:27:00 28-Mar-2013

Altering Template Toolkit's INCLUDE_PATH in Dancer

This just came up on Dancer's mailing list and I've been sitting on this code (and post) for a few months since the project I was working on didn't need it.

Basically Dancer's Template Toolkit view requires you completely alter it or use the default setting. This is pain if you just want to add to it but not have to manage all the changes.

I created a new TT view class, to get inside the TT init and add to the INCLUDE_PATH instead of replace it. The code was a bit involved and I extended it a bit by adding a customization flag in each environment (if needed).

On to the code

Here is the code and config that i used to do this

Disclaimer

I don't recall all the other issues that i ran into while doing this. It was over 6 months ago but post questions if you have them

__END__

Dancer + Nginx + FastCGI

08:40:00 25-Jan-2013

Bring together the parts

I was able to find complete documentation on running dancer with nginx using FastCGI. In the dancer deployment it discusses using Apache and fastcgi or nginx with proxy. Often, using nginx as proxy to starman(or some other plack webserver) is probably the right thing. But sometimes using fastcgi is good idea too :) I'm running some benchmarks but it seems like memory usage is a bit smaller with FCGI but I still need to do more digging on this.

Make it so

Lets get all the parts install and then configure them

Install the Parts

Note: These parts will be very dependent on your system. I'm assuming a debian/ubuntu system below.

First you need to have nginx and dancer installed. For nginx i would recommend doing something like:

apt-get install nginx

or building and install from source. 

Next, install need Perl modules:

cpanm + Dancer's Makefile.PL

I like to install using Dancer's app generated Makefile.PL along with cpanm to manage Perl dependencies.

Setup your Makefile.PL:


use strict;
use warnings;
use ExtUtils::MakeMaker;

WriteMakefile(
NAME => 'AppName',
AUTHOR => q{your name},
VERSION_FROM => 'lib/ExApp.pm',
ABSTRACT => 'example dancer app',
($ExtUtils::MakeMaker::VERSION >= 6.3002
? ('LICENSE'=> 'perl')
: ()),
PL_FILES => {},
PREREQ_PM => {
'Test::More' => 0,
'YAML' => 0,
'Dancer' => 1.3095,

# required to run in fcgi mode
'Plack' => 0,
'FCGI' => 0,
'FCGI::ProcManager' => 0,

# application specific
'Template' => 0,
'Dancer::Plugin::Database' => 0,
'DateTime' => 0,
'DateTime::Format::MySQL' => 0,

},
dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
clean => { FILES => 'example-app-name-*' },
);

You can do: cpanm --installdeps .

Other options....

cpanm Dancer Plack FCGI FCGI::ProcManager
Or
cpan install Dancer Plack FCGI FCGI::ProcManager

Configure nginx

Now, lets configure nginx nginx.conf. It isn't a large change from http://wiki.nginx.org/NginxFcgiExample. There are three main changes below.

  1. Configure nginx to serve the static content (in dev this isn't a huge deal but in production you will save some major time and resources).
  2. Plack's FCGI handler requires SCRIPT_NAME to be empty. I'm not sure why but i'm sure its a very smart security thing or due the fact that it isn't using a dispatch script.
  3. Plack's FCGI handler uses PATH_INFO and needs it to be configured. See:set $path_info $uri; line

Example Configuration:


server {
listen 80;
server_name fastcgi-example.leecarmichael.com;
root /home/user/dancer_app/public;
access_log logs/fcgi-example.access.log main;

# serve static content from nginx not dancer
location = /favicon.ico {
}

location /images {
}

location /js {
}

location /css {
}

# serve all other stuff from appserver
location / {
set $script "";
set $path_info $uri;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;

fastcgi_param SCRIPT_FILENAME $request_filename;

# plack FCGI handler requires these changes
fastcgi_param SCRIPT_NAME $script;
fastcgi_param PATH_INFO $path_info;

fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;

fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;

fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;

# can use port as well
fastcgi_pass unix:/tmp/myapp-fcgi.sock;
}
}

Start, Restart and Go

Start or restart nginx.

On debian: /etc/init.d/nginx restart

Startup your app server (make sure you'ave changed to /home/user/dancer_app):

plackup -E development -s FCGI -a bin/app.pl -S /tmp/myapp-fcgi.sock -D

See plackup for all the options. I added -D and usually add --error-log but a start up script is probably a better long term choice

After writing all this, i stumbled across a pretty helpful reference in the Plack docs on Plack::Handler::FCGI which replicates the fast-cgi nginx.conf above.

__END__

Changing Dancer::Plugin::Ajax's content type

10:53:00 07-Oct-2012

Dancer does lots of great things. It has a nice clean way to define routes to handle AJAX routes using the plugin Dancer::Plugin::Ajax.

ajax routes are defined in a clear way:


ajax '/stuff' => sub {
# do work and return
};

This plugin technique allows for clear way to separate between ajax and other types of actions for the same route.


ajax '/stuff' => sub {
# do ajax-y stuff here
};

get '/stuff' => sub {
# handle html response
};

Unfortunately, the one negative with Dancer::Plugin::Ajax is that is assumes all responses will be XML.

A quick fix is to manually set the content type in each ajax handler.


ajax '/stuff' => sub {
content_type('application/json');

# do work
};
or add set it as a general option in your main before hook or in each prefix route handler like:

package WebApp;

hook before => sub {
if ( request->is_ajax ) {
content_type('application/json');
}
};

Both of these solutions feel kind of clunky due to the level of duplication. Our app returns JSON or HTML snippets and never uses XML. This redundancy in code led me to creating a patch for Dancer that allows default Ajax content_type to be set in the config file. (see issue 840).

Config Example:


plugins:
ajax:
content_type: 'application/json'

__END__

Blueberry (Image slider) and YouTube video working in harmony

15:27:00 25-Sep-2012

Do what needs to be done

We recently launched a new home page and the designed used a responsive image slider called Blueberry. Well there were a few issues with navigation and I needed to be able to make sure to have the slider start to slide automatically and then stop while playing a YouTube video.

I need to fix the problem with navigation causing a speed up and unreliable timing while showing slides. I extended it to support being stopped and started. Since the project appears to be on hiatus (no changes in a year even though it has a few github issues), I forked it on github to fix the event issue and add the ability to stop/start slider.

Blueberry + YouTube sitting in a tree

I found it to be a bit of challenge to update the site to support pausing the image slider when the YouTube video that is linked in through iframe started and stop being played. I found to get the correct permissions and callback into the player I needed to use the YouTube iFrame Player API. (thank you Google)

To setup the Blueberry slider, there is some basic html
(and css see: https://github.com/lecar-red/Blueberry/blob/master/index.html).

Here is a blurb of html


Next is the Javascript code to setup the slider:

$(function() {
$('.blueberry').blueberry({hoverpause: true});
});

Now the image slider will start up showing images (and YouTube video).

Next comes dropping in the YouTube API, plus adding in the callback controls. The following snippet of JS code contains all of the code needed to start and stop slider when video is played and stopped by user. I'll explain it in the following sections.


1. The first closure is to load the youtube js API script. 

2. onPlayerStateChange is a function that is called each time the player changes state, it is passed an event object with what type of change occurred see the details in the YouTube API Docs.  

2a. This code will pause the slider when the video is playing (when event type is PLAYING). 

2b. When data event is type is PAUSED or ENDED restart slider. The Blueberry slider's code will restart the timeout interval at start and stop so it won't necessarily change right away. I could see expanding this code to only start when the video was ended in our case it wasn't required.

3. Create new API object and save player to global object (this could be done a bit cleaner by storing in a global object or something else - exercise for the reader :)

Once I waded through the various APIs, browser cross domain restrictions and code patches. The end solution wasn't too bad. The above YouTube API code could be used with any slider or carousel.

__END__