Class: Ringleader::App

Inherits:
Object
  • Object
show all
Includes:
Celluloid::IO, Celluloid::Logger
Defined in:
lib/ringleader/app.rb

Overview

A configured application.

Listens on a port, starts and runs the app process on demand, and proxies network data to the process.

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ App

Returns a new instance of App.



11
12
13
14
15
16
# File 'lib/ringleader/app.rb', line 11

def initialize(config)
  @config = config
  @process = Process.new(config)
  async.enable unless config.disabled
  start if config.run_on_load
end

Instance Method Details

#close_server_socketObject



77
78
79
80
# File 'lib/ringleader/app.rb', line 77

def close_server_socket
  @server.close if @server && !@server.closed?
  @server = nil
end

#disableObject



67
68
69
70
71
72
73
74
75
# File 'lib/ringleader/app.rb', line 67

def disable
  info "disabling #{@config.name}..."
  return unless @server
  stop_activity_timer
  @server.close
  @server = nil
  @process.stop
  @enabled = false
end

#enableObject



57
58
59
60
61
62
63
64
65
# File 'lib/ringleader/app.rb', line 57

def enable
  return if @server
  @server = TCPServer.new @config.host, @config.server_port
  @enabled = true
  async.run
rescue Errno::EADDRINUSE
  error "could not bind to #{@config.host}:#{@config.server_port} for #{@config.name}!"
  @server = nil
end

#enabled?Boolean

Returns:

  • (Boolean)


22
23
24
# File 'lib/ringleader/app.rb', line 22

def enabled?
  @enabled
end

#handle_connection(socket) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/ringleader/app.rb', line 90

def handle_connection(socket)
  _, port, host = socket.peeraddr
  debug "received connection from #{host}:#{port}"

  started = @process.start
  if started
    async.proxy_to_app socket
    reset_activity_timer
  else
    error "could not start app"
    socket.close
  end
end

#nameObject



18
19
20
# File 'lib/ringleader/app.rb', line 18

def name
  @config.name
end

#proxy(from, to) ⇒ Object



138
139
140
141
142
143
144
145
# File 'lib/ringleader/app.rb', line 138

def proxy(from, to)
  ::IO.copy_stream from, to
rescue IOError, SystemCallError
  # from or to were closed or connection was reset
ensure
  from.close unless from.closed?
  to.close unless to.closed?
end

#proxy_to_app(upstream) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
# File 'lib/ringleader/app.rb', line 104

def proxy_to_app(upstream)
  debug "proxying to #{@config.host}:#{@config.app_port}"

  downstream = TCPSocket.new(@config.host, @config.app_port)
  async.proxy downstream, upstream
  async.proxy upstream, downstream

rescue IOError, SystemCallError => e
  error "could not proxy to #{@config.host}:#{@config.app_port}: #{e}"
  upstream.close
end

#reset_activity_timerObject



126
127
128
129
# File 'lib/ringleader/app.rb', line 126

def reset_activity_timer
  start_activity_timer
  @activity_timer.reset if @activity_timer
end

#restartObject



52
53
54
55
# File 'lib/ringleader/app.rb', line 52

def restart
  stop
  start
end

#runObject



83
84
85
86
87
88
# File 'lib/ringleader/app.rb', line 83

def run
  info "listening for connections for #{@config.name} on #{@config.host}:#{@config.server_port}"
  loop { async.handle_connection @server.accept }
rescue IOError
  @server.close if @server
end

#running?Boolean

Returns:

  • (Boolean)


26
27
28
# File 'lib/ringleader/app.rb', line 26

def running?
  @process.running?
end

#startObject



30
31
32
33
34
35
36
# File 'lib/ringleader/app.rb', line 30

def start
  return if @process.running?
  info "starting #{@config.name}..."
  if @process.start
    start_activity_timer
  end
end

#start_activity_timerObject



116
117
118
119
120
121
122
123
124
# File 'lib/ringleader/app.rb', line 116

def start_activity_timer
  return if @activity_timer || @config.idle_timeout == 0
  @activity_timer = every @config.idle_timeout do
    if @process.running?
      info "#{@config.name} has been idle for #{@config.idle_timeout} seconds, shutting it down"
      @process.stop
    end
  end
end

#stop(forever = false) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/ringleader/app.rb', line 38

def stop(forever=false)
  return unless @process.running?
  info "stopping #{@config.name}..."

  if forever
    # stop processing requests
    @server.close
    @server = nil
  end

  stop_activity_timer
  @process.stop
end

#stop_activity_timerObject



131
132
133
134
135
136
# File 'lib/ringleader/app.rb', line 131

def stop_activity_timer
  if @activity_timer
    @activity_timer.cancel
    @activity_timer = nil
  end
end