torquebox-console 0.1.4 → 0.2.0

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