| 1 | package Net::Partty; |
|---|
| 2 | |
|---|
| 3 | use strict; |
|---|
| 4 | use warnings; |
|---|
| 5 | use base 'Class::Accessor::Fast'; |
|---|
| 6 | __PACKAGE__->mk_accessors(qw/ sock host port select /); |
|---|
| 7 | our $VERSION = '0.02'; |
|---|
| 8 | |
|---|
| 9 | use Carp; |
|---|
| 10 | use IO::Select; |
|---|
| 11 | use IO::Socket; |
|---|
| 12 | |
|---|
| 13 | my $DefaultOpts = { |
|---|
| 14 | host => 'www.partty.org', |
|---|
| 15 | port => 2750, |
|---|
| 16 | }; |
|---|
| 17 | |
|---|
| 18 | sub new { |
|---|
| 19 | my($class, %opts) = @_; |
|---|
| 20 | |
|---|
| 21 | my $self = bless {}, $class; |
|---|
| 22 | |
|---|
| 23 | for my $opt (qw/ sock host port /) { |
|---|
| 24 | $self->{$opt} = delete $opts{$opt} || $DefaultOpts->{$opt}; |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | $self->{select} = IO::Select->new; |
|---|
| 28 | $self->{sock} or $self->_sock_open; |
|---|
| 29 | |
|---|
| 30 | $self; |
|---|
| 31 | } |
|---|
| 32 | |
|---|
| 33 | sub _sock_open { |
|---|
| 34 | my $self = shift; |
|---|
| 35 | $self->{sock} = IO::Socket::INET->new( |
|---|
| 36 | PeerAddr => $self->host, |
|---|
| 37 | PeerPort => $self->port, |
|---|
| 38 | Blocking => 1, |
|---|
| 39 | Proto => 'tcp', |
|---|
| 40 | ) or croak $!; |
|---|
| 41 | $self->select->add($self->{sock}); |
|---|
| 42 | $self->{sock}; |
|---|
| 43 | } |
|---|
| 44 | |
|---|
| 45 | sub _sock_close { |
|---|
| 46 | my $self = shift; |
|---|
| 47 | return unless $self->{sock}; |
|---|
| 48 | close $self->{sock}; |
|---|
| 49 | $self->select->remove($self->{sock}); |
|---|
| 50 | delete $self->{sock}; |
|---|
| 51 | } |
|---|
| 52 | |
|---|
| 53 | sub _send_uint8 { |
|---|
| 54 | my($self, $int) = @_; |
|---|
| 55 | my $data = pack 'C', $int; |
|---|
| 56 | $self->sock->syswrite($data, 1); |
|---|
| 57 | } |
|---|
| 58 | sub _send_uint16 { |
|---|
| 59 | my($self, $int) = @_; |
|---|
| 60 | my $data = pack 'n', $int; |
|---|
| 61 | $self->sock->syswrite($data, 2); |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | sub connect { |
|---|
| 65 | my($self, %opts) = @_; |
|---|
| 66 | |
|---|
| 67 | my @params = qw( message session_name writable_password readonly_password ); |
|---|
| 68 | my @error; |
|---|
| 69 | for my $param (@params) { |
|---|
| 70 | push @error, $param unless exists $opts{$param}; |
|---|
| 71 | } |
|---|
| 72 | croak join(', ', @error) . ' parameters is required.' if @error; |
|---|
| 73 | |
|---|
| 74 | croak 'session time out' unless $self->can_write(10); |
|---|
| 75 | $self->sock->syswrite('Partty!', 7); |
|---|
| 76 | $self->_send_uint8(2); |
|---|
| 77 | for my $param (@params) { |
|---|
| 78 | $self->_send_uint16(length $opts{$param}); |
|---|
| 79 | } |
|---|
| 80 | for my $param (@params) { |
|---|
| 81 | $self->sock->syswrite($opts{$param}, length $opts{$param}); |
|---|
| 82 | } |
|---|
| 83 | $self->sock->flush; |
|---|
| 84 | |
|---|
| 85 | |
|---|
| 86 | croak 'session time out' unless $self->can_read(10); |
|---|
| 87 | my $sock = $self->sock; |
|---|
| 88 | my $buf; |
|---|
| 89 | $self->sock->read($buf, 2); |
|---|
| 90 | my $retcode = unpack 'n', $buf; |
|---|
| 91 | $self->sock->read($buf, 2); |
|---|
| 92 | my $retmessage_len = unpack 'n', $buf; |
|---|
| 93 | $self->sock->read(my $retmessage, $retmessage_len); |
|---|
| 94 | croak $retmessage if $retcode; |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | sub can_read { |
|---|
| 98 | my($self, $time) = @_; |
|---|
| 99 | $self->select->can_read($time); |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | sub can_write { |
|---|
| 103 | my($self, $time) = @_; |
|---|
| 104 | $self->select->can_write($time); |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | |
|---|
| 108 | 1; |
|---|
| 109 | __END__ |
|---|
| 110 | |
|---|
| 111 | =encoding utf8 |
|---|
| 112 | |
|---|
| 113 | =head1 NAME |
|---|
| 114 | |
|---|
| 115 | Net::Partty - Partty.org! interface |
|---|
| 116 | |
|---|
| 117 | =head1 SYNOPSIS |
|---|
| 118 | |
|---|
| 119 | use Net::Partty; |
|---|
| 120 | my $partty = Net::Partty->new; |
|---|
| 121 | $partty->connect( |
|---|
| 122 | session_name => 'session', |
|---|
| 123 | message => 'message', |
|---|
| 124 | writable_password => 'password', |
|---|
| 125 | }; |
|---|
| 126 | |
|---|
| 127 | =head1 DESCRIPTION |
|---|
| 128 | |
|---|
| 129 | Net::Partty is Partty.org! login interface for perl. |
|---|
| 130 | |
|---|
| 131 | =head1 AUTHOR |
|---|
| 132 | |
|---|
| 133 | Kazuhiro Osawa E<lt>ko@yappo.ne.jpE<gt> |
|---|
| 134 | |
|---|
| 135 | =head1 SEE ALSO |
|---|
| 136 | |
|---|
| 137 | C<example/pertty.pl> |
|---|
| 138 | L<http://www.partty.org/> |
|---|
| 139 | |
|---|
| 140 | =head1 REPOSITORY |
|---|
| 141 | |
|---|
| 142 | svn co http://svn.coderepos.org/share/lang/perl/Net-Partty/trunk Net-Partty |
|---|
| 143 | |
|---|
| 144 | Net::Partty is Subversion repository is hosted at L<http://coderepos.org/share/>. |
|---|
| 145 | patches and collaborators are welcome. |
|---|
| 146 | |
|---|
| 147 | =head1 LICENSE |
|---|
| 148 | |
|---|
| 149 | This library is free software; you can redistribute it and/or modify |
|---|
| 150 | it under the same terms as Perl itself. |
|---|
| 151 | |
|---|
| 152 | =cut |
|---|