/[meteor]/googlecode.com/svn/trunk/Meteor/Channel.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/Channel.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 47 - (hide annotations)
Mon Feb 4 21:06:42 2008 UTC (16 years, 2 months ago) by knops.gerd
File size: 8033 byte(s)
• syslog change: If `SyslogFacility` is set to `none`, meteord will not put itself into the background and print all syslog messages with a priority higher than `debug` to standard output. The output will be prefixed with a timestamp (unix time in seconds) and a tab character.

• New syslog messges: joinchannel, leavechannel, document


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 Channel
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::Channel;
33     ###############################################################################
34     # Configuration
35     ###############################################################################
36    
37     use strict;
38    
39     use Meteor::Message;
40    
41     our %Channels=();
42     our $MessageID=0;
43    
44     ###############################################################################
45     # Class methods
46     ###############################################################################
47     sub channelWithName {
48     my $class=shift;
49     my $channelName=shift;
50     my $avoidCreation=shift;
51    
52     unless(exists($Channels{$channelName}))
53     {
54     return undef if($avoidCreation);
55     #
56     # Create new channel
57     #
58     $Channels{$channelName}=$class->newChannel($channelName);
59    
60     &::syslog('debug',"New channel $channelName");
61     }
62    
63     return $Channels{$channelName};
64     }
65    
66     sub listChannels {
67     my $class=shift;
68    
69     my $list='';
70     foreach my $channelName (sort keys %Channels)
71     {
72     my $channel=$Channels{$channelName};
73    
74     $list.=$channelName.'('.$channel->messageCount().'/'.$channel->subscriberCount().")$::CRLF";
75     }
76    
77     $list;
78     }
79    
80 knops.gerd 45 sub listChannelsUsingTemplate {
81     my $class=shift;
82     my $template=shift;
83    
84     return '' unless(defined($template) && $template ne '');
85    
86     my $list='';
87     foreach my $channelName (sort keys %Channels)
88     {
89     my $channel=$Channels{$channelName};
90    
91     $list.=$channel->descriptionWithTemplate($template);
92     }
93    
94     $list;
95     }
96    
97 knops.gerd 11 sub deleteChannel {
98     my $class=shift;
99     my $channelName=shift;
100    
101     delete($Channels{$channelName});
102     }
103    
104     sub trimMessageStoresByTimestamp {
105     my $class=shift;
106     my $minTimeStamp=shift;
107    
108     return unless($minTimeStamp);
109    
110     map { $_->trimMessageStoreByTimestamp($minTimeStamp) } (values %Channels);
111     }
112    
113     sub clearAllBuffers {
114     my $class=shift;
115    
116     map { $_->clearBuffer() } (values %Channels);
117     }
118    
119 knops.gerd 25 sub numChannels {
120    
121     return scalar(keys %Channels);
122     }
123    
124 knops.gerd 11 ###############################################################################
125     # Factory methods
126     ###############################################################################
127     sub new {
128     #
129     # Create a new empty instance
130     #
131     my $class=shift;
132    
133     my $obj={};
134    
135     bless($obj,$class);
136     }
137    
138     sub newChannel {
139     #
140     # new instance from new server connection
141     #
142     my $self=shift->new();
143    
144     my $name=shift;
145     $self->{'name'}=$name;
146    
147     $self->{'subscribers'}=[];
148     $self->{'messages'}=[];
149    
150     $self;
151     }
152    
153     sub DESTROY {
154     my $self=shift;
155    
156     my @subscribers=@{$self->{'subscribers'}};
157 knops.gerd 13 map { $_->closeChannel($self->{'name'}) } @subscribers;
158 knops.gerd 11 }
159    
160     ###############################################################################
161     # Instance methods
162     ###############################################################################
163     sub name {
164     shift->{'name'};
165     }
166    
167     sub addSubscriber {
168     my $self=shift;
169     my $subscriber=shift;
170     my $startId=shift;
171     my $persist=shift;
172 knops.gerd 47 my $mode=shift || '';
173     my $userAgent=shift || '';
174 knops.gerd 11
175     # Note: negative $startId means go back that many messages
176    
177     push(@{$self->{'subscribers'}},$subscriber) if($persist);
178    
179 knops.gerd 47 &::syslog('info','',
180     'joinchannel',
181     $subscriber->{'subscriberID'},
182     $self->{'name'},
183     $mode,
184     $startId,
185     $userAgent
186     );
187    
188 knops.gerd 11 my $startIndex=$self->indexForMessageID($startId);
189     return unless(defined($startIndex));
190    
191     my $msgCount=scalar(@{$self->{'messages'}});
192     my $txt='';
193    
194     $startIndex=0 if($startIndex<0);
195    
196 knops.gerd 45 if($startIndex<$msgCount)
197 knops.gerd 11 {
198 knops.gerd 45 $subscriber->sendMessages(@{$self->{'messages'}}[$startIndex,$msgCount-1]);
199 knops.gerd 11 }
200     }
201    
202     sub removeSubscriber {
203     my $self=shift;
204     my $subscriber=shift;
205 knops.gerd 47 my $reason=shift ||'unknown';
206 knops.gerd 11
207     my $idx=undef;
208     for(my $i=0;$i<scalar(@{$self->{'subscribers'}});$i++)
209     {
210     if($self->{'subscribers'}->[$i]==$subscriber)
211     {
212     $idx=$i;
213     last;
214     }
215     }
216    
217     if(defined($idx))
218     {
219     splice(@{$self->{'subscribers'}},$idx,1);
220 knops.gerd 47
221     &::syslog('info','',
222     'leavechannel',
223     $subscriber->{'subscriberID'},
224     $self->{'name'},
225     $subscriber->{'ConnectionStart'},
226     $subscriber->{'MessageCount'},
227     $subscriber->{'bytesWritten'},
228     $reason
229     );
230 knops.gerd 11 }
231    
232     $self->checkExpiration();
233     }
234    
235     sub subscriberCount {
236     my $self=shift;
237    
238     scalar(@{$self->{'subscribers'}});
239     }
240    
241     sub addMessage {
242     my $self=shift;
243     my $messageText=shift;
244    
245     my $message=Meteor::Message->newWithID($MessageID++);
246 knops.gerd 16 $message->setText($messageText);
247     $message->setChannelName($self->{'name'});
248 knops.gerd 11 push(@{$self->{'messages'}},$message);
249    
250     $self->trimMessageStoreBySize();
251    
252 knops.gerd 45 map { $_->sendMessages($message) } @{$self->{'subscribers'}};
253 knops.gerd 46
254     $message;
255 knops.gerd 11 }
256    
257     sub messageCount {
258     my $self=shift;
259    
260     scalar(@{$self->{'messages'}});
261     }
262    
263     sub trimMessageStoreBySize {
264     my $self=shift;
265    
266     my $numMessages=scalar(@{$self->{'messages'}});
267    
268     if($numMessages>$::CONF{'MaxMessagesPerChannel'})
269     {
270     splice(@{$self->{'messages'}},0,-$::CONF{'MaxMessagesPerChannel'});
271     }
272     }
273    
274     sub trimMessageStoreByTimestamp {
275     my $self=shift;
276     my $ts=shift;
277    
278     while(scalar(@{$self->{'messages'}})>0 && $self->{'messages'}->[0]->timestamp()<$ts)
279     {
280     my $msg=shift(@{$self->{'messages'}});
281     }
282    
283     $self->checkExpiration();
284     }
285    
286     sub clearBuffer {
287     my $self=shift;
288    
289     $self->{'messages'}=[];
290    
291     $self->checkExpiration();
292     }
293    
294     sub checkExpiration {
295     my $self=shift;
296    
297     if($self->messageCount()==0 && $self->subscriberCount()==0)
298     {
299     my $name=$self->name();
300     &::syslog('debug',"Channel expired: $name");
301     $self->deleteChannel($name);
302     }
303     }
304    
305     sub indexForMessageID {
306     my $self=shift;
307     my $id=shift;
308    
309     # the messages is always sorted by ID, so we can
310     # use a binary search to find the message.
311     # return undef if there are no messages or the
312     # ID is that of the last message.
313     # Otherwise return the ID of the found message
314     # of if no message with that ID exists the one
315     # with the next higher ID
316     #
317     return undef unless(defined($id));
318    
319 knops.gerd 46 my $numMessages=scalar(@{$self->{'messages'}});
320 knops.gerd 11
321     return undef unless($numMessages);
322     return -1 unless($id ne '');
323    
324     # Note: negative $id means go back that many messages
325     return $numMessages+$id if($id<0);
326    
327     my $low=0;
328     my $high=$numMessages-1;
329     my $mid;
330     my $cond;
331     while($low<=$high)
332     {
333     $mid=($low+$high)>>1;
334     $cond=$id <=> $self->{'messages'}->[$mid]->id();
335     if($cond<0)
336     {
337     $high=$mid-1;
338     }
339     elsif($cond>0)
340     {
341     $low=$mid+1;
342     }
343     else
344     {
345     return $mid;
346     }
347     }
348    
349     return undef if($low>=$numMessages);
350    
351     return $low;
352     }
353    
354 knops.gerd 46 sub lastMsgID {
355     my $self=shift;
356    
357     my $numMessages=scalar(@{$self->{'messages'}});
358    
359     return 'undefined' unless($numMessages>0);
360    
361     @{$self->{'messages'}}[-1]->id();
362     }
363    
364 knops.gerd 45 sub descriptionWithTemplate {
365     my $self=shift;
366     my $template=shift;
367    
368     $template=~s/~([a-zA-Z0-9_]*)~/
369     if(!defined($1) || $1 eq '')
370     {
371     '~';
372     }
373     elsif($1 eq 'messageCount')
374     {
375     $self->messageCount();
376     }
377     elsif($1 eq 'subscriberCount')
378     {
379     $self->subscriberCount();
380     }
381 knops.gerd 46 elsif($1 eq 'lastMsgID')
382     {
383     $self->lastMsgID();
384     }
385    
386 knops.gerd 45 elsif(exists($self->{$1}))
387     {
388     $self->{$1};
389     }
390     else
391     {
392     '';
393     }
394     /gex;
395    
396     $template;
397     }
398    
399 knops.gerd 11 1;
400 andrew.betts 3 ############################################################################EOF

  ViewVC Help
Powered by ViewVC 1.1.26