Class: Sockeye::Server
- Inherits:
-
Object
- Object
- Sockeye::Server
- Defined in:
- lib/sockeye/server.rb
Instance Attribute Summary collapse
-
#authentication_method ⇒ Object
Returns the value of attribute authentication_method.
-
#connection_map ⇒ Object
Returns the value of attribute connection_map.
-
#connections ⇒ Object
Returns the value of attribute connections.
-
#host ⇒ Object
Returns the value of attribute host.
-
#port ⇒ Object
Returns the value of attribute port.
-
#secret_token ⇒ Object
Returns the value of attribute secret_token.
Instance Method Summary collapse
-
#add_connection(identifier:, connection:) ⇒ Object
Add a connection to the list and add a map entry to link the connection object with an authenticated identifier.
-
#authenticate(token) ⇒ Object
Call the supplied authentication method.
-
#deliver_to_many(payload:, identifiers:) ⇒ Object
Find all open connections associated with the specified identifiers then attempt to push the payload to each of them.
-
#initialize(host:, port:, secret_token:, authentication_method: nil) ⇒ Server
constructor
A new instance of Server.
-
#json_try_parse(data) ⇒ Object
Safely parse data as JSON, but return nil values on failure.
-
#listen ⇒ Object
Main server connection listener loop.
-
#remove_connection(connection) ⇒ Object
Safely remove the specified connection from the connections lists.
Constructor Details
#initialize(host:, port:, secret_token:, authentication_method: nil) ⇒ Server
Returns a new instance of Server.
10 11 12 13 14 15 16 17 |
# File 'lib/sockeye/server.rb', line 10 def initialize(host:, port:, secret_token:, authentication_method: nil) self.connections = {} self.connection_map = {} self.host = host self.port = port self.secret_token = secret_token self.authentication_method = authentication_method end |
Instance Attribute Details
#authentication_method ⇒ Object
Returns the value of attribute authentication_method.
8 9 10 |
# File 'lib/sockeye/server.rb', line 8 def authentication_method @authentication_method end |
#connection_map ⇒ Object
Returns the value of attribute connection_map.
8 9 10 |
# File 'lib/sockeye/server.rb', line 8 def connection_map @connection_map end |
#connections ⇒ Object
Returns the value of attribute connections.
8 9 10 |
# File 'lib/sockeye/server.rb', line 8 def connections @connections end |
#host ⇒ Object
Returns the value of attribute host.
8 9 10 |
# File 'lib/sockeye/server.rb', line 8 def host @host end |
#port ⇒ Object
Returns the value of attribute port.
8 9 10 |
# File 'lib/sockeye/server.rb', line 8 def port @port end |
#secret_token ⇒ Object
Returns the value of attribute secret_token.
8 9 10 |
# File 'lib/sockeye/server.rb', line 8 def secret_token @secret_token end |
Instance Method Details
#add_connection(identifier:, connection:) ⇒ Object
Add a connection to the list and add a map entry to link the connection object with an authenticated identifier
38 39 40 41 42 |
# File 'lib/sockeye/server.rb', line 38 def add_connection(identifier:, connection:) connections[identifier] = [] if connections[identifier].nil? connections[identifier] << connection connection_map[connection.object_id] = identifier end |
#authenticate(token) ⇒ Object
Call the supplied authentication method
31 32 33 |
# File 'lib/sockeye/server.rb', line 31 def authenticate(token) return self.authentication_method.call(token) end |
#deliver_to_many(payload:, identifiers:) ⇒ Object
Find all open connections associated with the specified identifiers then attempt to push the payload to each of them
58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/sockeye/server.rb', line 58 def deliver_to_many(payload:, identifiers:) identifiers.each do |identifier| identified_connections = connections[identifier] next unless identified_connections.is_a? Array identified_connections.each do |connection| begin connection.send({payload: payload, status: payload.dig(:status) || 200}.to_json, :type => :text) rescue end end end end |
#json_try_parse(data) ⇒ Object
Safely parse data as JSON, but return nil values on failure
21 22 23 24 25 26 27 |
# File 'lib/sockeye/server.rb', line 21 def json_try_parse(data) begin return JSON.parse(data, symbolize_names: true) rescue JSON::ParserError => e return nil end end |
#listen ⇒ Object
Main server connection listener loop. Uses an EventMachine and websocket server to handle and abstract raw connections. Handles authentication and delivery actions for clients and pushers.
75 76 77 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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/sockeye/server.rb', line 75 def listen EM.run do WebSocket::EventMachine::Server.start(host: self.host, port: self.port) do |ws| # Called when a new message arrives at the server # ws. do |, type| # Attempt to parse the received data as JSON # = json_try_parse() if .nil? ws.send({payload: "invalid message", status: 400}.to_json, :type => :text) ws.close else # Execute the appropriate action based on JSON action # case [:action].to_sym # Handle authentication requests by calling the authentication # method supplied on server setup # when :authenticate authentication_result = authenticate([:payload]) if authentication_result add_connection(identifier: authentication_result, connection: ws) ws.send({payload: "authenticated", status: 200}.to_json, :type => :text) else ws.send({payload: "authentication failure", status: 401}.to_json, :type => :text) ws.close end # Handle delivery requests by verifying the auth token supplied # then push out the payload to all connected specified clients # when :deliver if [:secret_token] == self.secret_token deliver_to_many(payload: [:payload], identifiers: [[:identifiers]].flatten) ws.send({payload: "payload pushed", status: 201}.to_json, :type => :text) ws.close else ws.send({payload: "authentication failure", status: 401}.to_json, :type => :text) ws.close end else ws.send({payload: "invalid action", status: 405}.to_json, :type => :text) ws.close end end end # Cleanup connection lists when a connection is closed # ws.onclose do remove_connection(ws) end end end end |
#remove_connection(connection) ⇒ Object
Safely remove the specified connection from the connections lists
46 47 48 49 50 51 52 53 |
# File 'lib/sockeye/server.rb', line 46 def remove_connection(connection) identifier = connection_map[connection.object_id] if connections[identifier].is_a? Array connections[identifier].delete(connection) connections.delete(identifier) if connections[identifier].empty? end connection_map.delete(connection.object_id) end |