Class: Marvin::Distributed::Server

Inherits:
Protocol
  • Object
show all
Defined in:
lib/marvin/distributed/server.rb

Instance Attribute Summary collapse

Attributes inherited from Protocol

#callbacks

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Protocol

#handle_enable_ssl, #handle_enabled_ssl, #handle_noop, #handle_response, #host_with_port, #receive_line, #send_message, #send_message_reply, #ssl_handshake_completed

Constructor Details

#initialize(*args) ⇒ Server



21
22
23
24
# File 'lib/marvin/distributed/server.rb', line 21

def initialize(*args)
  @configuration = args.last.is_a?(Marvin::Nash) ? args.pop : Marvin::Nash.new
  super(*args)
end

Instance Attribute Details

#configurationObject

Returns the value of attribute configuration.



19
20
21
# File 'lib/marvin/distributed/server.rb', line 19

def configuration
  @configuration
end

#processingObject

Returns the value of attribute processing.



19
20
21
# File 'lib/marvin/distributed/server.rb', line 19

def processing
  @processing
end

Class Method Details

.nextObject



149
150
151
# File 'lib/marvin/distributed/server.rb', line 149

def self.next
  @@free_connections.shift
end

.startObject



140
141
142
143
144
145
146
147
# File 'lib/marvin/distributed/server.rb', line 140

def self.start
  opts = Marvin::Settings.distributed || Marvin::Nash.new
  opts = opts.server || Marvin::Nash.new
  host = opts.host  || "0.0.0.0"
  port = (opts.port || 8943).to_i
  logger.info "Starting distributed server on #{host}:#{port} (requires authentication = #{opts.token?})"
  EventMachine.start_server(host, port, self, opts)
end

Instance Method Details

#authenticated?Boolean



127
128
129
# File 'lib/marvin/distributed/server.rb', line 127

def authenticated?
  @authenticated ||= false
end

#complete_processingObject



108
109
110
111
# File 'lib/marvin/distributed/server.rb', line 108

def complete_processing
  @@free_connections << self
  @processing = false
end

#dispatch(client, name, options) ⇒ Object



49
50
51
52
53
54
55
56
57
# File 'lib/marvin/distributed/server.rb', line 49

def dispatch(client, name, options)
  @processing = true
  send_message(:event, {
    "event-name"    => name.to_s,
    "event-options" => options,
    "client-host"   => client.host_with_port,
    "client-nick"   => client.nickname
  })
end

#fails_auth!Object



131
132
133
134
135
136
137
138
# File 'lib/marvin/distributed/server.rb', line 131

def fails_auth!
  if requires_auth?
    logger.debug "Authentication missing for distributed client"
    send_message(:unauthorized)
    close_connection_after_writing
    return true
  end
end

#handle_action(options = {}) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/marvin/distributed/server.rb', line 86

def handle_action(options = {})
  return if fails_auth!
  logger.debug "Handling action from on #{self.host_with_port}"
  target    = lookup_client_for(options["client-host"])
  action    = options["action"]
  arguments = [*options["arguments"]]
  return if target.blank? || action.blank?
  begin
    a = action.to_sym
    if self.action_whitelist.include?(a) && target.respond_to?(a)
      res = target.send(a, *arguments)
      if @callback_id.present? && res.respond_to?(:to_json)
        send_message_reply(:noop, {"return-value" => res.to_json})
      end
    else
      logger.warn "Client attempted invalid action #{a.inspect}"
    end
  rescue Exception => e
    Marvin::ExceptionTracker.log(e)
  end
end

#handle_authenticate(options = {}) ⇒ Object



59
60
61
62
63
64
65
66
67
68
# File 'lib/marvin/distributed/server.rb', line 59

def handle_authenticate(options = {})
  return unless requires_auth?
  logger.info "Attempting authentication for distributed client"
  if options["token"].present? && options["token"] == configuration.token
    @authenticated = true
    send_message(:authenticated)
  else
    send_message(:authentication_failed)
  end
end

#handle_completed(options = {}) ⇒ Object



70
71
72
73
74
# File 'lib/marvin/distributed/server.rb', line 70

def handle_completed(options = {})
  return if fails_auth!
  logger.debug "Completed message from #{self.host_with_port}"
  complete_processing
end

#handle_exception(options = {}) ⇒ Object



76
77
78
79
80
81
82
83
84
# File 'lib/marvin/distributed/server.rb', line 76

def handle_exception(options = {})
  return if fails_auth!
  logger.info "Handling exception on #{self.host_with_port}"
  name      = options["name"]
  message   = options["message"]
  backtrace = options["backtrace"]
  logger.warn "Error in remote client - #{name}: #{message}"
  [*backtrace].each { |line| logger.warn "--> #{line}" } if backtrace.present?
end

#lookup_client_for(key) ⇒ Object



117
118
119
120
121
# File 'lib/marvin/distributed/server.rb', line 117

def lookup_client_for(key)
  Marvin::IRC::Client.connections.detect do |c|
    c.host_with_port == key
  end
end

#post_connectObject



37
38
39
40
41
# File 'lib/marvin/distributed/server.rb', line 37

def post_connect
  logger.debug "Remote client available, welcoming"
  send_message(:welcome)
  complete_processing
end

#post_initObject



26
27
28
29
30
31
32
33
34
35
# File 'lib/marvin/distributed/server.rb', line 26

def post_init
  @callbacks = {}
  logger.info "Got distributed client connection with #{self.host_with_port}"
  if should_use_ssl?
    handle_enable_ssl
  else
    @connected = true
    post_connect
  end
end

#requires_auth?Boolean



123
124
125
# File 'lib/marvin/distributed/server.rb', line 123

def requires_auth?
  configuration.token? && !authenticated?
end

#start_processingObject



113
114
115
# File 'lib/marvin/distributed/server.rb', line 113

def start_processing
  @processing = true
end

#unbindObject



43
44
45
46
47
# File 'lib/marvin/distributed/server.rb', line 43

def unbind
  logger.info "Lost distributed client connection with #{self.host_with_port}"
  @@free_connections.delete(self)
  super
end