PennMUSH Community

root/1.8.3/trunk/test/MUSHConnection.pm

Revision 439, 3.7 kB (checked in by pennmush, 2 years ago)

PennMUSH 1.7.7p20 Archival

Line 
1 package MUSHConnection;
2
3 # use strict;
4 use IO::Poll;
5 use IO::Socket::INET;
6
7 my $nextpat = "PATTERN000000001";
8
9 sub new {
10   my $proto = shift;
11   my $class = ref($proto) || $proto;
12   my $self = [];
13   $self->[0] = IO::Socket::INET->new();
14   $self->[1] = {};
15   $self->[1]->{PREFIX} = '=-=-= OUTPUTPREFIX =-=-=';
16   $self->[1]->{SUFFIX} = '=-=-= OUTPUTSUFFIX =-=-=';
17   $self->[1]->{MATCHER} = {};
18   bless($self, $class);
19   $self->connect(@_) if @_;
20   return $self;
21 }
22
23 sub connected {
24   my $self = shift;
25
26   my $socket = $self->[0];
27   return $socket->connected();
28 }
29
30 sub connect {
31   my $self = shift;
32   my $addr = shift;
33   my $port = shift;
34   my $name = shift;
35   my $passwd = shift;
36
37   my $socket = $self->[0];
38   $socket->close if $socket->connected();
39   $self->[0] = IO::Socket::INET->new(PeerAddr => $addr, PeerPort => $port,
40                                      Proto => "tcp");
41   $socket = $self->[0];
42 #  $socket->connect(PeerAddr => $addr, PeerPort => $port, Proto => "tcp");
43   $socket->autoflush(1);
44   $socket->timeout(30);
45
46   $self->read_to_pattern('.') || return;
47   $self->read_to_empty();
48   $socket->print("connect $name $passwd\r\n");
49   $socket->flush();
50   $self->read_to_pattern('.') || return;
51   $self->read_to_empty();
52   sleep(1);
53   $socket->print("OUTPUTPREFIX " . $self->[1]->{PREFIX} . "\r\n");
54   $socket->print("OUTPUTSUFFIX " . $self->[1]->{SUFFIX} . "\r\n");
55   $socket->print("say CodeMUSH $$\r\n");
56   $self->read_to_pattern("CodeMUSH $$") || return;
57 }
58
59 sub disconnect {
60   my $self = shift;
61
62   my $socket = $self->[0];
63   $socket->close if $socket->connected();
64 }
65
66 sub read_to_pattern {
67   my $self = shift;
68   my $pattern = shift;
69
70 # warn "Looking for pattern $pattern\n";
71   my $matcher = $self->[1]->{MATCHER}->{$pattern};
72   unless ($matcher) {
73     my $patsub = $pattern;
74 #    $patsub =~ s/(\W)/\\$1/go;
75     my $sub = <<EOT;
76 sub $nextpat {
77   return (\$`, \$&, \$') if \$_[\$[] =~ /$patsub/o;
78   return undef;
79 }
80 1;
81 EOT
82 # warn "Building matcher $nextpat:\n$sub";
83     eval($sub);
84     $matcher = $nextpat++;
85     $self->[1]->{MATCHER}->{$pattern} = $matcher;
86   }
87 # warn "Using matcher $matcher\n";
88
89   my $socket = $self->[0];
90   my $buffer = $self->[1]->{BUFFER};
91   my @match = &$matcher($buffer);
92   my $poll = new IO::Poll;
93   $poll->mask($socket => POLLIN | POLLERR | POLLHUP);
94   until (@match > 1) {
95 # warn "Looping...\n";
96     my $buf;
97     my $amount = $socket->sysread($buf, 1024);
98 # warn "Read $amount: $buf...\n";
99     $amount || ($self->disconnect(), return);
100     $buffer .= $buf;
101   } continue {
102     @match = &$matcher($buffer);
103   }
104   $self->[1]->{BUFFER} = $match[2];
105
106 # warn "Found match: ".join(",", @match)."\n";
107 # warn "Returning: ".join(",",@match[0,1])."\n";
108   return (@match[0,1]);
109 }
110
111 sub read_to_empty {
112   my $self = shift;
113
114 # warn "Emptying input...\n";
115   my $socket = $self->[0];
116   my $poll = new IO::Poll;
117   $poll->mask($socket => POLLIN | POLLERR | POLLHUP);
118   my $result = $self->[1]->{BUFFER};
119   my $buf;
120   while ($poll->poll(0) && !($poll->events($socket) & POLLERR | POLLHUP)) {
121     $socket->read($buf, 1024, 0);
122     $result .= $buf;
123   }
124   $self->[1]->{BUFFER} = "";
125 # warn "Have result: $result\n";
126   return $result;
127 }
128
129 sub command {
130   my $self = shift;
131   my $command = shift;
132   my $socket = $self->[0];
133   my $noise = $self->read_to_empty();
134   $socket->print($command."\r\n");
135   my @result = $self->read_to_pattern($self->[1]->{PREFIX});
136   $noise .= $result[0];
137   $self->[1]->{NOISE} = $noise;
138   @result = $self->read_to_pattern($self->[1]->{SUFFIX});
139   $result[0] =~ s/^[\r\n]+//o;
140 # warn "Noise: $noise\n";
141   return $result[0];
142 }
143
144 sub noise {
145   my $self = shift;
146   return $self->[1]->{NOISE};
147 }
148
149 sub listen {
150   my $self = shift;
151   $self->command("think Listening!");
152   $self->[1]->{NOISE} =~ s/^\r?\n//o;
153 # warn "LISTENING!: ".$self->[1]->{NOISE}."\n";
154   return $self->[1]->{NOISE};
155 }
156
157 1;
Note: See TracBrowser for help on using the browser.