Module to manage HTTP errors - perl

I'm writing a Perl module Result to manage HTTP errors.
I am a little lost to generate the function managing all this.
Result.pm
package Result;
use strict;
use warnings;
use Data::Dumper;
use Log::Log4perl;
sub new
{
my $class = shift;
my %params = #_;
my $self = {
code => $params{'code'},
value => $params{'value'}
};
bless $self, $class;
return $self;
}
sub generateError
{
my $self = shift;
my %params = #_;
if($self->{'code'} == 200)
{
return "Your request was well executed !";
}
elsif($self->{'code'} == 400)
{
return "There is an error in your request! Please verify it!";
}
elsif($self->{'code'} == 404)
{
return "We did not find for what you ask !"
}
elsif($self->{'code'} == 500)
{
return "Internal error of the server, please re-try later !";
}
elsif($self->{'code'} == 504)
{
return "Your request has set of time to be executed, please retry !";
}
}
1;
App.pm
sub template
{
my $self = shift;
my $query = $self->query;
my $id = $query->param('id');
my $session = $self->param('session');
my $profile = $session->param('profile');
my $Project = Project->newFromId($id);
if(!$Project or $Project eq 'NOT_FOUND')
{
return $self->redirect('?rm=notfound');
}
if(!$profile->{'uid'} or $Project->{'userId'} != $profile->{'uid'})
{
return $self->redirect('?rm=notfound');
}
my $mailContent = from_json($Project->{'mail'});
my $templateContent = formatTemplate($Project->{'template'});
my $infos = [
{
'ID' => $id,
'TEMPLATE' => $templateContent,
'MAILSUBJECT' => $mailContent->{'subject'},
'MAILBODY' => $mailContent->{'body'}
}
];
if($mailContent->{'type'} eq 'text')
{
$infos->[0]{'MAILTEXT'} = 1;
}
else
{
$infos->[0]{'MAILHTML'} = 1;
}
return $self->processtmpl('template.tmpl', $infos);
}
1;

Related

Perl Redis listen does not subscribe to channel

This code doesn't seem to be working and I don't know how to debug this.. I'm using Mojolicious to send out subscribed messages through websocket.
use Mojo::Redis;
#Controller
sub data_stream {
my $c = shift;
$c->inactivity_timeout(300);
my $redis = Mojo::Redis-new('redis://xxxxxxxx#localhost:6379/');
my $pubsub = $redis->pubsub;
my $cb = $pubsub->listen('data' => sub {
my ($pubsub, $msg) = #_;
$c->app->log->debug("WS: $msg");
$c->send({text => $msg});
});
$c->on(finish => sub {
$c->app->log->debug("WS CONNECTION CLOSED!");
$pubsub->unlisten('data' => $cb)
});
}
Sub above is called from the following router
$router->websocket('/data_stream')->to('grid#data_stream');
Lol this is the second question that I answered myself.
This finally works when I moved the Mojo::Redis-new bit as helper
So in the router file;
$self->helper(redis => sub {
state $redis = Mojo::Redis->new('redis://anything:jejakredis1234!#localhost:6379/');
});
and in controller
sub data_stream {
my $c = shift;
$c->inactivity_timeout(300);
my $pubsub = $c->redis->pubsub;
my $cb = $pubsub->listen('data' => sub {
my ($pubsub, $msg) = #_;
$c->app->log->debug("WS: $msg");
$c->send({text => $msg});
});
$c->on(finish => sub {
$c->app->log->debug("WS CONNECTION CLOSED!");
$pubsub->unlisten('data' => $cb)
});
}

Custom Storable hooks for dclone-ing a light-weight object referencing a heavy-weight object

Say I have a tiny object that has a reference to a huge object:
package Tiny;
sub new {
my ($class, $tiny, $large) = #_;
return bless { tiny => $tiny, large => $large };
}
I'd like to create a STORABLE_freeze/STORABLE_thaw pair that lets me (recursively) clone $tiny but maintain/keep the reference to $large as-is without cloning $large too.
I tried temporarily deleting $self->{large} (see below), and putting it in a hash with a Scalar::Util::refaddr key and a weak reference to $large, serializing the rest of $self, and then putting the (weak) reference back into both the original object immediately and the cloned one in STORABLE_thaw, but it is a mess, and on every clone, the weak ref value gets deleted when it goes out of scope, but the key remains in the hash forever leaking memory and I need a global class member hash (%largeWeakRefs) to hold the temporary $large reference. Has a smell.
How it that possible to do this in a cleaner way?
Here is my solution using the hash to hold the large ref temporarily:
package Tiny;
use Scalar::Util qw(refaddr weaken);
sub new {
my ( $class, $tiny, $large ) = #_;
return bless { tiny => $tiny, large => $large }, $class;
}
# Ugly temporary storage to hold $large refs from _freeze to _thaw...
my %largeWeakRefs;
sub STORABLE_freeze {
my ( $self, $cloning ) = #_;
my $large = delete local $self->{large};
my $refaddr = refaddr $large;
$largeWeakRefs{$refaddr} = $large;
weaken $largeWeakRefs{$refaddr};
my %restOfSelf = %$self;
$self->{large} = $large;
return $refaddr, \%restOfSelf;
}
sub STORABLE_thaw {
my ($self, $cloning, $refaddr, $restOfSelf) = #_;
%$self = %$restOfSelf;
$self->{large} = $largeWeakRefs{$refaddr};
return $self;
}
(Yes I know, my example only handles cloning, not straight-up freeze and thaw)
You could add reference counts.
my %larges;
sub STORABLE_freeze {
my ( $self, $cloning ) = #_;
if ($cloning) {
my $large_key = pack('j', refaddr(self->{large}));
$larges{$large_key} //= [ $self->{large}, 0 ];
++$larges{$large_key}[1];
return ( $large_key, $self->{tiny} );
} else {
return ( "", $self->{tiny}, $self->{large} );
}
}
sub STORABLE_thaw {
my ( $self, $cloning, $serialized ) = splice(#_, 0, 3);
if ($cloning) {
my $large_key = $serialized;
$self->{ tiny } = shift;
$self->{ large } = $larges{$large_key}[0];
--$larges{$large_key}[1]
or delete($larges{$large_key});
} else {
$self->{ tiny } = shift;
$self->{ large } = shift;
}
}
Untested.
If the cloning process dies, you'll have a memory leak.
Alternatively, you could avoid the need for external resources as follows:
use Inline C => <<'__EOS__';
IV get_numeric_ref(SV *sv) {
SvGETMAGIC(sv);
if (!SvROK(sv))
croak("Argument not a reference");
sv = MUTABLE_SV(SvRV(sv));
SvREFCNT_inc(sv);
return PTR2IV(sv); /* Despite its name, can be used to convert pointer to IV */
}
SV* get_perl_ref_from_numeric_ref(IV iv) {
SV* sv = PTR2IV(iv);
return newRV_noinc(sv);
}
__EOS__
sub STORABLE_freeze {
my ( $self, $cloning ) = #_;
if ($cloning) {
return ( pack('j', get_numeric_ref($self->{large})), $self->{tiny} );
} else {
return ( "", $self->{tiny}, $self->{large} );
}
}
sub STORABLE_thaw {
my ( $self, $cloning, $serialized ) = splice(#_, 0, 3);
if ($cloning) {
$self->{ tiny } = shift;
$self->{ large } = get_perl_ref_from_numeric_ref(unpack('j', $serialized));
} else {
$self->{ tiny } = shift;
$self->{ large } = shift;
}
}
Didn't test STORABLE_freeze and STORABLE_thaw, but tested the C/XS code using the following:
use strict;
use warnings;
use feature qw( say state );
use Cpanel::JSON::XS qw( );
sub _dump {
state $encoder = Cpanel::JSON::XS->new->canonical->allow_nonref;
return $encoder->encode($_[0]);
}
{
my %h = ( a => 4, b => 5 );
say _dump(\%h); # {"a":4,"b":5}
say sprintf "0x%x", \%h; # 0x32cdbf8
say Internals::SvREFCNT(%h); # 1
my $i = get_numeric_ref(\%h);
say sprintf "0x%x", $i; # 0x32cdbf8
say Internals::SvREFCNT(%h); # 2
my $ref = get_perl_ref_from_numeric_ref($i);
say sprintf "0x%x", $ref; # 0x32cdbf8
say Internals::SvREFCNT(%h); # 2
say _dump($ref); # {"a":4,"b":5}
}
If the cloning process dies, you'll have a memory leak. I suppose it would be safe to rely on "large" not going anywhere during the cloning process, so you could remove the SvREFCNT_inc and change newRV_noinc to newRV to avoid the potential memory leak.
To avoid the possible memory leak, never store "large" in the object.
my %larges;
sub new {
my $class = shift;
my $self = bless({}, $class);
return $self->_init(#_);
}
sub _init {
my ($self, $tiny, $large) = #_;
$self->{ tiny } = $tiny;
{
my $large_key = pack('j', refaddr($self));
$self->{ large_key } = $large_key;
$larges{ $large_key } = $large;
}
return $self;
}
sub DESTROY {
my ($self) = #_;
if (defined( my $large_key = $self->{ large_key } )) {
delete( $larges{ $large_key } );
}
}
sub STORABLE_freeze {
my ( $self, $cloning ) = #_;
if ($cloning) {
return ( $self->{large_key}, $self->{tiny} );
} else {
return ( "", $self->{tiny}, $larges{ $self->{large_key} } );
}
}
sub STORABLE_thaw {
my ( $self, $cloning, $serialized ) = splice(#_, 0, 3);
if ($cloning) {
my ($tiny) = #_;
my $large_key = $serialized;
$self->_init($tiny, $larges{ $large_key });
} else {
$self->_init(#_);
}
}
Untested.
No memory leaks if the cloning process dies.

Can't build perl class use autoload

class Gene
package Gene;
use strict;
use Carp;
use vars qw($AUTOLOAD);
my %_ok_gene_attr = (
"id" => "string",
"name" => "string",
"chrom" => "string", # chromosome or seq id
"txtStart" => "int", # 1-based
"txtEnd" => "int" # 1-based
);
sub new {
my ($class, %arg) = #_;
my $self = {};
$self->{_id} = $arg{id} || croak "no id";
$self->{_name} = $arg{name} || croak "no db";
$self->{_chrom} = $arg{chrom} || croak "no seq_id";
$self->{_strand} = $arg{strand} || -1;
$self->{_txStart} = $arg{txStart} || -1;
$self->{_txEnd} = $arg{txEnd} || -1;
$self->{_cdsStart} = $arg{cdsStart} || -1;
$self->{_cdsEnd} = $arg{cdsEnd} || -1;
$self->{_exonCount} = $arg{exonCount} || -1;
$self->{_exonStarts} = $arg{exonStarts} || -1;
$self->{_exonEnds} = $arg{exonEnds} || -1;
$self->{_score} = $arg{score} || -1;
$self->{_name2} = $arg{name2} || -1;
$self->{_cdsStartStat} = $arg{cdsStartStat} || -1;
$self->{_cdsEndStat} = $arg{cdsEndStat} || -1;
$self->{_exonFrames} = $arg{exonFrames} || -1;
bless($self, $class);
}
sub AUTOLOAD {
my ($self, $newvalue) = #_;
my ($operation, $attribute) = ($AUTOLOAD =~ /(get)(_\w+)$/);
unless ($operation && $attribute) {
croak "Method name $AUTOLOAD is not in the recognized form get_attribute\n";
}
unless (defined $_ok_gene_attr{$attribute}) {
croak "No such attribute '$attribute' exists in the class ", ref($self);
}
if ($operation eq 'get') {
*{$AUTOLOAD} = sub { shift->{$attribute} };
} elsif($operation eq 'set') {
*{$AUTOLOAD} = sub { shift->{$attribute} = shift };
$self->{$attribute} = $newvalue;
}
return $self->{$attribute};
}
sub DESTROY {
my($self) = #_;
$self->_decr_count( );
}
I use this class in
open my $in, '<', q/C:\Users\Jesse\Desktop\refGene.txt/ or die "Cannot open file : $!";
while(<$in>) {
chomp $_;
my #temp= split(/\t/, $_);
my $i=0;
my $temp1= Gene->new("id" => $temp[0],"name"=>$temp[1],"chrom"=>$temp[2], "strand"=>$temp[3],"txStart"=>$temp[4], "txEnd"=>$temp[5],"cdsStart"=>$temp[6],"cdsEnd"=>$temp[7],"exonCount"=>$temp[8],"exonStarts"=>$temp[9],"exonEnds"=>$temp[10],"score"=>$temp[11],"name2"=>$temp[12],"cdsStartStat"=>$temp[13],"cdsEndStat"=>$temp[14],"exonFrames"=>$temp[15]);
}
is has a error
(in cleanup) Method name Gene::_decr_count is not in the recognized form get_attribute
It also seems the autoload function doesn't work when i use $temp1->set_id("1234")?
Try this some kind of fixed version of Gene.pm:
package Gene;
use strict;
use Carp;
use vars qw($AUTOLOAD);
use Data::Dumper;
my %_ok_gene_attr = (
"_id" => "string",
"_name" => "string",
"_chrom" => "string", # chromosome or seq id
"_txtStart" => "int", # 1-based
"_txtEnd" => "int" # 1-based
);
sub new {
my ($class, %arg) = #_;
my $self = {};
$self->{_id} = $arg{id} || croak "no id";
$self->{_name} = $arg{name} || croak "no db";
$self->{_chrom} = $arg{chrom} || croak "no seq_id";
$self->{_strand} = $arg{strand} || -1;
$self->{_txStart} = $arg{txStart} || -1;
$self->{_txEnd} = $arg{txEnd} || -1;
$self->{_cdsStart} = $arg{cdsStart} || -1;
$self->{_cdsEnd} = $arg{cdsEnd} || -1;
$self->{_exonCount} = $arg{exonCount} || -1;
$self->{_exonStarts} = $arg{exonStarts} || -1;
$self->{_exonEnds} = $arg{exonEnds} || -1;
$self->{_score} = $arg{score} || -1;
$self->{_name2} = $arg{name2} || -1;
$self->{_cdsStartStat} = $arg{cdsStartStat} || -1;
$self->{_cdsEndStat} = $arg{cdsEndStat} || -1;
$self->{_exonFrames} = $arg{exonFrames} || -1;
bless($self, $class);
}
sub AUTOLOAD {
my ($self, $newvalue) = #_;
my ($operation, $attribute) = ($AUTOLOAD =~ /(get|set)(_\w+)$/);
unless ($operation && $attribute) {
croak "Method name $AUTOLOAD is not in the recognized form set_{attribute} or get_{attribute}\n";
}
unless (defined $_ok_gene_attr{$attribute}) {
croak "No such attribute '$attribute' exists in the class ", ref($self);
}
if ($operation eq 'get') {
no strict 'refs';
*{$AUTOLOAD} = sub { shift->{$attribute} };
} elsif($operation eq 'set') {
no strict 'refs';
*{$AUTOLOAD} = sub { shift->{$attribute} = shift };
$self->{$attribute} = $newvalue;
}
return $self->{$attribute};
}
sub DESTROY {
my($self) = #_;
$self->_decr_count( );
}
Tested with the following script:
#!/usr/bin/perl
use strict;
use warnings;
use Gene;
my $t1 = Gene->new(id=>"id", name=>"name", chrom=>"chrom");
$t1->set_id("1234");
print $t1->get_id(), "\n";
Beside using Perl's builtin OO system, you may also want to take a look of some other OO system, such as Moose. See perlootut for further details.

Sending messages with facebook xmpp api

I have copied and modified some of the facebook's given chat api code, now I want to send a message to my friend. I found that we send a xml <message from="" to=""> to send a message. But that did not happen. maybe it's because i don't know what to put on from and to attribs?
The Code:
<?php
$STREAM_XML = '<stream:stream '.
'xmlns:stream="http://etherx.jabber.org/streams" '.
'version="1.0" xmlns="jabber:client" to="chat.facebook.com" '.
'xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">';
$AUTH_XML = '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" '.
'mechanism="X-FACEBOOK-PLATFORM"></auth>';
$CLOSE_XML = '</stream:stream>';
$RESOURCE_XML = '<iq type="set" id="3">'.
'<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">'.
'<resource>fb_xmpp_script</resource></bind></iq>';
$SESSION_XML = '<iq type="set" id="4" to="chat.facebook.com">'.
'<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>';
$START_TLS = '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>';
$MESSAGE = '<message from="-cyberkiller.nishchal#chat.facebook.com" to="-nootan.ghimire#chat.facebook.com">
<body>This is the test message! Sent from App. by, "Nishchal"</body>
</message>';
function open_connection($server) {
$fp = fsockopen($server, 5222, $errno, $errstr);
if (!$fp) {
print "$errstr ($errno)<br>";
} else {
print "connnection open<br>";
}
return $fp;
}
function send_xml($fp, $xml) {
fwrite($fp, $xml);
}
function recv_xml($fp, $size=4096) {
$xml = fread($fp, $size);
if (!preg_match('/^</', $xml)) {
$xml = '<' . $xml;
}
if ($xml === "") {
return null;
}
$xml_parser = xml_parser_create();
xml_parse_into_struct($xml_parser, $xml, $val, $index);
xml_parser_free($xml_parser);
return array($val, $index);
}
function find_xmpp($fp, $tag, $value=null, &$ret=null) {
static $val = null, $index = null;
do {
if ($val === null && $index === null) {
list($val, $index) = recv_xml($fp);
if ($val === null || $index === null) {
return false;
}
}
foreach ($index as $tag_key => $tag_array) {
if ($tag_key === $tag) {
if ($value === null) {
if (isset($val[$tag_array[0]]['value'])) {
$ret = $val[$tag_array[0]]['value'];
}
return true;
}
foreach ($tag_array as $i => $pos) {
if ($val[$pos]['tag'] === $tag && isset($val[$pos]['value']) &&
$val[$pos]['value'] === $value) {
$ret = $val[$pos]['value'];
return true;
}
}
}
}
$val = $index = null;
} while (!feof($fp));
return false;
}
function xmpp_connect($options, $access_token) {
global $STREAM_XML, $AUTH_XML, $RESOURCE_XML, $SESSION_XML, $CLOSE_XML, $START_TLS;
$fp = open_connection($options['server']);
if (!$fp) {
return false;
}
send_xml($fp, $STREAM_XML);
if (!find_xmpp($fp, 'STREAM:STREAM')) {
return false;
}
if (!find_xmpp($fp, 'MECHANISM', 'X-FACEBOOK-PLATFORM')) {
return false;
}
send_xml($fp, $START_TLS);
if (!find_xmpp($fp, 'PROCEED', null, $proceed)) {
return false;
}
stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
send_xml($fp, $STREAM_XML);
if (!find_xmpp($fp, 'STREAM:STREAM')) {
return false;
}
if (!find_xmpp($fp, 'MECHANISM', 'X-FACEBOOK-PLATFORM')) {
return false;
}
send_xml($fp, $AUTH_XML);
if (!find_xmpp($fp, 'CHALLENGE', null, $challenge)) {
return false;
}
$challenge = base64_decode($challenge);
$challenge = urldecode($challenge);
parse_str($challenge, $challenge_array);
$resp_array = array(
'method' => $challenge_array['method'],
'nonce' => $challenge_array['nonce'],
'access_token' => $access_token,
'api_key' => $options['app_id'],
'call_id' => 0,
'v' => '1.0',
);
$response = http_build_query($resp_array);
$xml = '<response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">'.
base64_encode($response).'</response>';
send_xml($fp, $xml);
if (!find_xmpp($fp, 'SUCCESS')) {
return false;
}
send_xml($fp, $STREAM_XML);
if (!find_xmpp($fp,'STREAM:STREAM')) {
return false;
}
if (!find_xmpp($fp, 'STREAM:FEATURES')) {
return false;
}
send_xml($fp, $RESOURCE_XML);
if (!find_xmpp($fp, 'JID')) {
return false;
}
send_xml($fp, $SESSION_XML);
if (!find_xmpp($fp, 'SESSION')) {
return false;
}
send_xml($fp, $MESSAGE);
if (!find_xmpp($fp, 'BODY')) {
return false;
}
send_xml($fp, $CLOSE_XML);
print ("Authentication complete<br>");
fclose($fp);
return true;
}
function get_access_token(){
$token=new Facebook(array("AppId"=>"my app id","AppSecret"=>"my app secret"));
$token=$facebook->getAccessToken();
return $token;
}
function _main() {
require_once("facebook.php");
$app_id='app id';
$app_secret='app secret';
$my_url = "http://localhost/message.php";
$uid = 'cyberkiller.nishchal#chat.facebook.com';
$access_token = get_access_token();
$options = array(
'uid' => $uid,
'app_id' => $app_id,
'server' => 'chat.facebook.com',
);
if (xmpp_connect($options, $access_token)) {
print "Done<br>";
} else {
print "An error ocurred<br>";
}
}
_main();
so what do I need to do to send a message to that user through this, i tried to create a xml with the message but got strucked there, can any one please suggest something, When I run the code, socket enable crypto is being executed after that it is taking some time like 20 secs, then it displays an error occured, do I have to remove the send_xml($fp,$STREAM_XML); for the second time after the stream_socket_enable_crypto($fp, false, STREAM_CRYPTO_METHOD_TLS_CLIENT);
I changed the second parameter of this call to false because I don't have an ssl connection, what should I do next?
Use Facebook ID instead of the url username.Get it by requesting http://graph.facebook.com/{username}
Then replace it on "from" and "to" attributes.Also remove the hyphen on "from" attribute, or just remove all of it (from my experience its still going to work).Hyphen on "to" attribute is mandatory.

Perl package error handling question

I have a package called "SamplePkg". I have another script that uses SamplePkg, creates an object and calls a method.
package SamplePkg;
use strict;
use DBI;
use Try::Tiny;
my $dbh = DBI_>connect(..., { RaiseError => 1 });
sub new {
my $self = {};
$self->{CODE} = 0;
bless($self);
return $self;
}
sub do_something {
my $self = shift;
try {
my $query = "select myvalue from mytable";
$sth = $dbh->prepare($query);
$sth->execute();
} catch { $self->{CODE} = 100; return; }
$self->{CODE} = 50;
}
The other script
use SamplePkg;
my $object = SamplePkg->new();
$object->do_something();
print "Code is: $object->{CODE}\n";
Questions:
For some reason, the try block doesn't catch the DB error (myvalue is not a valid column name)
The "return" in the catch block does not return to the calling script
The output gives the error code as 50
try { ... } catch { ... };
is really
try(sub { ... }, catch(sub { ... }));
Returning from the sub that's called when an exception is caught returns from that sub, not from the sub in which try is located.
You could use
try {
my $query = "select myvalue from mytable";
$sth = $dbh->prepare($query);
$sth->execute();
$self->{CODE} = 50;
} catch {
$self->{CODE} = 100;
};
Or maybe you need something more like
my $success = try {
my $query = "select myvalue from mytable";
$sth = $dbh->prepare($query);
$sth->execute();
return 1;
} catch {
return 0;
};
... do stuff ...
$self->{CODE} = $succes ? 50 : 100;