torquebox-console 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,9 +1,7 @@
1
1
  source :rubygems
2
2
 
3
- gem "pry", "~>0.9.10"
4
- gem "torquebox", "~>2.0"
5
- gem "sinatra", "~>1.3.3"
6
- gem "haml", "~>3.1.7"
7
- gem "stomp", "~>1.2.6"
8
- gem "thor", "~>0.14.6"
3
+ gemspec
9
4
 
5
+ group :development do
6
+ gem "jruby-openssl"
7
+ end
data/README.md CHANGED
@@ -16,3 +16,18 @@ First deploy to a TorqueBox server.
16
16
  Then you can connect with a web browser at
17
17
  `http://<servername>:<portnumber>/console`, or on the command line with
18
18
  `tbconsole connect`.
19
+
20
+ To list and connect to other running applications, use the commands:
21
+
22
+ list_applications
23
+ list_runtimes
24
+ switch_application(app)
25
+ switch_runtime(app, runtime)
26
+
27
+ The `switch_application` command is just a shortcut for
28
+ `switch_runtime(app, 'web')` since the web runtime is the most
29
+ commonly used.
30
+
31
+ The console, especially runtime switching, is still pretty
32
+ experimental so don't go doing anything crazy with it in a production
33
+ environment.
data/TODO CHANGED
@@ -1,5 +1,4 @@
1
1
  * Destroy queues on disconnect
2
- * Figure out how to attach to other runtimes
3
2
  * multi-line input
4
3
  * Add auth if necessasry
5
4
  * Implement additional helper methods in Builtin, e.g. clear_cache
@@ -10,3 +9,4 @@
10
9
  * [done] Make web UI auto scroll
11
10
  * [done] Ensure the client unsubscribes
12
11
  * [done] escape angle brackets in the html
12
+ * [done] Figure out how to attach to other runtimes
data/bin/tbconsole CHANGED
@@ -25,51 +25,32 @@ class TorqueBoxConsoleCommand < Thor
25
25
 
26
26
  DEPLOYMENT_NAME = 'torquebox-console-knob.yml'
27
27
 
28
- desc "deploy --dir=<deploy_dir> [--secure=username:password[,username:password]*]",
29
- <<-EOT
28
+ desc "deploy --dir=DIR", <<-EOT
30
29
  Writes the torquebox-console application to disk in the directory specified by
31
- --dir, and deploys the app to the TorqueBox instance specified by ENV['TORQUEBOX_HOME']
32
- (currently #{ENV['TORQUEBOX_HOME']}).
30
+ --dir, and deploys the app to the TorqueBox instance detected on the local host,
31
+ (currently #{TorqueBox::DeployUtils.torquebox_home}).
33
32
 
34
33
  If --dir is not provided, the torquebox-console app will be written to Dir.pwd/torquebox-console
35
34
  (currently #{Dir.pwd}/torquebox-console).
36
-
37
35
  EOT
38
- method_option :secure, :type => :hash, :default => nil
39
36
  method_option :dir, :type => :string, :default => "#{Dir.pwd}/torquebox-console"
40
37
  def deploy
41
38
  check
42
39
  deploy_dir = File.expand_path options[:dir]
43
40
  descriptor = TorqueBox::DeployUtils.basic_deployment_descriptor( :root => deploy_dir,
44
41
  :env => 'production' )
45
- if options[:secure]
46
- descriptor['environment']['REQUIRE_AUTHENTICATION'] = true
47
- descriptor['auth'] = {'console' => {'domain'=>'torquebox-torquebox-console', 'credentials'=>{}}}
48
- options[:secure].each do |user, pass|
49
- descriptor['auth']['console']['credentials'][user] = pass
50
- end
51
- puts ">> Wrote user/password entries to TorqueBox::Console deployment descriptor"
52
- else
53
- puts ">> WARNING: deploying TorqueBox::Console with no security - use the --secure=username:password option to secure it"
54
- end
55
-
56
- unless File.exist?( deploy_dir )
57
- puts ">> Creating torquebox-console app directory #{deploy_dir}."
58
- Dir.mkdir( deploy_dir )
59
- end
42
+ Dir.mkdir( deploy_dir ) unless File.exist?( deploy_dir )
60
43
  puts "Copying torquebox-console app to #{deploy_dir}"
61
44
  files = Dir.glob("#{root_dir}/*") - ["#{root_dir}/bin"]
62
- FileUtils.cp_r( files, "#{deploy_dir}/", :verbose=>true )
45
+ FileUtils.cp_r( files, "#{deploy_dir}/" )
63
46
  name, dir = TorqueBox::DeployUtils.deploy_yaml( descriptor, :name => DEPLOYMENT_NAME )
64
- puts ">> Deployed #{deploy_dir} as #{name} to #{dir}/#{name}"
47
+ puts ">> Deployed to #{dir}/#{name}"
65
48
  end
66
49
 
67
50
  desc "undeploy", "Undeploys TorqueBox::Console from the TorqueBox instance specified by $TORQUEBOX_HOME"
68
51
  def undeploy
69
52
  check
70
53
  name, dir = TorqueBox::DeployUtils.undeploy_yaml( :name => DEPLOYMENT_NAME )
71
-
72
- puts ">> Undeployed #{name} from #{dir}" if name
73
54
  end
74
55
 
75
56
  desc "connect", "Runs the CLI console"
@@ -79,16 +60,13 @@ EOT
79
60
 
80
61
  protected
81
62
  def check
82
- raise Exception.new("$TORQUEBOX_HOME must be set") unless ENV['TORQUEBOX_HOME']
63
+ if !TorqueBox::DeployUtils.torquebox_home
64
+ raise Exception.new("Can't find a local TorqueBox instance. Try setting TORQUEBOX_HOME.")
65
+ end
83
66
  end
84
67
 
85
68
  def root_dir
86
- _root_dir_ = File.expand_path( File.join( File.dirname( __FILE__ ), '..' ) )
87
- if _root_dir_ =~/\.rvm/
88
- $stderr.puts "It looks like you're using RVM for your JRuby."
89
- $stderr.puts "TorqueBox has some trouble with load paths with an '@'."
90
- end
91
- _root_dir_
69
+ File.expand_path( File.join( File.dirname( __FILE__ ), '..' ) )
92
70
  end
93
71
  end
94
72
 
data/console.rb CHANGED
@@ -1,6 +1,28 @@
1
+ require 'torquebox'
2
+ require 'torquebox-stomp'
1
3
  require 'sinatra'
2
4
  require 'haml'
3
5
 
6
+ class Sinatra::Application
7
+ include TorqueBox::Injectors
8
+ end
9
+
10
+ helpers do
11
+ def endpoint
12
+ unless @endpoint
13
+ @endpoint = fetch('stomp-endpoint')
14
+ # Workaround for https://issues.jboss.org/browse/TORQUE-957
15
+ if @endpoint =~ /default-host/
16
+ @endpoint.gsub!(/default-host/, "localhost")
17
+ @endpoint.gsub!(/\/console\/console/, "")
18
+ end
19
+ @endpoint
20
+ end
21
+ @endpoint
22
+ end
23
+ end
24
+
4
25
  get '/' do
5
26
  haml :index, :format => :html5
6
27
  end
28
+
@@ -12,32 +12,39 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'torquebox'
16
-
17
15
  module TorqueBox
18
16
  module Console
19
17
  module Builtin
20
18
  extend TorqueBox::Injectors
21
19
  class << self
22
- def service_registry
23
- @@service_registry ||= inject("service-registry")
20
+
21
+ # Simple placeholder methods - the stomplet is responsible
22
+ # for actually switching runtimes
23
+ def switch_application(app)
24
+ switch_runtime(app, 'web')
25
+ end
26
+ def switch_runtime(app, runtime)
27
+ [app, runtime]
24
28
  end
25
29
 
26
- def list_runtimes
27
- get_runtimes.each do |runtime|
28
- puts "Application: #{runtime[0]}"
29
- puts "Pool: #{runtime[1]}"
30
- end
30
+ def list_applications
31
+ list_runtimes.map { |runtimes| runtimes.first }.uniq
31
32
  end
32
33
 
33
- def get_runtimes
34
- service_registry.service_names.to_a.map { |x| parse_pool_name(x) }.reject(&:nil?)
34
+ def list_runtimes
35
+ service_registry = inject("service-registry")
36
+ service_registry.service_names.to_a.map { |x| parse_pool_name(x) }.
37
+ reject(&:nil?).map { |app, runtime, svc_name| [app, runtime] }.sort
35
38
  end
36
39
 
37
40
  def parse_pool_name(service_name)
38
41
  [$1, $3, service_name] if service_name.canonical_name =~
39
42
  /"(.*)(-knob\.yml|\.knob)"\.torquebox\.core\.runtime\.pool\.([^.]+)$/
40
43
  end
44
+
45
+ def create_block
46
+ Proc.new {}
47
+ end
41
48
  end
42
49
  end
43
50
  end
@@ -22,12 +22,13 @@ module TorqueBox
22
22
  HOSTS = [{:host => "localhost", :port => 8675}]
23
23
  PARAMS = { :connect_headers => HEADERS, :hosts => HOSTS, :max_reconnect_attempts => -1 }
24
24
 
25
- attr_accessor :client
25
+ attr_accessor :client, :closed
26
26
 
27
27
  def initialize
28
+ @closed = false
28
29
  @client = Stomp::Client.new( PARAMS )
29
30
  rescue Stomp::Error::MaxReconnectAttempts
30
- puts "Can't connect to TorqueBox. Are you sure the server is running?"
31
+ puts "Cannot connect to TorqueBox. Are you sure the server is running?"
31
32
  end
32
33
 
33
34
  def self.connect
@@ -36,17 +37,36 @@ module TorqueBox
36
37
 
37
38
  def run
38
39
  if client
39
- client.subscribe("/stomplet/console") do |msg|
40
- !msg.headers['prompt'] && puts(msg.body)
40
+ trap("INT") {
41
+ @closed = true
42
+ puts ""
43
+ puts "Disconnecting console, press enter to exit"
44
+ }
45
+ prompt = "TorqueBox> "
46
+ received_prompt = false
47
+ client.subscribe("/stomplet/console") do |msg|
48
+ if msg.headers['prompt']
49
+ prompt = msg.body
50
+ received_prompt = true
51
+ else
52
+ puts msg.body
53
+ end
41
54
  end
42
55
  # Since our messaging is async, sleep
43
56
  # before displaying the prompt
44
- sleep 0.3
45
- while(input = Readline.readline( "TorqueBox> ", true ))
46
- client.publish("/stomplet/console", input)
47
- sleep 0.3 # again with the async
57
+ while !received_prompt && !closed
58
+ sleep 0.05
59
+ end
60
+ while !closed && (input = Readline.readline( prompt, true ))
61
+ received_prompt = false
62
+ client.publish("/stomplet/console", input) unless closed
63
+ while !received_prompt && !closed
64
+ sleep 0.05 # again with the async
65
+ end
48
66
  end
49
67
  client.unsubscribe('/stomplet/console')
68
+ # Hide any errors printed after we've unsubscribed
69
+ $stderr.close
50
70
  end
51
71
  end
52
72
  end
@@ -13,32 +13,26 @@
13
13
  # limitations under the License.
14
14
 
15
15
  require 'pry'
16
- require 'torquebox-stomp'
17
- require 'torquebox-cache'
18
- require 'torquebox-messaging'
19
16
 
20
17
  module TorqueBox
21
18
  module Console
22
19
  class Server
23
20
 
24
- attr_accessor :input_queue, :output_queue, :console_id
21
+ attr_accessor :input_queue, :output_queue, :console_id, :application, :runtime
25
22
 
26
- def initialize
27
- @cache = TorqueBox::Infinispan::Cache.new(:name=>"torquebox-console")
28
- @console_id = @cache.increment( "console" )
29
-
30
- input_name = "/queues/torquebox-console/#{console_id}-input"
31
- output_name = "/queues/torquebox-console/#{console_id}-output"
32
-
33
- @input_queue = TorqueBox::Messaging::Queue.start( input_name, :durable => false )
34
- @output_queue = TorqueBox::Messaging::Queue.start( output_name, :durable => false )
23
+ def initialize(console_id, input_queue, output_queue, application, runtime)
24
+ @console_id = console_id
25
+ @input_queue = input_queue
26
+ @output_queue = output_queue
27
+ @application = application
28
+ @runtime = runtime
35
29
  end
36
30
 
37
31
  def run( entry_point )
38
- Thread.new do
32
+ Thread.new do
39
33
  Pry.config.pager = false
40
34
  #Pry.config.color = false
41
- Pry.config.prompt = proc { "TorqueBox> " }
35
+ Pry.config.prompt = proc { "TorqueBox (#{application}, #{runtime})> " }
42
36
  Pry.start entry_point, :input => self, :output => self
43
37
  end
44
38
  end
@@ -56,6 +50,11 @@ module TorqueBox
56
50
  output_queue.publish output.to_s
57
51
  end
58
52
 
53
+ def evaluate( code )
54
+ binding = TorqueBox::Console::Builtin.create_block.binding
55
+ eval( code, binding )
56
+ end
57
+
59
58
  # Pry (undocumented?) requires this
60
59
  def tty?
61
60
  false
@@ -1,5 +1,5 @@
1
1
  module TorqueBox
2
2
  module Console
3
- VERSION = "0.1.4"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
data/public/ansispan.js CHANGED
@@ -13,7 +13,7 @@ var ansispan = function (str) {
13
13
  ).replace(
14
14
  new RegExp('\033\\[1;' + ansi + 'm', 'g'),
15
15
  '<span style="color: ' + ansispan.brightForegroundColors[ansi] + '">'
16
- );
16
+ ).replace( new RegExp('\033\\[4m', 'g'), '<span style="text-decoration: underline">' );
17
17
  });
18
18
  //
19
19
  // `\033[1m` enables bold font, `\033[22m` disables it or \033[0m` resets
@@ -21,6 +21,7 @@ var ansispan = function (str) {
21
21
  str = str.replace(/\033\[1m/g, '<b>').replace(/\033\[22m/g, '</b>');
22
22
  str = str.replace(/\033\[1m/g, '<b>').replace(/\033\[0m/g, '</b>');
23
23
 
24
+
24
25
  //
25
26
  // `\033[3m` enables italics font, `\033[23m` disables it or \033[0m resets
26
27
  //
data/public/console.js CHANGED
@@ -1,5 +1,14 @@
1
1
  $().ready( function() {
2
- client = Stomp.client( "ws://localhost:8675" )
2
+ if (endpoint == null) {
3
+ // endpoint should be set in index.haml
4
+ // value provided by torquebox injection
5
+ // but if for whatever reason that doesn't
6
+ // work, we'll try this
7
+ endpoint = "ws://localhost:8675"
8
+ } else {
9
+ alert( "Using: " + endpoint )
10
+ }
11
+ client = Stomp.client( endpoint )
3
12
 
4
13
  var display_message = function( message ) {
5
14
  elem = $("#console .content")
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require 'torquebox-cache'
16
+ require 'torquebox-messaging'
15
17
  require 'torquebox-stomp'
16
18
  require 'torquebox-console'
17
19
 
@@ -20,40 +22,129 @@ class TorqueBoxConsole < TorqueBox::Stomp::JmsStomplet
20
22
  def configure( options )
21
23
  super
22
24
  @servers = {}
25
+ @server_runtimes = {}
26
+ @cache = TorqueBox::Infinispan::Cache.new(:name=>"torquebox-console")
23
27
  end
24
28
 
25
29
  def on_message( message, session )
26
- server = @servers[session["console_id"]]
27
- if server
28
- send_to( server.input_queue, message.content_as_string )
30
+ console_id = session["console_id"]
31
+ input = message.content_as_string
32
+ servers = @servers[console_id]
33
+ if servers
34
+ server = servers.last
35
+ # Intercept the switch runtime commands
36
+ if input =~ /^\s*(switch_application|switch_runtime)\s*\(.+\)$/
37
+ app, runtime = server.evaluate( input )
38
+ switch_runtime( app, runtime, console_id )
39
+ output_queue = TorqueBox::Messaging::Queue.new( output_name( console_id ) )
40
+ send_to( output_queue, "Switched to #{runtime} runtime of #{app} application" )
41
+ else
42
+ input_queue = TorqueBox::Messaging::Queue.new( server.input_queue.name )
43
+ send_to( input_queue, input )
44
+ end
29
45
  else
30
- logger.error("No console found for the server #{server}")
46
+ logger.error("No server found for console #{console_id}")
31
47
  end
32
48
  end
33
49
 
34
50
  def on_subscribe( subscriber )
35
- # Create a new server that sends/receives on the queue
36
- server = TorqueBox::Console::Server.new
51
+ console_id = @cache.increment( "console" )
52
+ output_queue = TorqueBox::Messaging::Queue.start( output_name( console_id ), :durable => false )
37
53
 
38
- # Keep a reference to it around for a while
39
- console_id = server.console_id
40
- @servers[console_id] = server
41
-
42
- # Make sure we can find the server using session
54
+ # Make sure we can find the console using session
43
55
  subscriber.session["console_id"] = console_id
44
56
  logger.info "Running TorqueBox console #{console_id}."
45
57
 
46
- # Subscribe our stomplet connection to the server's queue
47
- subscribe_to( subscriber, server.output_queue )
48
- server.run( TorqueBox::Console::Builtin )
58
+ # Subscribe our stomplet connection to the server's queue
59
+ subscribe_to( subscriber, output_queue )
60
+
61
+ # start the console against the current app
62
+ switch_runtime( ENV['TORQUEBOX_APP_NAME'], 'web', console_id )
49
63
  end
50
-
64
+
51
65
  def on_unsubscribe( subscriber )
52
66
  session = subscriber.session
53
67
  logger.info "Closing TorqueBox console #{session["console_id"]}"
54
68
  @servers.delete( session["console_id"] )
55
69
  end
56
70
 
71
+ def output_name(console_id)
72
+ "/queues/torquebox-console/#{console_id}-output"
73
+ end
74
+
75
+ def switch_runtime(app, runtime, console_id)
76
+ runtime ||= 'web'
77
+ @server_runtimes[console_id] ||= {}
78
+ @server_runtimes[console_id][app] ||= {}
79
+ existing_server = @server_runtimes[console_id][app][runtime]
80
+ if existing_server
81
+ # shuffle the desired runtime to the current one
82
+ @servers[console_id] << @servers[console_id].delete( existing_server )
83
+ input_queue = TorqueBox::Messaging::Queue.new( existing_server.input_queue.name )
84
+ send_to( input_queue, "" )
85
+ else
86
+ pool = lookup_runtime( app, runtime )
87
+ dependencies = Gem::Specification.find_by_name('pry').runtime_dependencies.map(&:name)
88
+ dependencies << 'pry'
89
+ load_paths = $:.select do |path|
90
+ dependencies.any? { |dep| path.include?(dep) }
91
+ end
92
+ load_paths << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
93
+ load_paths.each do |path|
94
+ pool.evaluate(%Q{$: << '#{path}' unless $:.include?('#{path}')})
95
+ end
96
+ pool.evaluate("require 'torquebox/console/server'")
97
+ pool.evaluate("require 'torquebox/console/builtin'")
98
+
99
+ server_id = Time.now.to_f.to_s
100
+ input_name = "/queues/torquebox-console/#{console_id}-#{server_id}-input"
101
+ output_name = output_name( console_id )
102
+
103
+ server = pool.evaluate( """
104
+ input_queue = TorqueBox::Messaging::Queue.start( '#{input_name}', :durable => false )
105
+ output_queue = TorqueBox::Messaging::Queue.new( '#{output_name}' )
106
+ server = TorqueBox::Console::Server.new( #{console_id}, input_queue, output_queue, '#{app}', '#{runtime}' )
107
+ server.run( TorqueBox::Console::Builtin )
108
+ server
109
+ """ )
110
+ @server_runtimes[console_id][app][runtime] = server
111
+ @servers[console_id] ||= []
112
+ @servers[console_id] << server
113
+ end
114
+ end
115
+
116
+ def web_runtime(app)
117
+ lookup_runtime(app, 'web')
118
+ end
119
+
120
+ def lookup_runtime(app, name)
121
+ service_registry = inject('service-registry')
122
+ service_name = nil
123
+
124
+ if app
125
+ _, _, service_name = list_runtimes.detect { |v| v[0] == app && v[1] == name }
126
+ else
127
+ unit = inject('deployment-unit')
128
+ service_name = org.torquebox.core.as.CoreServices.runtimePoolName(unit, name)
129
+ end
130
+
131
+ return nil unless service_name
132
+ service_controller = service_registry.get_service(service_name)
133
+ return nil unless service_controller
134
+ pool = service_controller.service.value
135
+ pool
136
+ end
137
+
138
+ def list_runtimes
139
+ service_registry = inject("service-registry")
140
+ service_registry.service_names.to_a.map { |x| parse_pool_name(x) }.reject(&:nil?)
141
+ end
142
+
143
+ def parse_pool_name(service_name)
144
+ [$1, $3, service_name] if service_name.canonical_name =~
145
+ /"(.*)(-knob\.yml|\.knob)"\.torquebox\.core\.runtime\.pool\.([^.]+)$/
146
+ end
147
+
57
148
  def logger
58
149
  @logger ||= TorqueBox::Logger.new( self )
59
150
  end
data/views/index.haml CHANGED
@@ -1,6 +1,8 @@
1
1
  !!!
2
2
  %html
3
3
  %head
4
+ %script{ :type => "text/javascript" }
5
+ = "var endpoint = '#{endpoint}'"
4
6
  %script{ :type => "text/javascript",
5
7
  :src => "https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" }
6
8
  %script{ :type => "text/javascript",
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: torquebox-console
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.4
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Lance Ball
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-10-16 00:00:00 Z
13
+ date: 2012-12-04 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: pry
@@ -61,7 +61,7 @@ dependencies:
61
61
  version_requirements: &id005 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
- - - ~>
64
+ - - ">="
65
65
  - !ruby/object:Gem::Version
66
66
  version: 0.14.6
67
67
  requirement: *id005
@@ -134,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
134
  requirements: []
135
135
 
136
136
  rubyforge_project:
137
- rubygems_version: 1.8.24
137
+ rubygems_version: 1.8.15
138
138
  signing_key:
139
139
  specification_version: 3
140
140
  summary: TorqueBox Console - A REPL commandline and information viewer for TorqueBox