/[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

Contents of /googlecode.com/svn/trunk/Meteor/Config.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations)
Thu Nov 27 00:33:21 2008 UTC (10 years, 7 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 #!/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 '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 ChannelInfoTemplate => '<script>ch("~name~", ~lastMsgID~);</script>\r\n',
47
48 '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 DirectoryIndex => 'index.html',
65
66 'Footer template',
67 FooterTemplate => '</body></html>',
68
69 'Header template, ~server~, ~servertime~ and ~status~ will be replaced by the appropriate values.',
70 HeaderTemplate => 'HTTP/1.1 ~status~\r\n\r\n~channelinfo~\r\n',
71
72 'Print out this help message',
73 Help => '',
74
75 'Format to use for timestamps in debug output: unix or human',
76 LogTimeFormat => 'human',
77
78 'Maximum age of a message in seconds',
79 MaxMessageAge => 7200,
80
81 '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
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 '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
93 '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 PingInterval => 5,
95
96 'Persistence of a connection.',
97 Persist => 0,
98
99 'Message to be sent to all persistent subscriber connections (see above) every PingInterval seconds',
100 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 SubscriberShutdownMsg => '<script>eof();</script>\r\n',
110
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 '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 SubscriberDynamicPageAddress => '/push',
116
117 'The syslog facility to use',
118 SyslogFacility => 'daemon',
119
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 );
127
128 our %ConfigFileData=();
129 our %CommandLine=();
130 our %Defaults=();
131 our %Modes=();
132
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 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
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 foreach my $mode ('',keys %Modes)
159 {
160 print STDERR ($mode) ? "\r\n$mode:\r\n" : "\r\nDefaults:\r\n" if($debug);
161 foreach my $baseKey (@keys)
162 {
163 my $foundValue=0;
164 my $key=$baseKey.$mode;
165
166 if(exists($CommandLine{$key}))
167 {
168 print STDERR "CmdLine" if($debug);
169 $::CONF{$key}=$CommandLine{$key};
170 $foundValue=1;
171 }
172 elsif(exists($ConfigFileData{$key}))
173 {
174 print STDERR "CnfFile" if($debug);
175 $::CONF{$key}=$ConfigFileData{$key};
176 $foundValue=1;
177 }
178 elsif(exists($Defaults{$key}))
179 {
180 print STDERR "Default" if($debug);
181 $::CONF{$key}=$Defaults{$key};
182 $foundValue=1;
183 }
184
185 next unless($foundValue);
186
187 print STDERR "\t$baseKey\t$::CONF{$key}\n" if($debug);
188
189 # Take care of escapes
190 $::CONF{$key}=~s/\\(.)/
191 if($1 eq 'r') {
192 "\r";
193 } elsif($1 eq 'n') {
194 "\n";
195 } elsif($1 eq 's') {
196 ' ';
197 } elsif($1 eq 't') {
198 "\t";
199 } elsif($1 eq '0') {
200 "\0";
201 } else {
202 $1;
203 }
204 /gex;
205 }
206 }
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 #
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 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 my $mode='';
244
245 if($k=~s/(\.(.+))$//)
246 {
247 $mode=$2;
248 $Modes{$mode}=1;
249 }
250
251 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 $CommandLine{"$key$mode"}=1;
290
291 if($cnt>1 && $_[0]!~/^\-(?!\-)/)
292 {
293 my $param=shift;
294 $param=~s/^\-\-/\-/;
295 $CommandLine{"$key$mode"}=$param;
296 }
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 my $mode='';
313
314 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 if(/^\s*\[\s*([^\]\s]+)\s*\]\s*$/)
323 {
324 $Modes{$1}=1;
325 $mode = $1;
326 next;
327 }
328
329 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 unless(exists($Defaults{$key}))
339 {
340 &usage("Unknown configuration file parameter name '$key$mode'");
341 }
342 if($key eq 'ConfigFileLocation')
343 {
344 &usage("'ConfigFileLocation' parameter not allowed in configuration file!");
345 }
346
347 $val=~s/^--/-/;
348
349 $ConfigFileData{"$key$mode"}=$val;
350 }
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 or consult docs at http://meteorserver.org/
362 EOT
363
364 } else {
365
366
367 print STDERR <<"EOT";
368
369 Meteor server v$::VERSION (release date: $::RELEASE_DATE)
370 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 website at http://meteorserver.org/
394 EOT
395
396 }
397 exit(1);
398 }
399
400 1;
401 ############################################################################EOF

  ViewVC Help
Powered by ViewVC 1.1.26