Class: TunnelRb::Server::ClientRegistry
- Inherits:
-
Object
- Object
- TunnelRb::Server::ClientRegistry
- Defined in:
- lib/tunnel_rb/server/client_registry.rb
Overview
Thread-safe in-memory registry of connected clients keyed by subdomain, with a reverse index for O(1) lookup by socket.
Instance Method Summary collapse
- #active_subdomains ⇒ Object
-
#each_client(&block) ⇒ Object
Yields each Client under the registry mutex.
-
#forget(socket) ⇒ Object
Removes a client identified by socket.
-
#forget_many(sockets) ⇒ Object
Atomically tags many clients for removal and returns their sockets.
-
#initialize ⇒ ClientRegistry
constructor
A new instance of ClientRegistry.
- #lookup(subdomain) ⇒ Object
- #lookup_by_socket(socket) ⇒ Object
-
#register(subdomain, socket, token) ⇒ Object
Registers a new client.
- #size ⇒ Object
-
#sockets ⇒ Object
Snapshot of currently registered control sockets, for IO.select.
Constructor Details
#initialize ⇒ ClientRegistry
Returns a new instance of ClientRegistry.
13 14 15 16 17 |
# File 'lib/tunnel_rb/server/client_registry.rb', line 13 def initialize @clients = {} # subdomain -> Client @socket_to_subdomain = {} # control_socket -> subdomain @mutex = Mutex.new end |
Instance Method Details
#active_subdomains ⇒ Object
67 68 69 |
# File 'lib/tunnel_rb/server/client_registry.rb', line 67 def active_subdomains @mutex.synchronize { @clients.keys.to_set } end |
#each_client(&block) ⇒ Object
Yields each Client under the registry mutex. Block must not block on I/O; collect work and execute it after the iteration.
63 64 65 |
# File 'lib/tunnel_rb/server/client_registry.rb', line 63 def each_client(&block) @mutex.synchronize { @clients.each_value(&block) } end |
#forget(socket) ⇒ Object
Removes a client identified by socket. Returns the subdomain it was registered under, or nil if the socket was already gone (e.g. replaced by a reconnect).
41 42 43 |
# File 'lib/tunnel_rb/server/client_registry.rb', line 41 def forget(socket) @mutex.synchronize { forget_unlocked(socket) } end |
#forget_many(sockets) ⇒ Object
Atomically tags many clients for removal and returns their sockets. Used by the ping loop to evict unresponsive peers without holding the mutex while closing sockets.
78 79 80 81 82 |
# File 'lib/tunnel_rb/server/client_registry.rb', line 78 def forget_many(sockets) @mutex.synchronize do sockets.each { |s| forget_unlocked(s) } end end |
#lookup(subdomain) ⇒ Object
45 46 47 |
# File 'lib/tunnel_rb/server/client_registry.rb', line 45 def lookup(subdomain) @mutex.synchronize { @clients[subdomain] } end |
#lookup_by_socket(socket) ⇒ Object
49 50 51 52 53 54 |
# File 'lib/tunnel_rb/server/client_registry.rb', line 49 def lookup_by_socket(socket) @mutex.synchronize do sub = @socket_to_subdomain[socket] sub && @clients[sub] end end |
#register(subdomain, socket, token) ⇒ Object
Registers a new client. If a client with the same subdomain is already connected, returns the old socket so the caller can close it outside the registry’s mutex.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/tunnel_rb/server/client_registry.rb', line 22 def register(subdomain, socket, token) old_socket = nil client = nil @mutex.synchronize do old = @clients[subdomain] if old && old.socket != socket @socket_to_subdomain.delete(old.socket) old_socket = old.socket end client = Client.new(subdomain: subdomain, socket: socket, token: token) @clients[subdomain] = client @socket_to_subdomain[socket] = subdomain end [client, old_socket] end |
#size ⇒ Object
71 72 73 |
# File 'lib/tunnel_rb/server/client_registry.rb', line 71 def size @mutex.synchronize { @clients.size } end |
#sockets ⇒ Object
Snapshot of currently registered control sockets, for IO.select.
57 58 59 |
# File 'lib/tunnel_rb/server/client_registry.rb', line 57 def sockets @mutex.synchronize { @socket_to_subdomain.keys } end |