2 ###############################################################################
4 # An HTTP server for the 2.0 web
5 # Copyright (c) 2006 contributing authors
12 ###############################################################################
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)
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
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
28 # For more information visit www.meteorserver.org
30 ###############################################################################
32 package Meteor
::Channel
;
33 ###############################################################################
35 ###############################################################################
44 ###############################################################################
46 ###############################################################################
49 my $channelName=shift;
50 my $avoidCreation=shift;
52 unless(exists($Channels{$channelName}))
54 return undef if($avoidCreation);
58 $Channels{$channelName}=$class->newChannel($channelName);
60 &::syslog
('debug',"New channel $channelName");
63 return $Channels{$channelName};
70 foreach my $channelName (sort keys %Channels)
72 my $channel=$Channels{$channelName};
74 $list.=$channelName.'('.$channel->messageCount().'/'.$channel->subscriberCount().")$::CRLF";
82 my $channelName=shift;
84 delete($Channels{$channelName});
87 sub trimMessageStoresByTimestamp
{
89 my $minTimeStamp=shift;
91 return unless($minTimeStamp);
93 map { $_->trimMessageStoreByTimestamp($minTimeStamp) } (values %Channels);
99 map { $_->clearBuffer() } (values %Channels);
104 return scalar(keys %Channels);
107 ###############################################################################
109 ###############################################################################
112 # Create a new empty instance
123 # new instance from new server connection
125 my $self=shift-
>new();
128 $self->{'name'}=$name;
130 $self->{'subscribers'}=[];
131 $self->{'messages'}=[];
139 my @subscribers=@{$self->{'subscribers'}};
140 map { $_->closeChannel($self->{'name'}) } @subscribers;
143 ###############################################################################
145 ###############################################################################
152 my $subscriber=shift;
155 my $mode=shift || '';
156 my $userAgent=shift || '';
158 # Note: negative $startId means go back that many messages
159 my $startIndex=$self->indexForMessageID($startId);
160 my $logStartIndex = $startIndex || $self->lastMsgID() || 0;
162 push(@{$self->{'subscribers'}},$subscriber) if($persist);
167 $subscriber->{'subscriberID'},
174 return unless(defined($startIndex));
176 my $msgCount=scalar(@{$self->{'messages'}});
179 $startIndex=0 if($startIndex<0);
181 if($startIndex<$msgCount) {
182 $subscriber->sendMessages(@{$self->{'messages'}}[$startIndex..$msgCount-1]);
186 sub removeSubscriber
{
188 my $subscriber=shift;
189 my $reason=shift ||'unknown';
192 my $numsubs = scalar(@{$self->{'subscribers'}});
194 for (my $i=0; $i<$numsubs; $i++) {
195 if($self->{'subscribers'}->[$i]==$subscriber) {
203 splice(@{$self->{'subscribers'}},$idx,1);
205 my $timeConnected = time - $subscriber->{'ConnectionStart'};
209 $subscriber->{'subscriberID'},
212 $subscriber->{'MessageCount'},
213 $subscriber->{'bytesWritten'},
218 $self->checkExpiration();
221 sub subscriberCount
{
224 scalar(@{$self->{'subscribers'}});
229 my $messageText=shift;
231 my $message=Meteor
::Message-
>newWithID($MessageID++);
232 $message->setText($messageText);
233 $message->setChannelName($self->{'name'});
234 push(@{$self->{'messages'}},$message);
235 &::syslog
('debug',"New message ".$message->{"id"}." on channel ".$self->{'name'});
237 $self->trimMessageStoreBySize();
239 map { $_->sendMessages($message) } @{$self->{'subscribers'}};
247 scalar(@{$self->{'messages'}});
250 sub trimMessageStoreBySize
{
253 my $numMessages=scalar(@{$self->{'messages'}});
255 if($numMessages>$::CONF
{'MaxMessagesPerChannel'})
257 splice(@{$self->{'messages'}},0,-$::CONF
{'MaxMessagesPerChannel'});
261 sub trimMessageStoreByTimestamp
{
265 while(scalar(@{$self->{'messages'}})>0 && $self->{'messages'}->[0]->timestamp()<$ts)
267 my $msg=shift(@{$self->{'messages'}});
270 $self->checkExpiration();
276 $self->{'messages'}=[];
278 $self->checkExpiration();
281 sub checkExpiration
{
284 if($self->messageCount()==0 && $self->subscriberCount()==0)
286 my $name=$self->name();
287 &::syslog
('debug',"Channel expired: $name");
288 $self->deleteChannel($name);
292 sub indexForMessageID
{
296 # the messages is always sorted by ID, so we can
297 # use a binary search to find the message.
298 # return undef if there are no messages or the
299 # ID is that of the last message.
300 # Otherwise return the ID of the found message
301 # of if no message with that ID exists the one
302 # with the next higher ID
304 return undef unless(defined($id));
306 my $numMessages=scalar(@{$self->{'messages'}});
308 return undef unless($numMessages);
309 return -1 unless($id ne '');
311 # Note: negative $id means go back that many messages
312 return $numMessages+$id if($id<0);
315 my $high=$numMessages-1;
320 $mid=($low+$high)>>1;
321 $cond=$id <=> $self->{'messages'}->[$mid]->id();
336 return undef if($low>=$numMessages);
343 my $numMessages=scalar(@{$self->{'messages'}});
344 return undef unless($numMessages>0);
345 @{$self->{'messages'}}[-1]->id();
348 sub descriptionWithTemplate
{
352 return '' unless(defined($template) && $template ne '');
354 $template=~s
/~([a-zA-Z0-9_]*)~/
355 if(!defined($1) || $1 eq '') {
357 } elsif($1 eq 'messageCount') {
358 $self->messageCount();
359 } elsif($1 eq 'subscriberCount') {
360 $self->subscriberCount();
361 } elsif($1 eq 'lastMsgID') {
362 $self->lastMsgID() || 0;
363 } elsif($1 eq 'name') {
374 ############################################################################EOF