rsence 2.0.0.0.pre → 2.0.0.1.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/conf/argv.rb ADDED
@@ -0,0 +1,664 @@
1
+ #--
2
+ ## Riassence Framework
3
+ # Copyright 2010 Riassence Inc.
4
+ # http://riassence.com/
5
+ #
6
+ # You should have received a copy of the GNU General Public License along
7
+ # with this software package. If not, contact licensing@riassence.com
8
+ ##
9
+ #++
10
+
11
+ module RSence
12
+ def self.pid_support?
13
+ # true for non-windows
14
+ return (not ['i386-mingw32','x86-mingw32'].include?(RUBY_PLATFORM))
15
+ end
16
+ class ARGVParser
17
+
18
+ @@version = File.read( File.join( SERVER_PATH, 'VERSION' ) ).strip
19
+
20
+ if RSence.pid_support?
21
+ @@cmds = [ :run, :status, :start, :stop, :restart, :save, :setup,
22
+ :initenv, :version, :help ]
23
+ else
24
+ @@cmds = [ :run, :setup, :initenv, :version, :help ]
25
+ end
26
+
27
+ @@cmd_help = {}
28
+
29
+ @@cmd_help[:head] = <<-EOF
30
+ usage: rsence <command> [options] [args]
31
+ RSence command-line tool, version #{@@version}
32
+ EOF
33
+
34
+ @@cmd_help[:unknown] = "Unknown command: "
35
+
36
+ @@cmd_help[:help_help] = "Type 'rsence help' for usage."
37
+
38
+ @@cmd_help[:help_main] = <<-EOF
39
+ Type 'rsence help <command>' for help on a specific command.
40
+
41
+ Available commands:
42
+ #{@@cmds.map{|cmd|cmd.to_s}.join("\n ")}
43
+
44
+ EOF
45
+
46
+ @@cmd_help[:path] = <<-EOF
47
+ The [PATH] is the RSence environment to use.
48
+ The [PATH] defaults to the current working directory.
49
+
50
+ The expected structure of a project environment (where 'project_directory'
51
+ is the directory of your project) is:
52
+
53
+ [dir] project_directory :: The directory of your project.
54
+ [dir] conf :: The directory of config files.
55
+ [file] config.yaml :: The config file to load by defult.
56
+ [dir] db :: Directory containing database files.
57
+ [dir] log :: Directory containing log files.
58
+ [dir] plugins :: Directory containing installed plugins.
59
+ [dir] run :: Directory containing runtime pid files.
60
+
61
+ The 'config.yaml' file contains patches specific to your project.
62
+
63
+ The configuration files are loaded and applied in this order:
64
+ 1: [rsence_install_path]/conf/default_conf.yaml
65
+ 2: [rsence_install_path]/conf/local_conf.yaml
66
+ 3: /etc/rsence/config.yaml
67
+ 4: ~/.rsence/config.yaml
68
+ 5: [project_directory]/conf/config.yaml
69
+ 6: Any files given using --conf parameters, in order of occurrence.
70
+
71
+ The plugins directory contains the plugins installed in the project.
72
+
73
+ See also the 'setup' and 'initenv' commands.
74
+ EOF
75
+
76
+ @@cmd_help[:options] = <<-EOF
77
+ Available options:
78
+
79
+ --conf <file.yaml> Use additional config file. You can give this option
80
+ several times. The <file.yaml> is the configuration
81
+ file to load.
82
+
83
+ --debug (-d) Debug mode. Shortcut for several options useful for
84
+ developers. Not the preferred mode for production.
85
+
86
+ --verbose (-v) More verbose output. Also enabled by --debug
87
+
88
+ --log-fg (-f) Directs the output of the log messages to stdout
89
+ instead of the log files. Useful for development.
90
+
91
+ --trace-js Logs all js/json going through the msg object.
92
+
93
+ --trace-delegate Logs all plugin delegate calls.
94
+
95
+ --port <number> The port number the http server listens to.
96
+
97
+ --addr <ip address> The IP address or netmask the http server listens to.
98
+ '0.0.0.0' matches all interfaces.
99
+ '127.0.0.1' matches the local loopback interface.
100
+
101
+ --server <handler> The Rack handler to use.
102
+
103
+ --reset-sessions (-r) Resets all active sessions.
104
+
105
+ --auto-update (-a) Automatically checks for changes in installed plugin
106
+ and component bundles. Rebuilds changed component
107
+ bundles and reload changed plugin bundles.
108
+ Useful for development purposes.
109
+ Also enabled by --debug
110
+
111
+ --latency <number> Sleeps <number> amount of milliseconds on every
112
+ request. Useful for testing slow connections.
113
+
114
+ --say (-S) Uses speech synthesis via the 'say' command to
115
+ provide audible feedback, when --auto-update is
116
+ enabled. Says 'Autobuild complete.',
117
+ 'Loaded [plugin name].', 'Unloaded [plugin name].',
118
+ 'Reloaded [plugin name].', 'Reloading plugins.' and
119
+ 'Plugins reloaded.'
120
+ Only available on Mac OS X and other systems with a
121
+ 'say' command installed.
122
+
123
+ EOF
124
+
125
+ @@cmd_help[:run] = <<-EOF
126
+ usage: 'rsence run [options] [PATH]'
127
+
128
+ The 'run' command starts RSence in foreground (no daemon). Exit with CTRL-C.
129
+ This is the suggested mode for development and the only mode supported by
130
+ Windows, because Windows is missing the concept of a process ID.
131
+
132
+ #{@@cmd_help[:path]}
133
+ #{@@cmd_help[:options]}
134
+ EOF
135
+
136
+ @@cmd_help[:start] = <<-EOF
137
+ usage: 'rsence start [options] [PATH]'
138
+
139
+ The 'start' command starts RSence in the background (as a daemon).
140
+
141
+ Use the 'stop' command to stop RSence.
142
+
143
+ Use the 'restart' command to restart RSence in the background.
144
+
145
+ Use the 'status' command to check if RSence is running.
146
+
147
+ #{@@cmd_help[:path]}
148
+ #{@@cmd_help[:options]}
149
+ EOF
150
+
151
+ @@cmd_help[:stop] = <<-EOF
152
+ usage: 'rsence stop [options] [PATH]'
153
+
154
+ The 'stop' command stops RSence running in the background (as a daemon).
155
+
156
+ Use the 'status' command to check if RSence is running.
157
+
158
+ #{@@cmd_help[:path]}
159
+ #{@@cmd_help[:options]}
160
+ EOF
161
+
162
+ @@cmd_help[:restart] = <<-EOF
163
+ usage: 'rsence restart [options] [PATH]'
164
+
165
+ The 'restart' command restarts RSence in the background (as a daemon).
166
+ If RSence wasn't running before the 'restart' command was issued, the
167
+ effect is the same as 'start'.
168
+
169
+ Use the 'stop' command to stop RSence.
170
+ Use the 'status' command to check if RSence is running.
171
+
172
+ #{@@cmd_help[:path]}
173
+ #{@@cmd_help[:options]}
174
+ EOF
175
+
176
+ @@cmd_help[:status] = <<-EOF
177
+ usage: 'rsence status [options] [PATH]'
178
+
179
+ The 'status' command checks if RSence is running.
180
+ If started with the 'start', 'run' or 'restart' command, a PID file is written.
181
+ Status checks if the PID file exists, if the RSence process responds and if
182
+ the configured TCP port responds in the configured IP address.
183
+
184
+ Available options:
185
+
186
+ --conf <file.yaml> Use additional config file. You can give this option
187
+ several times. The <file.yaml> is the configuration
188
+ file to load.
189
+
190
+ --debug (-d) Debug mode. Shortcut for several options useful for
191
+ developers. Not the preferred mode for production.
192
+
193
+ --verbose (-v) More verbose output. Also enabled by --debug
194
+
195
+ --port <number> The port number the http server listens to.
196
+
197
+ --addr <ip address> The IP address or netmask the http server listens to.
198
+
199
+ #{@@cmd_help[:path]}
200
+
201
+ EOF
202
+
203
+ @@cmd_help[:tail] = <<-EOF
204
+ RSence is a self-contained rich internet application client-server framework.
205
+ For further information, see http://rsence.org/
206
+ EOF
207
+
208
+ def initialize( argv )
209
+ @argv = argv
210
+ @startable = false
211
+ parse_argv
212
+ end
213
+
214
+ def startable?; @startable; end
215
+
216
+ def parse_help_argv
217
+ if @argv.length >= 2
218
+ help_cmd = @argv[1].to_sym
219
+ else
220
+ help_cmd = :help_main
221
+ end
222
+ help( help_cmd )
223
+ exit
224
+ end
225
+
226
+ def init_args
227
+ @args = {
228
+ :env_path => Dir.pwd,
229
+ :conf_files => [ ], # --conf
230
+ :debug => false, # -d --debug
231
+ :verbose => false, # -v --verbose
232
+ :log_fg => false, # -f --log-fg
233
+ :trace_js => false, # --trace-js
234
+ :trace_delegate => false, # --trace-delegate
235
+ :port => nil, # --port
236
+ :addr => nil, # --addr --bind
237
+ :server => nil, # --server
238
+ :reset_ses => false, # -r --reset-sessions
239
+ :autoupdate => false, # -a --auto-update
240
+ :latency => 0, # --latency
241
+ :say => false, # -S --say
242
+
243
+ # client_pkg (not supported yet)
244
+ :client_pkg_no_gzip => false, # --build-no-gzip
245
+ :client_pkg_no_obfuscation => false, # --build-no-obfuscation
246
+ :client_pkg_no_whitespace_removal => false, # --build-keep-whitespace
247
+ :client_pkg_quiet => true, # --build-verbose
248
+
249
+ }
250
+ end
251
+
252
+ def parse_startup_argv
253
+ init_args
254
+ expect_option = false
255
+ option_name = false
256
+ if @argv.length >= 2
257
+ @argv[1..-1].each_with_index do |arg,i|
258
+ if expect_option
259
+ if [:port,:latency].include?(option_name) and arg.to_i.to_s != arg
260
+ puts "invalid #{option_nam.to_s}, expected number: #{arg.inspect}"
261
+ puts "Type 'rsence help #{@cmd.to_s}' for usage."
262
+ exit
263
+ elsif option_name == :conf_files
264
+ if not File.exists?( arg ) or not File.file?( arg )
265
+ puts "no such configuration file: #{arg.inspect}"
266
+ puts "Type 'rsence help #{@cmd.to_s}' for usage."
267
+ exit
268
+ else
269
+ @args[:conf_files].push( arg )
270
+ end
271
+ else
272
+ @args[option_name] = arg
273
+ end
274
+ expect_option = false
275
+ else
276
+ if arg.start_with?('--')
277
+ if arg == '--debug'
278
+ set_debug
279
+ elsif arg == '--verbose'
280
+ set_verbose
281
+ elsif arg == '--log-fg'
282
+ set_log_fg
283
+ elsif arg == '--trace-js'
284
+ @args[:trace_js] = true
285
+ elsif arg == '--trace-delegate'
286
+ @args[:trace_delegate] = true
287
+ elsif arg == '--port'
288
+ expect_option = true
289
+ option_name = :port
290
+ elsif arg == '--addr'
291
+ expect_option = true
292
+ option_name = :addr
293
+ elsif arg == '--server'
294
+ expect_option = true
295
+ option_name = :server
296
+ elsif arg == '--conf' or arg == '--config'
297
+ expect_option = true
298
+ option_name = :conf_files
299
+ elsif arg == '--reset-sessions'
300
+ set_reset_ses
301
+ elsif arg == '--auto-update'
302
+ set_autoupdate
303
+ elsif arg == '--latency'
304
+ expect_option = true
305
+ option_name = :latency
306
+ elsif arg == '--say'
307
+ set_say
308
+ else
309
+ invalid_option(arg)
310
+ end
311
+ elsif arg.start_with?('-')
312
+ arg.split('')[1..-1].each do |chr|
313
+ if chr == 'd'
314
+ set_debug
315
+ elsif chr == 'v'
316
+ set_verbose
317
+ elsif chr == 'f'
318
+ set_log_fg
319
+ elsif chr == 'r'
320
+ set_reset_ses
321
+ elsif chr == 'a'
322
+ set_autoupdate
323
+ elsif chr == 'S'
324
+ set_say
325
+ else
326
+ invalid_option(arg,chr)
327
+ end
328
+ end
329
+ elsif valid_env?(arg)
330
+ @args[:env_path] = File.expand_path(arg)
331
+ @args[:conf_files].push( File.expand_path( File.join( arg, 'conf', 'config.yaml' ) ) )
332
+ else
333
+ invalid_env( arg )
334
+ end
335
+ end
336
+ end
337
+ if expect_option
338
+ puts "no value for option #{option_name.to_s.inspect}"
339
+ puts "Type 'rsence help #{@cmd.to_s} for usage."
340
+ exit
341
+ end
342
+ end
343
+ if valid_env?(@args[:env_path])
344
+ conf_file = File.expand_path( File.join( @args[:env_path], 'conf', 'config.yaml' ) )
345
+ @args[:conf_files].push( conf_file ) unless @args[:conf_files].include?( conf_file )
346
+ else
347
+ puts "invalid environment."
348
+ exit
349
+ end
350
+ @startable = true
351
+ end
352
+
353
+ def set_debug
354
+ @args[:debug] = true
355
+ @args[:verbose] = true
356
+ @args[:autoupdate] = true
357
+ @args[:client_pkg_quiet] = false
358
+ end
359
+ def set_verbose
360
+ @args[:verbose] = true
361
+ end
362
+ def set_log_fg
363
+ @args[:log_fg] = true
364
+ end
365
+ def set_reset_ses
366
+ @args[:reset_ses] = true
367
+ end
368
+ def set_autoupdate
369
+ @args[:autoupdate] = true
370
+ end
371
+ def set_say
372
+ @args[:say] = true
373
+ end
374
+
375
+ def valid_env?( arg )
376
+ path = File.expand_path( arg )
377
+ if not File.exists?( path )
378
+ puts "no such directory: #{path.inspect}"
379
+ return false
380
+ elsif not File.directory?( path )
381
+ puts "not a directory: #{path.inspect}"
382
+ return false
383
+ end
384
+ conf_path = File.join( path, 'conf' )
385
+ if not File.exists?( conf_path )
386
+ puts "no conf directory, expected: #{conf_path.inspect}"
387
+ return false
388
+ elsif not File.directory?( conf_path )
389
+ puts "not a conf directory, expected: #{conf_path.inspect}"
390
+ return false
391
+ end
392
+ conf_file = File.join( path, 'conf', 'config.yaml' )
393
+ if not File.exists?(conf_file)
394
+ puts "missing conf file, expected: #{conf_file.inspect}"
395
+ return false
396
+ elsif not File.file?( conf_file )
397
+ puts "conf file not a file, expected: #{conf_file.inspect}"
398
+ return false
399
+ end
400
+ plugin_path = File.join( path, 'plugins' )
401
+ if not File.exists?( plugin_path )
402
+ warn "Warning; no plugin directory in project, expected: #{plugin_path.inspect}" if @args[:verbose]
403
+ elsif not File.directory?( plugin_path )
404
+ puts "plugin directory not a directory, expected: #{plugin_path.inspect}"
405
+ return false
406
+ end
407
+ run_path = File.join( path, 'run' )
408
+ unless File.exists?( run_path )
409
+ warn "Warning: no run directory: Creating #{run_path.inspect}" if @args[:verbose]
410
+ Dir.mkdir( run_path )
411
+ end
412
+ log_path = File.join( path, 'log' )
413
+ unless File.exists?( log_path )
414
+ warn "Warning: no log directory: Creating #{log_path.inspect}" if @args[:verbose]
415
+ Dir.mkdir( log_path )
416
+ end
417
+ db_path = File.join( path, 'db' )
418
+ unless File.exists?( db_path )
419
+ warn "Warning: no db directory: Creating #{db_path.inspect}" if @args[:verbose]
420
+ Dir.mkdir( db_path )
421
+ end
422
+ return true
423
+ end
424
+
425
+ def invalid_env( arg )
426
+ puts "invalid environment: #{arg.inspect}"
427
+ puts "Type 'rsence help #{@cmd.to_s}' for usage."
428
+ puts "Type 'rsence help initenv' for environment initialization usage."
429
+ exit
430
+ end
431
+
432
+ def invalid_option(arg,chr=false)
433
+ if not chr
434
+ puts "invalid option: #{arg.inspect}"
435
+ else
436
+ puts "invalid option character #{chr.inspect} in option character block #{arg.inspect}"
437
+ end
438
+ puts "Type 'rsence help #{@cmd.to_s}' for usage."
439
+ exit
440
+ end
441
+
442
+ def test_port( port, addr='127.0.0.1' )
443
+ require 'socket'
444
+ begin
445
+ sock = TCPsocket.open( addr, port )
446
+ sock.close
447
+ return true
448
+ rescue Errno::ECONNREFUSED
449
+ return false
450
+ end
451
+ end
452
+
453
+ def parse_status_argv
454
+ init_args
455
+ expect_option = false
456
+ option_name = false
457
+ if @argv.length >= 2
458
+ @argv[1..-1].each_with_index do |arg,i|
459
+ if expect_option
460
+ if [:port,:latency].include?(option_name) and arg.to_i.to_s != arg
461
+ puts "invalid #{option_nam.to_s}, expected number: #{arg.inspect}"
462
+ puts "Type 'rsence help #{@cmd.to_s}' for usage."
463
+ exit
464
+ elsif option_name == :conf_files
465
+ if not File.exists?( arg ) or not File.file?( arg )
466
+ puts "no such configuration file: #{arg.inspect}"
467
+ puts "Type 'rsence help #{@cmd.to_s}' for usage."
468
+ exit
469
+ else
470
+ @args[:conf_files].push( arg )
471
+ end
472
+ else
473
+ @args[option_name] = arg
474
+ end
475
+ expect_option = false
476
+ else
477
+ if arg.start_with?('--')
478
+ if arg == '--debug'
479
+ set_debug
480
+ elsif arg == '--verbose'
481
+ set_verbose
482
+ elsif arg == '--port'
483
+ expect_option = true
484
+ option_name = :port
485
+ elsif arg == '--addr'
486
+ expect_option = true
487
+ option_name = :addr
488
+ elsif arg == '--server'
489
+ expect_option = true
490
+ option_name = :server
491
+ elsif arg == '--conf' or arg == '--config'
492
+ expect_option = true
493
+ option_name = :conf_files
494
+ else
495
+ invalid_option(arg)
496
+ end
497
+ elsif arg.start_with?('-')
498
+ arg.split('')[1..-1].each do |chr|
499
+ if chr == 'd'
500
+ set_debug
501
+ elsif chr == 'v'
502
+ set_verbose
503
+ else
504
+ invalid_option(arg,chr)
505
+ end
506
+ end
507
+ elsif valid_env?(arg)
508
+ @args[:env_path] = File.expand_path(arg)
509
+ @args[:conf_files].push( File.expand_path( File.join( arg, 'conf', 'config.yaml' ) ) )
510
+ else
511
+ invalid_env( arg )
512
+ end
513
+ end
514
+ end
515
+ if expect_option
516
+ puts "no value for option #{option_name.to_s.inspect}"
517
+ puts "Type 'rsence help #{@cmd.to_s} for usage."
518
+ exit
519
+ end
520
+ end
521
+ if valid_env?(@args[:env_path])
522
+ conf_file = File.expand_path( File.join( @args[:env_path], 'conf', 'config.yaml' ) )
523
+ @args[:conf_files].push( conf_file ) unless @args[:conf_files].include?( conf_file )
524
+ else
525
+ puts "invalid environment."
526
+ exit
527
+ end
528
+ require 'conf/default'
529
+ config = Configuration.new(@args).config
530
+ # require 'daemon/daemon'
531
+ # puts "status: #{HTTPDaemon.daemonize.inspect}"
532
+ port = config[:http_server][:port]
533
+ addr = config[:http_server][:bind_address]
534
+ port_status = test_port( port, addr )
535
+ # port_msg = port_status ? 'responds' : 'does not respond'
536
+ # puts "TCP status: #{addr}:#{port} #{port_msg}" if @args[:verbose]
537
+ if RSence.pid_support?
538
+ pid_fn = config[:daemon][:pid_fn]
539
+ if File.exists?( pid_fn )
540
+ pid = File.read( pid_fn ).to_i
541
+ begin
542
+ pid_status = Process.kill('USR2',pid)
543
+ rescue Errno::ESRCH
544
+ pid_status = false
545
+ end
546
+ # pid_msg = pid_status == false ? 'not running' : 'responds'
547
+ # puts "process id (#{pid}) #{pid_msg}" if @args[:verbose]
548
+ else
549
+ puts "no PID file, unable to check process status" if @args[:verbose]
550
+ pid_status = nil
551
+ end
552
+ else
553
+ puts "no PID support, unable to check process status" if @args[:verbose]
554
+ pid_status = nil
555
+ end
556
+ if port_status
557
+ puts "TCP response from #{addr} port #{port}"
558
+ else
559
+ puts "No TCP response from #{addr} port #{port}."
560
+ end
561
+ if RSence.pid_support?
562
+ if pid_status == nil
563
+ puts "No process id, unable to check process status."
564
+ elsif pid_status == false
565
+ puts "No process running."
566
+ else
567
+ puts "Process id #{pid} responded with signal #{pid_status}."
568
+ end
569
+ end
570
+ end
571
+
572
+ def parse_save_argv
573
+ throw "parse_save_argv not implemented!"
574
+ end
575
+
576
+ def parse_setup_argv
577
+ throw "parse_setup_argv not implemented!"
578
+ end
579
+
580
+ def parse_initenv_argv
581
+ throw "parse_initenv_argv not implemented!"
582
+ end
583
+
584
+ def parse_argv
585
+ if @argv.empty?
586
+ puts @@cmd_help[:help_help]
587
+ exit
588
+ else
589
+ cmd = @argv[0].to_sym
590
+ cmd = :help if [:h, :'-h', :'--help', :'-help'].include? cmd
591
+ end
592
+ if @@cmds.include?(cmd)
593
+ @cmd = cmd
594
+ if cmd == :help
595
+ parse_help_argv
596
+ elsif cmd == :version
597
+ version
598
+ exit
599
+ elsif [:run,:start,:stop,:restart].include? cmd
600
+ parse_startup_argv
601
+ elsif cmd == :status
602
+ parse_status_argv
603
+ elsif cmd == :save
604
+ parse_save_argv
605
+ elsif cmd == :setup
606
+ parse_setup_argv
607
+ elsif cmd == :initenv
608
+ parse_initenv_argv
609
+ end
610
+ else
611
+ puts @@cmd_help[:unknown] + cmd.to_s.inspect
612
+ puts @@cmd_help[:help_help]
613
+ exit
614
+ end
615
+ end
616
+
617
+ def help( cmd )
618
+ cmd.to_sym! if cmd.class != Symbol
619
+ puts @@cmd_help[:head]
620
+ if @@cmd_help.has_key?(cmd)
621
+ puts @@cmd_help[cmd]
622
+ else
623
+ puts @@cmd_help[:help_main]
624
+ end
625
+ puts @@cmd_help[:tail]
626
+ end
627
+
628
+ def version
629
+ puts @@version
630
+ end
631
+
632
+ def cmd
633
+ @cmd
634
+ end
635
+
636
+ def args
637
+ @args
638
+ end
639
+
640
+ end
641
+
642
+ @@argv_parser = ARGVParser.new( ARGV )
643
+
644
+ def self.argv; @@argv_parser; end
645
+ def self.cmd; @@argv_parser.cmd; end
646
+ def self.args; @@argv_parser.args; end
647
+ def self.startable?; @@argv_parser.startable?; end
648
+ def self.startup
649
+ puts "Loading configuration..." if self.args[:verbose]
650
+ # Use the default configuration:
651
+ require 'conf/default'
652
+ @@config = Configuration.new(self.args).config
653
+ def self.config
654
+ @@config
655
+ end
656
+ ## Riassence Daemon controls
657
+ require 'daemon/daemon'
658
+ puts "Starting RSence..." if self.args[:verbose]
659
+ daemon = HTTPDaemon.new
660
+ daemon.daemonize!
661
+ end
662
+
663
+ end
664
+