Class: N::Sync::Handler

Inherits:
Object
  • Object
show all
Defined in:
lib/n/sync/handler.rb

Overview

Worker

Override this to create your worker.

Constant Summary collapse

SEPARATOR =
"\000"
STATUS_IDLE =
0
STATUS_RUNNING =
10
STATUS_STOPPED =
20
@@socket_timeout =

socket timeout in seconds

30
@@handler_timeout =

handler timeout in seconds

60 * 60

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server, socket) ⇒ Handler

Returns a new instance of Handler.



44
45
46
# File 'lib/n/sync/handler.rb', line 44

def initialize(server, socket)
	@server, @socket = server, socket
end

Instance Attribute Details

#serverObject (readonly)

Returns the value of attribute server.



33
34
35
# File 'lib/n/sync/handler.rb', line 33

def server
  @server
end

#statusObject

status



38
39
40
# File 'lib/n/sync/handler.rb', line 38

def status
  @status
end

#threadObject (readonly)

Returns the value of attribute thread.



35
36
37
# File 'lib/n/sync/handler.rb', line 35

def thread
  @thread
end

Instance Method Details

#broadcast(cmd) ⇒ Object

Broadcast to all handlers (clients)



184
185
186
# File 'lib/n/sync/handler.rb', line 184

def broadcast(cmd)
	@server.broadcast(cmd)
end

#broadcast_to_others(cmd) ⇒ Object

Broadcast to all other handlers (clients)



190
191
192
193
194
195
196
# File 'lib/n/sync/handler.rb', line 190

def broadcast_to_others(cmd)
	for handler in @server.handlers
		unless self == handler 
			handler.write(cmd)
		end
	end
end

#cmd_ping(args) ⇒ Object


Commands



211
212
213
214
215
216
217
# File 'lib/n/sync/handler.rb', line 211

def cmd_ping(args)
	cmd = %{<pong time="#{Time.now}"}
	cmd += %{ challenge="#{args[:challenge]}"} if args
	cmd += " />"
	
	write(cmd)
end

#error(txt) ⇒ Object



204
205
206
# File 'lib/n/sync/handler.rb', line 204

def error(txt)
	write(%|<error text="#{txt}" />|)
end

#gc!Object

called by the garbage collector.



74
75
76
# File 'lib/n/sync/handler.rb', line 74

def gc!
	@thread.raise HandlerExitException.new()
end

#handle(cmd) ⇒ Object

Generic handler.



165
166
167
168
169
170
171
172
173
174
# File 'lib/n/sync/handler.rb', line 165

def handle(cmd)
	if cmd = parse(cmd)
		$log.debug "exec: #{cmd}" if $DBG
		begin
			eval(cmd)
		rescue => ex
			$log.error ex
		end
	end
end

#info(txt) ⇒ Object




200
201
202
# File 'lib/n/sync/handler.rb', line 200

def info(txt)
	write(%|<info text="#{txt}" />|)
end

#live?Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/n/sync/handler.rb', line 112

def live?
	return Time.now < @touch_time + @@handler_timeout
end

#parse(cmd) ⇒ Object

parse the xml commnad to create a ruby method call.



148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/n/sync/handler.rb', line 148

def parse(cmd)
	return unless @status == STATUS_RUNNING
	
	cmd = REXML::Document.new(cmd).root()

	method = cmd.name().gsub(/-/, "_")
	unless cmd.attributes.empty?
		args = "(#{cmd.attributes.collect { |k, v| ":#{k.gsub(/-/, "_")} => '#{v}'" }.join(", ")})"
	else
		args = nil
	end

	return "cmd_#{method}#{args}"
end

#readObject

Read xml from the socket



118
119
120
121
122
123
124
125
126
127
128
# File 'lib/n/sync/handler.rb', line 118

def read
	return unless @status == STATUS_RUNNING
	
	cmd = nil
	
	# gmosx: no timeout here!
	cmd = @socket.gets(SEPARATOR)
	$log.debug "in: #{cmd}" if $DBG
	
	return cmd
end

#runObject



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/n/sync/handler.rb', line 78

def run
	@status = STATUS_RUNNING
	
	while (STATUS_RUNNING == @status) and (not @socket.closed?)
		begin
			unless cmd = read()
				$log.error "Client closed connection"
				@status = STATUS_IDLE
			else
				touch!
				handle(cmd.chop())
			end
		rescue HandlerExitException => ex
			@status = STATUS_IDLE
			$log.debug "Handler exit" if $DBG
		rescue Exception, StandardError => ex
			@status = STATUS_IDLE
			$log.debug ex if $DBG
		end
	end

	begin		
		stop()
	rescue Exception, StandardError => e
		# gmosx: this rescue block needed to get debug info!
		# 
		$log.error pp_exception(e)
	end
end

#send(cmd, handler) ⇒ Object

Send to another handler



178
179
180
# File 'lib/n/sync/handler.rb', line 178

def send(cmd, handler)
	handler.write(cmd)
end

#startObject



48
49
50
51
# File 'lib/n/sync/handler.rb', line 48

def start
	touch!
	@thread = Thread.new(&method("run").to_proc)
end

#stopObject



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/n/sync/handler.rb', line 53

def stop
	unless STATUS_STOPPED == @status
		@status = STATUS_STOPPED
		$log.debug "Stoping handler" if $DBG

		begin
			@socket.close()
		rescue Exception, StandardError => e
			# gmosx: this is needed to be FAULT TOLERANT
			# DRINK IT!
			$log.error "Cannot close exception when stoping handler."
		end
		
		# gmosx: why not? more FAULT TOLERANT.
		@server.handlers.delete_if {|h| STATUS_STOPPED == h.status}

	end
end

#touch!Object



108
109
110
# File 'lib/n/sync/handler.rb', line 108

def touch!
	@touch_time = Time.now()
end

#write(cmd) ⇒ Object

Write xml to the socket



132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/n/sync/handler.rb', line 132

def write(cmd)
	return unless @status == STATUS_RUNNING
	
	$log.debug "out: #{cmd}" if $DBG
	
	begin
		timeout(@@socket_timeout) { @socket << "#{cmd}#{SEPARATOR}" }
	rescue Exception, StandardError => e
		# gmosx: the socket is invalid close the handler.
		$log.error pp_exception(e)
		stop()
	end
end