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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations)
Thu Nov 27 00:33:21 2008 UTC (15 years, 4 months ago) by andrew.betts
File size: 10471 byte(s)
1 Fixed: Added SIGPIPE handler.  We noticed that under heavy load
Meteor receives SIGPIPEs from the OS, suspected to relate to clients
that have just disconnected the moment Meteor attempts to write to the
socket.  This caused Meteor to crash.
2 Fixed: Long polling multiple channels no longer causes the loop to
die and restart when some channels have messages queued for delivery.
3 Fixed: Over time, Meteor 'collected' connections from clients that
never got disconnected even if MaxTime was set.  This happened if the
client concerned sent a header with no terminating blank line.  Meteor
kept waiting for the rest of the header, which never arrived, and
therefore the client remained in limbo, never subjected to the MaxTime
time limit because it had not yet become a subscriber.  Clients are
now allowed 30 seconds to send a valid request header.
4 Fixed: If only one message existed on the server, the JS client
would continue to request it again and again, because it has message
ID 0, and the JS client considered this an invalid message ID.
5 Fixed: Corrected some comments in file headers

6 Changed: MaxMessages has been renamed to CloseOnEvent and functions
in a similar, but not quite identical way.  Thanks to Matthew Haak,
who pointed out the extreme confusingness of MaxMessages and a bug
that has resulted in Fix 2 above.  Setting CloseOnEvent to any value
that evaluates to true will cause Meteor to close subscriber
connections after at least one message has been sent and there are no
further messages pending.  This is identical to MaxMessages for values
of 0 and 1, but where MaxMessages is set to a value higher than one,
replacing it with CloseOnEvent with the same value will act as though
it were set to one.  The intent of MaxMessages was to enable long-
polling (and it is used by the JS client in that way), and
CloseonEvent is a drop in replacement for that behaviour.
7 Changed: Meteor JS client now uses dynamic <SCRIPT> tags for all
polling behaviours, rather than XHR.  This enables it to make poll
requests cross-domain (see 13)
8 Changed: Meteor JS client now abstracts timestamp lookups to a
dedicated method.
9 Changed: Default HeaderTemplates no longer include cache busting
headers, since all meteor requests contain a millisecond timestamp and
so no client makes the same request twice.  These were therefore
simply chewing up bandwidth.
10 Changed: Date strings used for logging debug messages are cached to
avoid numerous expensive lookups to localtime().
11 Changed: Channel info is only sent in a response if the client does
not request a restart from a specified ID.  The logic being that if
the client knows the ID they want to start from, they have already
made previous requests and have the channel information they need.
Bandwidth saving measure.

12 Added: JS client now has a Meteor.isSupportedBrowser() method,
which you can call to detemine whether Meteor will run in the user's
browser version.
13 Added: JS client can now use different hosts for polling and
streaming.  This is only really useful if your website is on a domain
that has a lot of cookies, and you don't want to send them in every
poll request.  Removing cookies from request headers can reduce the
size of the request significantly.  We find that with cookies included
Meteor poll requests are usually larger than the responses.  To use,
set Meteor.pollhost.  Meteor.pollhost can be any domain, while
Meteor.host must be a subdomain of your website hostname.
14 Added: Config file now supports new 'FooterTemplate' parameter, for
a string to send just before the connection to the subscriber is
closed.  This is in support of change 7.
15 Added: Better inline documentation for ChannelInfoTemplate config
parameter
16 Added: Log output includes connection IDs corresponding to the file
inode for each connection
17 Added: New controller command LISTCONNECTIONS, produces a newline
delimited list of all currently connected clients, and for each one
displaying "ConnectionID IPAddress ClientType [SubscriberID]"
18 Added: New controller command DESCRIBE, takes a ConnectionID as a
parameter, and outputs numerous statistics about that particular
client, including number of messages sent/received, user agent, IP
address, time connected, time remaining until MaxTime etc.
19 Added: New controller comment LISTSUBSCRIBERS, produces a newline
delimited list of all currently connected streaming subscribers, and
for each one displaying "SubscriberID IPAddress Starttime TimeLimit
TimeRemaining MessageCount UserAgent"
20 Added: SHOWSTATS command produces the following additional stats:
connection_count: total current connections, real_subscribers: total
of number of currently connected streaming subscribers plus the number
of unique polling connections seen in the last 60 seconds.
21 Added: STDERR outputs prior to every exit() for debugging purposes
22 Added: The UDP server is now considered stable, and is the best way
of broadcasting messages to lots of Meteor nodes simultaneously and
efficiently. 


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     # Meteor Configuration handling.
11     #
12     # Main program should call Meteor::Config::setCommandLineParameters(@ARGV),.
13     # Afterwards anybody can access $::CONF{<parameterName>}, where
14     # <parameterName> is any valid parameter (except 'Help') listed in the
15     # @DEFAULTS array below.
16     #
17     ###############################################################################
18     #
19     # This program is free software; you can redistribute it and/or modify it
20     # under the terms of the GNU General Public License as published by the Free
21     # Software Foundation; either version 2 of the License, or (at your option)
22     # any later version.
23     #
24     # This program is distributed in the hope that it will be useful, but WITHOUT
25     # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26     # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
27     # more details.
28     #
29     # You should have received a copy of the GNU General Public License along
30     # with this program; if not, write to the Free Software Foundation, Inc.,
31     # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32     #
33     # For more information visit www.meteorserver.org
34     #
35     ###############################################################################
36    
37     package Meteor::Config;
38     ###############################################################################
39     # Configuration
40     ###############################################################################
41    
42     use strict;
43    
44     our @DEFAULTS=(
45 andrew.betts 62 'Template for each line in channelinfo. Placeholders are name, lastMsgID, subscriberCount, messageCount. Channel info is included in output when client does not give a message start index in its request (indicating it is the client\'s first request for that channel)',
46 andrew.betts 50 ChannelInfoTemplate => '<script>ch("~name~", ~lastMsgID~);</script>\r\n',
47    
48 knops.gerd 11 'Configuration file location on disk (if any)',
49     ConfigFileLocation => '/etc/meteord.conf',
50    
51     'IP address for controller server (leave empty for all local addresses)',
52     ControllerIP => '',
53    
54     'Port number for controller connections',
55     ControllerPort => 4671,
56    
57     'Controller Shutdown message, sent when the controller server shuts down (leave empty for no message)',
58     ControllerShutdownMsg => '',
59    
60     'Debug Flag, when set daemon will run in foreground and emit debug messages',
61     Debug => 0,
62    
63     'Name of index file to serve when a directory is requested from the static file web server',
64 andrew.betts 62 DirectoryIndex => 'index.html',
65 knops.gerd 11
66 andrew.betts 62 'Footer template',
67     FooterTemplate => '</body></html>',
68    
69 andrew.betts 51 'Header template, ~server~, ~servertime~ and ~status~ will be replaced by the appropriate values.',
70 andrew.betts 62 HeaderTemplate => 'HTTP/1.1 ~status~\r\n\r\n~channelinfo~\r\n',
71 knops.gerd 11
72     'Print out this help message',
73     Help => '',
74    
75 andrew.betts 62 'Format to use for timestamps in debug output: unix or human',
76 andrew.betts 50 LogTimeFormat => 'human',
77    
78 knops.gerd 11 'Maximum age of a message in seconds',
79     MaxMessageAge => 7200,
80    
81 andrew.betts 62 'Whether to close subscriber connections once at least one message has been sent, and there are no further messages pending. 1 to enable, 0 to disable. Irrelevant unless Persist is set to 1.',
82     CloseOnEvent => 0,
83 knops.gerd 11
84     'Maximum number of stored messages per channel',
85     MaxMessagesPerChannel => 250,
86    
87     'Maximum duration in seconds for a subscriber connection to exist before forcing a it to close. Note that the server checks for expired connections in 60 second intervals, so small changes to this value will not have much of an effect. Use 0 to disable',
88     MaxTime => 0,
89    
90 andrew.betts 20 'Message template, ~text~, ~id~, ~channel~ and ~timestamp~ will be replaced by the appropriate values',
91     MessageTemplate => '<script>p(~id~,"~channel~","~text~");</script>\r\n',
92 knops.gerd 11
93 andrew.betts 50 'Interval at which PingMessage is sent to all persistent subscriber connections. Must be at least 3 if set higher than zero. Set to zero to disable.',
94 knops.gerd 11 PingInterval => 5,
95    
96 andrew.betts 50 'Persistence of a connection.',
97 knops.gerd 45 Persist => 0,
98    
99 andrew.betts 51 'Message to be sent to all persistent subscriber connections (see above) every PingInterval seconds',
100 knops.gerd 11 PingMessage => '<script>p(-1,"");</script>\r\n',
101    
102     'IP address for subscriber server (leave empty for all local addresses)',
103     SubscriberIP => '',
104    
105     'Port number for subscriber connections',
106     SubscriberPort => 4670,
107    
108     'Subscriber Shutdown message, sent when the subscriber server shuts down (leave empty for no message)',
109 andrew.betts 62 SubscriberShutdownMsg => '<script>eof();</script>\r\n',
110 knops.gerd 11
111     'An absolute filesystem path, to be used as the document root for Meteor\'s static file web server. If left empty, no documents will be served.',
112     SubscriberDocumentRoot => '/usr/local/meteor/public_html',
113    
114 andrew.betts 50 'Since Meteor is capable of serving static pages from a document root as well as streaming events to subscribers, this parameter is used to specify the URI at which the event server can be reached. If set to the root, Meteor will lose the ability to serve static pages.',
115 knops.gerd 11 SubscriberDynamicPageAddress => '/push',
116    
117     'The syslog facility to use',
118     SyslogFacility => 'daemon',
119 knops.gerd 48
120     'IP address for udp server (leave empty for all local addresses)',
121     UDPIP => '',
122    
123     'Port number for udp connections, set to 0 to disable',
124     UDPPort => 0,
125    
126 knops.gerd 11 );
127    
128     our %ConfigFileData=();
129     our %CommandLine=();
130     our %Defaults=();
131 knops.gerd 45 our %Modes=();
132 knops.gerd 11
133     for(my $i=0;$i<scalar(@DEFAULTS);$i+=3)
134     {
135     $Defaults{$DEFAULTS[$i+1]}=$DEFAULTS[$i+2];
136     }
137    
138     ###############################################################################
139     # Class methods
140     ###############################################################################
141     sub updateConfig {
142     my $class=shift;
143    
144     %::CONF=();
145    
146     my $debug=$class->valueForKey('Debug');
147    
148 andrew.betts 50 print STDERR '-'x79 ."\nMeteor server v$::VERSION (release date: $::RELEASE_DATE)\r\nLicensed under the terms of the GNU General Public Licence (2.0)\n".'-'x79 ."\n" if($debug);
149 knops.gerd 11
150     my @keys=();
151    
152     for(my $i=0;$i<scalar(@DEFAULTS);$i+=3)
153     {
154     next if($DEFAULTS[$i+1] eq 'Help');
155     push(@keys,$DEFAULTS[$i+1]);
156     }
157    
158 knops.gerd 45 foreach my $mode ('',keys %Modes)
159     {
160 andrew.betts 50 print STDERR ($mode) ? "\r\n$mode:\r\n" : "\r\nDefaults:\r\n" if($debug);
161 knops.gerd 45 foreach my $baseKey (@keys)
162 knops.gerd 11 {
163 knops.gerd 45 my $foundValue=0;
164     my $key=$baseKey.$mode;
165    
166     if(exists($CommandLine{$key}))
167 knops.gerd 11 {
168 knops.gerd 45 print STDERR "CmdLine" if($debug);
169     $::CONF{$key}=$CommandLine{$key};
170     $foundValue=1;
171 knops.gerd 11 }
172 knops.gerd 45 elsif(exists($ConfigFileData{$key}))
173 knops.gerd 11 {
174 knops.gerd 45 print STDERR "CnfFile" if($debug);
175     $::CONF{$key}=$ConfigFileData{$key};
176     $foundValue=1;
177 knops.gerd 11 }
178 knops.gerd 45 elsif(exists($Defaults{$key}))
179 knops.gerd 11 {
180 knops.gerd 45 print STDERR "Default" if($debug);
181     $::CONF{$key}=$Defaults{$key};
182     $foundValue=1;
183 knops.gerd 11 }
184 knops.gerd 45
185     next unless($foundValue);
186    
187 andrew.betts 50 print STDERR "\t$baseKey\t$::CONF{$key}\n" if($debug);
188 knops.gerd 45
189     # Take care of escapes
190     $::CONF{$key}=~s/\\(.)/
191 andrew.betts 50 if($1 eq 'r') {
192 knops.gerd 45 "\r";
193 andrew.betts 50 } elsif($1 eq 'n') {
194 knops.gerd 45 "\n";
195 andrew.betts 50 } elsif($1 eq 's') {
196 knops.gerd 45 ' ';
197 andrew.betts 50 } elsif($1 eq 't') {
198 knops.gerd 45 "\t";
199 andrew.betts 50 } elsif($1 eq '0') {
200     "\0";
201     } else {
202 knops.gerd 45 $1;
203     }
204     /gex;
205     }
206 knops.gerd 11 }
207     print STDERR '-'x79 ."\n" if($debug);
208     }
209    
210     sub valueForKey {
211     my $class=shift;
212     my $key=shift;
213    
214     return $CommandLine{$key} if(exists($CommandLine{$key}));
215     return $ConfigFileData{$key} if(exists($ConfigFileData{$key}));
216    
217     $Defaults{$key};
218     }
219    
220     sub setCommandLineParameters {
221     my $class=shift;
222    
223 knops.gerd 42 #
224     # Quick check if we should show the version, if so ignore everything else
225     # Accept -v, -version, and everything in between
226     #
227     foreach my $p (@_)
228     {
229     if(index($p,'-v')==0 && index('-version',$p)==0)
230     {
231     print "$::PGM $::VERSION\n";
232     exit(0);
233     }
234     }
235    
236 knops.gerd 11 while(my $cnt=scalar(@_))
237     {
238     my $k=shift(@_);
239     &usage("'$k' invalid") unless($k=~s/^\-(?=.+)//);
240    
241     $k='Debug' if($k eq 'd');
242    
243 knops.gerd 45 my $mode='';
244    
245 andrew.betts 50 if($k=~s/(\.(.+))$//)
246 knops.gerd 45 {
247 andrew.betts 50 $mode=$2;
248 knops.gerd 45 $Modes{$mode}=1;
249     }
250    
251 knops.gerd 11 my $key=undef;
252     my $kl=length($k);
253     my $kOrig=$k;
254     $k=lc($k);
255    
256     for(my $i=0;$i<scalar(@DEFAULTS);$i+=3)
257     {
258     my $p=$DEFAULTS[$i+1];
259     my $pl=length($p);
260    
261     next if($kl>$pl);
262    
263     #print "$kl $pl $k $p\n";
264    
265     if($kl==$pl && $k eq lc($p))
266     {
267     $key=$p;
268     last;
269     }
270    
271     my $ps=lc(substr($p,0,$kl));
272    
273     if($k eq $ps)
274     {
275     if(defined($key))
276     {
277     &usage("Ambigous parameter name '$kOrig'");
278     }
279     $key=$p;
280     }
281     }
282    
283     &usage("Unknown parameter name '$kOrig'") unless(defined($key));
284    
285     &usage() if($key eq 'Help');
286    
287     #print "$kOrig: $key\n";
288    
289 knops.gerd 45 $CommandLine{"$key$mode"}=1;
290 knops.gerd 11
291     if($cnt>1 && $_[0]!~/^\-(?!\-)/)
292     {
293     my $param=shift;
294     $param=~s/^\-\-/\-/;
295 knops.gerd 45 $CommandLine{"$key$mode"}=$param;
296 knops.gerd 11 }
297     }
298    
299     $class->readConfig();
300    
301     $class->updateConfig();
302     }
303    
304     sub readConfig {
305     my $class=shift;
306    
307     %ConfigFileData=();
308    
309     my $path=$class->valueForKey('ConfigFileLocation');
310     return unless(defined($path) && -f $path);
311    
312 knops.gerd 45 my $mode='';
313    
314 knops.gerd 11 open(CONFIG,"$path") or &usage("Config file '$path' for read: $!\n");
315     while(<CONFIG>)
316     {
317     next if(/^\s*#/);
318     next if(/^\s*$/);
319    
320     s/[\r\n]*$//;
321    
322 knops.gerd 45 if(/^\s*\[\s*([^\]\s]+)\s*\]\s*$/)
323     {
324 andrew.betts 50 $Modes{$1}=1;
325     $mode = $1;
326 knops.gerd 45 next;
327     }
328    
329 knops.gerd 11 unless(/^(\S+)\s*(.*)/)
330     {
331     &usage("Invalid configuration file parameter line '$_'");
332     }
333    
334     my $key=$1;
335     my $val=$2;
336     $val='' unless(defined($val));
337    
338 knops.gerd 49 unless(exists($Defaults{$key}))
339 knops.gerd 11 {
340 knops.gerd 49 &usage("Unknown configuration file parameter name '$key$mode'");
341 knops.gerd 11 }
342 knops.gerd 49 if($key eq 'ConfigFileLocation')
343 knops.gerd 11 {
344 knops.gerd 49 &usage("'ConfigFileLocation' parameter not allowed in configuration file!");
345 knops.gerd 11 }
346    
347     $val=~s/^--/-/;
348    
349 knops.gerd 45 $ConfigFileData{"$key$mode"}=$val;
350 knops.gerd 11 }
351     close(CONFIG);
352     }
353    
354     sub usage {
355     my $msg=shift || '';
356    
357     if($msg) {
358     print STDERR <<"EOT";
359     $msg;
360     For further help type $::PGM -help
361 andrew.betts 50 or consult docs at http://meteorserver.org/
362 knops.gerd 11 EOT
363    
364     } else {
365    
366    
367     print STDERR <<"EOT";
368    
369 knops.gerd 45 Meteor server v$::VERSION (release date: $::RELEASE_DATE)
370 knops.gerd 11 Licensed under the terms of the GNU General Public Licence (2.0)
371    
372     Usage:
373    
374     $::PGM [-parameter [value] [-parameter [value]...]]
375    
376     Accepted command-line parameters:
377    
378     EOT
379    
380     for(my $i=0;$i<scalar(@DEFAULTS);$i+=3)
381     {
382     print STDERR "-$DEFAULTS[$i+1]\n$DEFAULTS[$i].\n\n";
383     }
384    
385     print STDERR <<"EOT";
386    
387     Any of the parameters listed above can also be configured in the
388     configuration file. The default location for this file is:
389    
390     $Defaults{'ConfigFileLocation'}
391    
392     For more information and complete documentation, see the Meteor
393 andrew.betts 50 website at http://meteorserver.org/
394 knops.gerd 11 EOT
395    
396     }
397     exit(1);
398     }
399    
400     1;
401 andrew.betts 3 ############################################################################EOF

  ViewVC Help
Powered by ViewVC 1.1.26