Class: Anorexic::BasicService

Inherits:
Object
  • Object
show all
Defined in:
lib/anorexic/server/services/basic_service.rb

Overview

this class is a basic TCP socket service.

a protocol should be assigned, or the service will fall back to an echo service.

a protocol should answer to: on_connect(service), on_message(service, data), on_disconnect(service) and on_exception(service, exception)

the on_message method should return any data that wasn't used (to be sent again as part of the next `on_message` call, once more data is received).

if the protocol is a class, these methods should be instance methods. a protocol class should support the initialize(service, parameters={}) method as well.

to-do: fix logging

Direct Known Subclasses

SSLService

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(socket, parameters = {}) ⇒ BasicService

creates a new connection wrapper object for the new socket that was recieved from the `accept_nonblock` method call.


30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/anorexic/server/services/basic_service.rb', line 30

def initialize socket, parameters = {}
	@handler = parameters[:handler]
	@socket = socket
	# socket.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, "\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" #== [10 sec 0 usec].pack '1_2'
	@out_que = []
	@locker = Mutex.new
	@parameters = parameters
	@protocol = parameters[:protocol]
	@protocol = protocol.new self, parameters if protocol.is_a?(Class)
	@protocol.on_connect self if @protocol && @protocol.methods.include?(:on_connect)
	touch
	@timeout ||= 5
	# Anorexic.callback self, :on_message
end

Instance Attribute Details

#active_timeObject (readonly)

instance methods


26
27
28
# File 'lib/anorexic/server/services/basic_service.rb', line 26

def active_time
  @active_time
end

#closedObject (readonly)

instance methods


26
27
28
# File 'lib/anorexic/server/services/basic_service.rb', line 26

def closed
  @closed
end

#handlerObject

Returns the value of attribute handler


27
28
29
# File 'lib/anorexic/server/services/basic_service.rb', line 27

def handler
  @handler
end

#lockerObject (readonly)

instance methods


26
27
28
# File 'lib/anorexic/server/services/basic_service.rb', line 26

def locker
  @locker
end

#out_queObject (readonly)

instance methods


26
27
28
# File 'lib/anorexic/server/services/basic_service.rb', line 26

def out_que
  @out_que
end

#parametersObject (readonly)

instance methods


26
27
28
# File 'lib/anorexic/server/services/basic_service.rb', line 26

def parameters
  @parameters
end

#protocolObject

Returns the value of attribute protocol


27
28
29
# File 'lib/anorexic/server/services/basic_service.rb', line 27

def protocol
  @protocol
end

#socketObject (readonly)

instance methods


26
27
28
# File 'lib/anorexic/server/services/basic_service.rb', line 26

def socket
  @socket
end

#timeoutObject

Returns the value of attribute timeout


27
28
29
# File 'lib/anorexic/server/services/basic_service.rb', line 27

def timeout
  @timeout
end

Class Method Details

.create_service(port, parameters) ⇒ Object

create a listener (io) - will create a TCPServer socket

listeners are 'server sockets' that answer to `accept` by creating a new connection socket (io).


20
21
22
# File 'lib/anorexic/server/services/basic_service.rb', line 20

def self.create_service port, parameters
	TCPServer.new(port)
end

Instance Method Details

#<<(data) ⇒ Object

adds data to the out buffer - but doesn't send the data until a send event is called.


93
94
95
96
# File 'lib/anorexic/server/services/basic_service.rb', line 93

def << data
	touch
	locker.synchronize {@out_que << data}
end

#closeObject

closes the connection


141
142
143
144
145
# File 'lib/anorexic/server/services/basic_service.rb', line 141

def close
	locker.synchronize do
		_close rescue true
	end
end

#disconnectObject

disconects the service.


151
152
153
# File 'lib/anorexic/server/services/basic_service.rb', line 151

def disconnect
	Anorexic.callback self, :on_disconnect
end

#disconnected?Boolean

returns true if the service is disconnected

Returns:

  • (Boolean)

147
148
149
# File 'lib/anorexic/server/services/basic_service.rb', line 147

def disconnected?
	_disconnected?
end

#flushObject

makes sure any data in the que is send and calls `flush` on the socket, to make sure the buffer is sent.


99
100
101
102
103
104
105
106
# File 'lib/anorexic/server/services/basic_service.rb', line 99

def flush
	begin
		send
		socket.flush				
	rescue Exception => e
		
	end
end

#has_incoming_data?Boolean

returns true if the socket has content to be read.

Returns:

  • (Boolean)

155
156
157
# File 'lib/anorexic/server/services/basic_service.rb', line 155

def has_incoming_data?
	 (socket.stat.size > 0) rescue false
end

#ioObject

returns an IO-like object used for reading/writing (unlike the original IO object, this can be an SSL layer or any other wrapper object).


61
62
63
64
# File 'lib/anorexic/server/services/basic_service.rb', line 61

def io
	touch
	@socket
end

#on_disconnectObject

called once a socket is disconnected or needs to be disconnected.


128
129
130
131
132
133
134
135
136
# File 'lib/anorexic/server/services/basic_service.rb', line 128

def on_disconnect
	Anorexic.callback Anorexic, :remove_connection, self
	locker.synchronize do
		@out_que.each { |d| _send d rescue true}
		@out_que.clear
	end
	Anorexic.callback protocol, :on_disconnect, self if protocol
	close
end

#on_messageObject

notice: since it is all async evet base - multipart messages might be garbled up…? todo: protect from garbeling.


112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/anorexic/server/services/basic_service.rb', line 112

def on_message
	# return false if locker.locked?
	return false if locker.locked?
	begin
		
		locker.synchronize do
			return disconnect if _disconnected?
			protocol.on_message(self)
		end

	rescue Exception => e
		return disconnect
	end
end

#read(size = 1048576) ⇒ Object

this is a public method and it should be used by child classes to implement each read(_nonblock) action. accepts one argument ::size for an optional buffer size to be read.


176
177
178
179
180
181
182
# File 'lib/anorexic/server/services/basic_service.rb', line 176

def read size = 1048576
	data = @socket.recv_nonblock( size )
	touch unless data.nil? || data.empty?
	return data
	rescue Exception => e
		return ''
end

#send(data = nil) ⇒ Object

sends data immidiately - forcing the data to be sent, flushing any pending messages in the que


67
68
69
70
71
72
73
74
75
76
77
# File 'lib/anorexic/server/services/basic_service.rb', line 67

def send data = nil
	return if @out_que.empty? && data.nil?
	locker.synchronize do
		unless @out_que.empty?
			@out_que.each { |d| _send d rescue disconnect }
			@out_que.clear					
		end
		(_send data rescue disconnect) if data
		touch
	end
end

#send_nonblock(data) ⇒ Object

sends data without waiting - data might be sent in a different order then intended.


86
87
88
89
90
# File 'lib/anorexic/server/services/basic_service.rb', line 86

def send_nonblock data
	touch
	locker.synchronize {@out_que << data}
	Anorexic.callback(self, :send)
end

#send_unsafe_interrupt(data = nil) ⇒ Object

sends data immidiately, interrupting any pending que and ignoring thread safety.


80
81
82
83
# File 'lib/anorexic/server/services/basic_service.rb', line 80

def send_unsafe_interrupt data = nil
	touch
	_send data rescue disconnect
end

#service_typeObject

returns the service type - set to normal


163
164
165
# File 'lib/anorexic/server/services/basic_service.rb', line 163

def service_type
	'normal'
end

#ssl?Boolean

returns true if the service is encrypted using the OpenSSL library.

Returns:

  • (Boolean)

167
168
169
# File 'lib/anorexic/server/services/basic_service.rb', line 167

def ssl?
	false
end

#timedout?Boolean

checks if a connection timed out

Returns:

  • (Boolean)

51
52
53
# File 'lib/anorexic/server/services/basic_service.rb', line 51

def timedout?
	Time.now - @active_time > @timeout
end

#touchObject

resets the timer for the connection timeout


56
57
58
# File 'lib/anorexic/server/services/basic_service.rb', line 56

def touch
	@active_time = Time.now
end