/[meteor]/googlecode.com/svn/trunk/Meteor/Subscriber.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /googlecode.com/svn/trunk/Meteor/Subscriber.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (hide annotations)
Thu Dec 14 16:29:42 2006 UTC (13 years, 5 months ago) by knops.gerd
File size: 7847 byte(s)
• Change CRLF line endings back to LF only

1 knops.gerd 11 #!/usr/bin/perl -w
2     ###############################################################################
3     # Meteor
4     # An HTTP server for the 2.0 web
5     # Copyright (c) 2006 contributing authors
6     #
7     # Subscriber.pm
8     #
9     # Description:
10     # A Meteor Subscriber
11     #
12     ###############################################################################
13     #
14     # This program is free software; you can redistribute it and/or modify it
15     # under the terms of the GNU General Public License as published by the Free
16     # Software Foundation; either version 2 of the License, or (at your option)
17     # any later version.
18     #
19     # This program is distributed in the hope that it will be useful, but WITHOUT
20     # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21     # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
22     # more details.
23     #
24     # You should have received a copy of the GNU General Public License along
25     # with this program; if not, write to the Free Software Foundation, Inc.,
26     # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27     #
28     # For more information visit www.meteorserver.org
29     #
30     ###############################################################################
31    
32     package Meteor::Subscriber;
33     ###############################################################################
34     # Configuration
35     ###############################################################################
36    
37     use strict;
38    
39     use Meteor::Connection;
40     use Meteor::Channel;
41     use Meteor::Document;
42    
43     @Meteor::Subscriber::ISA=qw(Meteor::Connection);
44    
45     our %PersistentConnections=();
46    
47     ###############################################################################
48     # Factory methods
49     ###############################################################################
50     sub newFromServer {
51     my $class=shift;
52    
53     my $self=$class->SUPER::newFromServer(shift);
54    
55     $self->{'headerBuffer'}='';
56     $self->{'MessageCount'}=0;
57     $self->{'MaxMessageCount'}=0;
58    
59     $self->{'ConnectionStart'}=time;
60     my $maxTime=$::CONF{'MaxTime'};
61     if($maxTime>0)
62     {
63     $self->{'ConnectionTimeLimit'}=$self->{'ConnectionStart'}+$maxTime;
64     }
65    
66     $self;
67     }
68    
69     ###############################################################################
70     # Class methods
71     ###############################################################################
72     sub deleteSubscriberWithID {
73     my $class=shift;
74     my $id=shift;
75    
76     if(exists($PersistentConnections{$id}))
77     {
78     $PersistentConnections{$id}->close(1);
79     }
80     }
81    
82     sub pingPersistentConnections {
83     my $class=shift;
84    
85     my $msg=$::CONF{'PingMessage'};
86     my @cons=values %PersistentConnections;
87    
88     map { $_->write($msg) } @cons;
89     }
90    
91     sub checkPersistentConnectionsForMaxTime {
92     my $class=shift;
93    
94     my $time=time;
95     my @cons=values %PersistentConnections;
96    
97     map { $_->checkForMaxTime($time) } @cons;
98     }
99    
100     ###############################################################################
101     # Instance methods
102     ###############################################################################
103     sub processLine {
104     my $self=shift;
105     my $line=shift;
106    
107     # Once the header was processed we ignore any input
108     return unless(exists($self->{'headerBuffer'}));
109    
110     if($line ne '')
111     {
112     #
113     # Accumulate header
114     #
115     $self->{'headerBuffer'}.="$line\n";
116     }
117     else
118     {
119     #
120     # Empty line signals end of header.
121     # Analyze header, register with appropiate channel
122     # and send pending messages.
123     #
124     # GET $::CONF{'SubscriberDynamicPageAddress'}?channel=ml123&restartfrom=1 HTTP/1.1
125     #
126     # Find the 'GET' line
127     #
128     if($self->{'headerBuffer'}=~/GET\s+$::CONF{'SubscriberDynamicPageAddress'}\?(\S+)/)
129     {
130     my @formData=split('&',$1);
131     my $channelName=undef;
132     my $startIndex=undef;
133     my $backtrack=undef;
134     my $persist=1;
135     my $subscriberID=undef;
136     foreach my $formElement (@formData)
137     {
138     if($formElement=~/^channel=(.+)$/)
139     {
140     $channelName=$1;
141     }
142     elsif($formElement=~/^restartfrom=(\d*)$/)
143     {
144     $startIndex=$1;
145     $startIndex='' unless(defined($startIndex));
146     }
147     elsif($formElement=~/^backtrack=(\d+)$/)
148     {
149     $backtrack=$1;
150     $backtrack=0 unless(defined($backtrack));
151     }
152     elsif($formElement=~/^persist=(?i)(yes|true|1|no|false|0)$/)
153     {
154     $persist=0 if($1=~/(no|false|0)/i);
155     }
156     elsif($formElement=~/^id=(.+)$/)
157     {
158     $subscriberID=$1;
159     }
160     elsif($formElement=~/^maxmessages=(\d+)$/i)
161     {
162     $self->{'MaxMessageCount'}=$1;
163     }
164     elsif($formElement=~/^template=(\d+)$/i)
165     {
166     $self->{'HeaderTemplateNumber'}=$1;
167     }
168     elsif($formElement=~/^maxtime=(\d+)$/i)
169     {
170     my $clientRequest=$1;
171     my $serverDefault=$::CONF{'MaxTime'};
172    
173     if($serverDefault==0 || $serverDefault>$clientRequest)
174     {
175     $self->{'ConnectionTimeLimit'}=$self->{'ConnectionStart'}+$clientRequest;
176     }
177     }
178     }
179    
180     delete($self->{'headerBuffer'});
181    
182     if(defined($startIndex) && defined($backtrack))
183     {
184     $self->emitHeader("404 Cannot use both 'restartfrom' and 'backtrack'");
185     $self->close();
186    
187     return;
188     }
189    
190     if(defined($subscriberID) && $persist)
191     {
192     $self->{'subscriberID'}=$subscriberID;
193     $self->deleteSubscriberWithID($subscriberID);
194     $PersistentConnections{$subscriberID}=$self;
195     }
196    
197     if(defined($channelName))
198     {
199     $self->emitOKHeader();
200    
201     $startIndex=-$backtrack if(!defined($startIndex) && defined($backtrack));
202    
203     $self->setChannelName($channelName,$startIndex,$persist);
204    
205     $self->close(1) unless($persist);
206    
207     return;
208     }
209     }
210     elsif($self->{'headerBuffer'}=~/GET\s+([^\s\?]+)/)
211     {
212     Meteor::Document->serveFileToClient($1,$self);
213    
214     $self->close(1);
215    
216     return;
217     }
218    
219     #
220     # If we fall through we did not understand the request
221     #
222     $self->emitErrorHeader();
223     }
224     }
225    
226     sub setChannelName {
227     my $self=shift;
228     my $channelName=shift;
229     my $startIndex=shift;
230     my $persist=shift;
231    
232     my $channel=Meteor::Channel->channelWithName($channelName);
233     $self->{'channel'}=$channel if($persist);
234    
235     $channel->addSubscriber($self,$startIndex,$persist);
236     }
237    
238     sub emitOKHeader {
239     my $self=shift;
240    
241     $self->emitHeader('200 OK');
242     }
243    
244     sub emitErrorHeader {
245     my $self=shift;
246    
247     $self->emitHeader('404 Not Found');
248    
249     # close up shop here!
250     $self->close();
251     }
252    
253     sub emitHeader {
254     my $self=shift;
255     my $status=shift;
256    
257     my $header=undef;
258     if(exists($self->{'HeaderTemplateNumber'}))
259     {
260     my $hn='HeaderTemplate'.$self->{'HeaderTemplateNumber'};
261    
262     $header=$::CONF{$hn};
263     }
264     $header=$::CONF{'HeaderTemplate'} unless(defined($header));
265    
266     $header=~s/~([^~]+)~/
267     if(!defined($1) || $1 eq '')
268     {
269     '~';
270     }
271     elsif($1 eq 'server')
272     {
273     $::PGM;
274     }
275     elsif($1 eq 'status')
276     {
277     $status;
278     }
279     elsif($1 eq 'servertime')
280     {
281     time;
282     }
283     else
284     {
285     '';
286     }
287     /gex;
288    
289     $self->write($header);
290     }
291    
292     sub sendMessage {
293     my $self=shift;
294     my $msg=shift;
295    
296     $self->write($msg);
297    
298     my $msgCount=++$self->{'MessageCount'};
299    
300     my $maxMsg=$::CONF{'MaxMessages'};
301     if(defined($maxMsg) && $maxMsg>0 && $msgCount>=$maxMsg)
302     {
303     $self->close(1);
304     }
305    
306     if($self->{'MaxMessageCount'}>0 && $msgCount>=$self->{'MaxMessageCount'})
307     {
308     $self->close(1);
309     }
310     }
311    
312     sub close {
313     my $self=shift;
314     my $noShutdownMsg=shift;
315    
316     $self->{'channel'}->removeSubscriber($self) if($self->{'channel'});
317     delete($self->{'channel'});
318    
319     if(exists($self->{'subscriberID'}))
320     {
321     delete($PersistentConnections{$self->{'subscriberID'}});
322     }
323    
324     #
325     # Send shutdown message unless remote closed or
326     # connection not yet established
327     #
328     unless($noShutdownMsg || $self->{'remoteClosed'} || exists($self->{'headerBuffer'}))
329     {
330     my $msg=$::CONF{'SubscriberShutdownMsg'};
331     if(defined($msg) && $msg ne '')
332     {
333     $self->write($msg);
334     }
335     }
336    
337     $self->SUPER::close();
338     }
339    
340     sub checkForMaxTime {
341     my $self=shift;
342     my $time=shift;
343    
344     $self->close(1) if(exists($self->{'ConnectionTimeLimit'}) && $self->{'ConnectionTimeLimit'}<$time);
345     }
346    
347     1;
348 andrew.betts 3 ############################################################################EOF

  ViewVC Help
Powered by ViewVC 1.1.26