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_response, #host_with_port, #receive_line, #send_message

Constructor Details

#initialize(*args) ⇒ Server

Returns a new instance of 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

#using_tlsObject

Returns the value of attribute using_tls.



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

def using_tls
  @using_tls
end

Class Method Details

.nextObject



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

def self.next
  @@free_connections.shift
end

.startObject



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

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

Returns:

  • (Boolean)


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

def authenticated?
  @authenticated ||= false
end

#complete_processingObject



103
104
105
106
# File 'lib/marvin/distributed/server.rb', line 103

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

#dispatch(client, name, options) ⇒ Object



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

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



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

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



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

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

#handle_authenticate(options = {}) ⇒ Object



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

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



68
69
70
71
72
# File 'lib/marvin/distributed/server.rb', line 68

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

#handle_exception(options = {}) ⇒ Object



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

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



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

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

#post_initObject



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

def post_init
  super
  @callbacks = {}
  logger.info "Got distributed client connection with #{self.host_with_port}"
  if should_use_tls?
    start_tls
  else
    complete_processing
  end
end

#requires_auth?Boolean

Returns:

  • (Boolean)


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

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

#should_use_tls?Boolean

Returns:

  • (Boolean)


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

def should_use_tls?
  @using_tls ||= configuration.encrypted?
end

#ssl_handshake_completedObject



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

def ssl_handshake_completed
  complete_processing if should_use_tls?
end

#start_processingObject



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

def start_processing
  @processing = true
end

#unbindObject



41
42
43
44
45
# File 'lib/marvin/distributed/server.rb', line 41

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