<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Jesse Shy</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jesse_shy/" />
    <link rel="self" type="application/atom+xml" href="http://blogs.perl.org/users/jesse_shy/atom.xml" />
    <id>tag:blogs.perl.org,2009-11-03:/users/jesse_shy//1106</id>
    <updated>2012-10-18T13:23:48Z</updated>
    <subtitle>A blog about the Perl programming language</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 4.38</generator>

<entry>
    <title>Perl Success Story - Managing PHP apps with Perl</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jesse_shy/2012/10/perl-success-story---managing-php-apps-with-perl.html" />
    <id>tag:blogs.perl.org,2012:/users/jesse_shy//1106.3968</id>

    <published>2012-10-18T13:14:10Z</published>
    <updated>2012-10-18T13:23:48Z</updated>

    <summary>WebPub helps install and manage popular web apps. We currently are doing WordPress, Drupal, MODX and phpBB. While the web UI is in PHP (decided before I came onboard) the backend is all Perl. Some of the major components being...</summary>
    <author>
        <name>Jesse Shy</name>
        
    </author>
    
    <category term="perlinthewild" label="#perlinthewild" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jesse_shy/">
        <![CDATA[<p>WebPub helps install and manage popular web apps. We currently are doing WordPress, Drupal, MODX and phpBB. While the web UI is in PHP (decided before I came onboard) the backend is all Perl.</p>

<p>Some of the major components being used are: Mojolicious, Moose, DBIx::Class and Gearman. <br />
Mojolicious provides the REST interface for the PHP front end and will be used in the near future by at least one other company we are working with. That company will write their client in Ruby. <br />
Moose is used heavily for meta method creation, mapping various before / after 'method' to validation and DB update_or_create and the installer system loads the appropriate role (each app has its own role for things that are app specific - an install of Drupal needs more fixup than WP) at runtime. <br />
DBIx::Class - no explaination needed<br />
Gearman - actual interaction with remote systems happens from workers.</p>]]>
        <![CDATA[<p>There are really two main applications. The one that does database CRUD, and the part that handles actual installation, upgrade, rollback, import and uninstall of the app. That piece is Moose based behind Gearman workers; has its own API and can function as an independent app. If you knew the API you could skip the REST/CRUD interface and write your own to use the installer system. Or even just use the .pm(s) in your own app ( if they were public ).<br />
Outside of the primary web app, there is a check for updates system which watches the application repositories for new versions and pulls those in automatically. There is a mass upgrade daemon that handles distributing jobs for say a mass upgrade from WP 3.4.1 to 3.4.2 and works with the job server to throttle jobs by IP address (so as not to trip connection limits). Autoupgrades can be kicked off from a command line tool or web interface and both clients use the same daemon, feeding it installation IDs to upgrade.<br />
These two pieces make heavy use of Mojo::UserAgent, Mojo::DOM, Mojo::IOLoop server/client. Mojo::IOLoop is being used where POE::Component::TCP::* would have been used in the past.</p>

<p>In the modules list below you may notice some duplication of fuctionality. Where in the REST/CRUD server we are running 5.12.4 under perlbrew, we were concerned with having this requirement where we may need to spin up gearman workers. We made the decision early on that we wanted to be able to deploy the workers in a 5.8.8 environment - you all know why. So whereas the REST/CRUD server uses Mojolicious modules, the workers use WWW::Mechanize. You may find other similar duplication between other modules depending on which sub system they are in.</p>

<p>The list of CPAN modules used in the project.<br />
Mojo::Base<br />
MojoX::Log::Log4perl<br />
File::Basename<br />
File::Spec<br />
Method::Signatures<br />
Moose<br />
DateTime<br />
Try::Tiny<br />
Log::Log4perl<br />
Exception::Base<br />
Moose::Role<br />
Validate::Tiny<br />
Email::Valid<br />
Data::Validate::URI<br />
Moose::Util::TypeConstraints<br />
MooseX::Aliases<br />
Net::xFTP<br />
Net::Ping::External<br />
File::Temp<br />
Path::Class<br />
Data::Random<br />
JSON<br />
List::MoreUtils <br />
Gearman::XS<br />
Gearman::XS::Client<br />
Gearman::XS::Worker<br />
Hash::Merge<br />
MooseX::Types::Path::Class<br />
MooseX::Types::URI<br />
cPanel::PublicAPI<br />
Template::Simple<br />
App::Genpass<br />
IO::String<br />
URI<br />
HTTP::Tiny<br />
WWW::Mechanize<br />
Path::Class<br />
Archive::Tar::Wrapper<br />
Crypt::CBC<br />
Cwd<br />
Config::ZOMG</p>

<p>Modules used in Testing:<br />
FindBin<br />
Test::More<br />
Test::DBIx::Class<br />
Data::Printer;<br />
Test::Mojo<br />
Test::TCP<br />
Test::FTP::Server<br />
File::Temp<br />
File::Copy::Recursive<br />
Privileges::Drop<br />
MooseX::AutoImmute<br />
MooseX::Types::Path::Class<br />
Test::Httpd::Apache2</p>

<p>A bunch of DBIx::Class components.</p>]]>
    </content>
</entry>

<entry>
    <title>YAPC::NA 2012 donate ticket</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jesse_shy/2012/05/yapcna-2012-donate-ticket.html" />
    <id>tag:blogs.perl.org,2012:/users/jesse_shy//1106.3260</id>

    <published>2012-05-19T15:05:24Z</published>
    <updated>2012-05-19T15:07:49Z</updated>

    <summary>I will not be using my badge to the conference. Is there a place where I can put this in a &apos;needs&apos; pot? To be used by someone who can make the conference, thanks....</summary>
    <author>
        <name>Jesse Shy</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jesse_shy/">
        <![CDATA[<p>I will not be using my badge to the conference. Is there a place where I can put this in a 'needs' pot? To be used by someone who can make the conference, thanks.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Asynchronous HTTP Requests Using Mojolicious</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jesse_shy/2012/03/asynchronous-http-requests-using-mojolicious.html" />
    <id>tag:blogs.perl.org,2012:/users/jesse_shy//1106.2905</id>

    <published>2012-03-06T13:22:30Z</published>
    <updated>2012-03-12T21:48:32Z</updated>

    <summary>This is in response to this article, Asynchronous HTTP Requests in Perl Using AnyEvent - linked to from Perl Weekly. Particularly, this quote: BTW, if you’re a Perl programmer and you’ve been jealous of all the cool kids and node.js,...</summary>
    <author>
        <name>Jesse Shy</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jesse_shy/">
        <![CDATA[<p>This is in response to this article, <a href="http://www.windley.com/archives/2012/03/asynchronous_http_requests_in_perl_using_anyevent.shtml">Asynchronous HTTP Requests in Perl Using AnyEvent</a> - linked to from <a href="http://perlweekly.com/">Perl Weekly</a>. Particularly, this quote:<br />
<blockquote><br />
BTW, if you’re a Perl programmer and you’ve been jealous of all the cool kids and node.js, AnyEvent is how you do node.js-style programming in Perl.<br />
</blockquote></p>

<p><strong>UPDATE: </strong>this is a better example.<br />
<a href="http://https://gist.github.com/0dbc430a67f28bac0b39">Doug Wilson gist of HTTP async with Mojo::IOLoop</a>.  On my test system, this now runs slightly faster than the AnyEvent::HTTP solutions.</p>

<p><br />
Below is *a* solution using Mojolicous. I am sure there are other frameworks that can do the same thing. Benchmarks showed that the AnyEvent program is faster anywhere from fractions of a ms to one entire second depending on the iteration. In this simple case, AnyEvent::HTTP may be the correct solution, however I think as part of a larger project you are still better off going with an async web framework like Mojolicious.</p>

<p>I tried to keep the same style as the original author for comparison and testing. Almost entirely copied and pasted from the Mojolicious documentation and the original article; here is what I whipped up:</p>

<pre>
#!/usr/bin/env perl

<p>use strict;<br />
use warnings;</p>

<p>use Mojo::UserAgent;<br />
use Mojo::IOLoop;<br />
use Time::HiRes qw(time);</p>

<p>my $url = [<br />
        "https://www.google.com",<br />
        "http://www.windley.com/",<br />
        "https://www.bing.com",<br />
        "http://www.example.com",<br />
        "http://www.wetpaint.com",<br />
        "http://www.uh.cu"<br />
        ];</p>

<p>my $ua = Mojo::UserAgent->new;</p>

<p>my $start = time;</p>

<p>foreach my $u (@$url) {<br />
    print "\n";<br />
    my $now = time;</p>

<p>    $ua->get($u, => sub {<br />
        my ($ua, $tx) = @_;<br />
        if (my $res = $tx->success) {<br />
            print "$u has length " . (length $tx->res->body) . " and loaded in " . (time() - $now) . "ms";<br />
        }<br />
        else {<br />
            my ($message, $code) = $tx->error;<br />
            print "Error for $u : ($code) $message"<br />
        }</p>

<p>        Mojo::IOLoop->stop;<br />
    });<br />
    Mojo::IOLoop->start;<br />
}</p>

<p>print "\nTotal elapsed time: " . (time - $start) . "ms\n";<br />
</pre></p>]]>
        
    </content>
</entry>

<entry>
    <title>How not to use Moose</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jesse_shy/2012/02/how-not-to-use-moose.html" />
    <id>tag:blogs.perl.org,2012:/users/jesse_shy//1106.2860</id>

    <published>2012-02-22T13:56:53Z</published>
    <updated>2012-02-22T19:13:20Z</updated>

    <summary>Maybe this is legitimate and I just don&apos;t know why, but I have seen the following in a couple of projects where I have taken over after the original programmer left: use Moose; has [qw/foo bar baz/], is =&gt; &apos;rw&apos;;...</summary>
    <author>
        <name>Jesse Shy</name>
        
    </author>
    
    <category term="moose" label="Moose" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jesse_shy/">
        <![CDATA[<p>Maybe this is legitimate and I just don't know why, but I have seen the following in a couple of projects where I have taken over after the original programmer left:</p>

<pre><code>use Moose;

<p>has [qw/foo bar baz/], is => 'rw';</p>

<p>no Moose;</p>

<p>sub something {}<br />
sub somethingelse {}</code></pre></p>

<p>OK, I collapsed the attrib declaration into one line for brevity. I will say that from the code, I can tell you these are not Perl programmers, they are old time C programmers with CS degrees who convinced someone they knew what they were doing because they can write psudocode for finding the first 100 prime numbers and first 20 fibs. Somehow, they stumbled across Moose, but I think they quite got it - or maybe they did and I'm wrong? In the whole application this is the only way Moose is used and it seems to me there is about 20 ways to get attrib getter/setters lighter, if that is all you want.  Maybe there should be a "Common Moose mistakes" in the documentation.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Archive::Tar::Wrapper vs. Archive::Tar</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jesse_shy/2012/02/archivetarwrapper-vs-archivetar.html" />
    <id>tag:blogs.perl.org,2012:/users/jesse_shy//1106.2808</id>

    <published>2012-02-13T18:42:45Z</published>
    <updated>2012-02-13T18:58:18Z</updated>

    <summary>If you don&apos;t know it, Archive::Tar is SLOW; it even says so. Running NYTProf recently on a project revealed that the major part of the program was taking a little more than 27 seconds to run and a little over...</summary>
    <author>
        <name>Jesse Shy</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jesse_shy/">
        <![CDATA[<p>If you don't know it, Archive::Tar is SLOW; it even says so. Running NYTProf recently on a project revealed that the major part of the program was taking a little more than 27 seconds to run and a little over 24 seconds of this was Archive::Tar reading the archive into memory. Since I did not need the in memory feature, I switched to Archive::Tar::Wrapper. That sub now takes about 2.5 seconds to run and the equivalent portion to Archive::Tar->new($file); is now Archive::Tar::Wrapper->new; $arch->read($file); now takes 631 ms. </p>]]>
        
    </content>
</entry>

<entry>
    <title>Perl documentation is Awesome</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jesse_shy/2012/01/perl-documentation-is-awesome.html" />
    <id>tag:blogs.perl.org,2012:/users/jesse_shy//1106.2633</id>

    <published>2012-01-02T14:41:33Z</published>
    <updated>2012-01-02T15:24:50Z</updated>

    <summary>After reading the blog here a couple of weeks ago about taking 10 minutes to look for the answer before asking your fellow dev, and several other things of late about the state of documentation and such, I wanted to...</summary>
    <author>
        <name>Jesse Shy</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jesse_shy/">
        <![CDATA[<p>After reading the blog here a couple of weeks ago about taking 10 minutes to look for the answer before asking your fellow dev, and several other things of late about the state of documentation and such, I wanted to take some time to say this: "Things can always be improved upon, but for the most part, the Perl community does an awesome job of documenting. Whether in formal docs or giving clear answers on the web."   What's my evidence? I have been using Perl since 1997. I have used it in my role as a system or network admin and as an actual programmer. I have used it at small businesses, large corps, an ILEC where we served voice, video and web services. I have used it to build monitoring and maintenance apps and even a billing app. I often get projects where the original dev has left and there is no documentation and I am on my second Mojolicious app in a year. I have only worked on a team once in that time, and I was teaching Perl to the other two members (sys/network admins). I say all this to hopefully give an idea of the range of projects where I have personally used our favorite language. I have never been on a mailing list and I have been on IRC twice, once just to look and once to ask which was the better way to do something with some XML. This means that ever time I have had a problem, needed to know how to do something, what the heck does that error mean or why the f* is this not working?  The answer has been in the documentation, on Perlmonks, Stackoverflow, advent calendar or a blog somewhere. Sometimes the answer is not direct (but most of the time it is). Armed with a well defined question and your favorite search engine, the Perl community has done an incredible job documenting the hows, whens and wheres; the ins and outs of the language, and modules. Yes, there is a core of devs that do development on the language or with the language that need IRC. These folks are the 1% of people doing anything with Perl (that's a fake statistic for dramatization). They and many others have done a fantastic job documenting and explaining things in a way that lets people like me (who should probably have been a mechanic) to just get stuff done. Thanks.</p>

<p>Go ahead now, take your shots.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Frequently installing apps via any FTP</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jesse_shy/2011/11/frequently-installing-apps-via-any-ftp.html" />
    <id>tag:blogs.perl.org,2011:/users/jesse_shy//1106.2461</id>

    <published>2011-11-18T13:39:51Z</published>
    <updated>2011-11-18T14:53:37Z</updated>

    <summary>Your app is in a tarball and clients only have FTP access to install your app on their host. Furthermore, you need to customize the config file (or do other process) for each install. What you need is Net::xFTP and...</summary>
    <author>
        <name>Jesse Shy</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jesse_shy/">
        <![CDATA[<p>Your app is in a tarball and clients only have FTP access to install your app on their host. Furthermore, you need to customize the config file (or do other process) for each install. What you need is Net::xFTP and Archive::Tar. Net::xFTP's <strong>put</strong> allows you to pass in an open filehandle typeglob as the local file. So you can open a filehandle on a string reference and use that as the <small>LOCAL FILE</small>. This is a simplified version. </p>

<p></p><pre>my $xftp = Net::xFTP-&gt;new('Foreign', 'hostname', user =&gt; $user, password =&gt; $password,);

my $next = Archive::Tar-&gt;iter('mytarball.tar.gz');
while (my $file = $next-&gt;() )  {
   
  if ($file-&gt;type == 5) {    # 5 is the filetype number for directories in this case<br />
    $xftp-&gt;mkdir($file-&gt;full_path);
    next;
  }

  open FH, '&lt;', $file-&gt;get_content_by_ref;

  $xftp-&gt;put(*FH, $file-&gt;full_path) or die $xftp-&gt;message;
}
</pre><p></p>

<p>If for some reason the files you need are expanded on the filesystem, you can use File::Find to get a list of the files you want, then use Archive::Tar to create the archive in memory and loop through that.</p>

<p></p><pre>find(sub{push @files,$File::Find::name}, "./");

my $archive;
open (my $in, '&gt;', \$archive);
Archive::Tar-&gt;create_archive($in,0,@files);

open (my $out, '&lt;', \$archive);
my $tar = Archive::Tar-&gt;new($out);

foreach my $file ($tar-&gt;get_files) {
  if ($file-&gt;type == 5) {
    $xftp-&gt;mkdir($file-&gt;full_path);
    next;
  }

  open (FH, "&lt;", \$file-&gt;get_content);
  $xftp-&gt;put(*FH, $file-&gt;full_path) or die $xftp-&gt;message;
}
</pre><p></p>

<p>A couple of things to note. The filehandle typeglob does not work with the regular SFTP protocol module (but does work for FTP and FTPS and Foreign). Use Foreign as the protocol if you want SFTP; this will use Net::SFTP::Foreign and not Net::SFTP.  Also, if using an in memory created archive $file-&gt;get_content_by_ref does not work, use \$file-&gt;get_content.</p>]]>
        
    </content>
</entry>

</feed>
