Class: Ask::AppServer::SocketServer

Inherits:
Object
  • Object
show all
Defined in:
lib/ask/app_server/socket_server.rb

Overview

Unix-socket transport for the session host: any number of clients can attach to the same sessions (terminal TUI, web console, bots) by connecting to the socket and speaking the canonical session protocol as NDJSON lines.

Each accepted connection gets its own reader thread and a Connection with per-session delivery cursors; the shared protocol engine (Server) routes responses back to the requesting connection and fans out session/event notifications to every subscribed connection.

The socket file is removed on start (stale cleanup) and on stop.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(session_manager: nil, socket_path: nil) ⇒ SocketServer

Returns a new instance of SocketServer.

Parameters:

  • session_manager (SessionManager, nil) (defaults to: nil)

    shared session manager

  • socket_path (String, nil) (defaults to: nil)

    unix socket path



32
33
34
35
36
37
38
39
40
41
# File 'lib/ask/app_server/socket_server.rb', line 32

def initialize(session_manager: nil, socket_path: nil)
  @session_manager = session_manager || SessionManager.new
  @protocol = Server.new(session_manager: @session_manager)
  @socket_path = socket_path || self.class.default_socket_path
  @running = false
  @listener = nil
  @acceptor = nil
  @pusher = nil
  @logger = Logger.new($stdout, level: ENV["DEBUG"] ? Logger::DEBUG : Logger::WARN)
end

Instance Attribute Details

#protocolObject (readonly)

Returns the value of attribute protocol.



28
29
30
# File 'lib/ask/app_server/socket_server.rb', line 28

def protocol
  @protocol
end

#socket_pathObject (readonly)

Returns the value of attribute socket_path.



28
29
30
# File 'lib/ask/app_server/socket_server.rb', line 28

def socket_path
  @socket_path
end

Class Method Details

.default_socket_pathObject

Default socket path: ASK_APP_SERVER_SOCKET env var or ~/.ask-app-server/app-server.sock



23
24
25
26
# File 'lib/ask/app_server/socket_server.rb', line 23

def self.default_socket_path
  ENV["ASK_APP_SERVER_SOCKET"] ||
    File.expand_path("~/.ask-app-server/app-server.sock")
end

Instance Method Details

#running?Boolean

Whether the server is running.

Returns:

  • (Boolean)


67
68
69
# File 'lib/ask/app_server/socket_server.rb', line 67

def running?
  @running
end

#startObject

Bind the socket and start accepting connections. Returns immediately (accept and push run in background threads).



45
46
47
48
49
50
51
52
53
54
# File 'lib/ask/app_server/socket_server.rb', line 45

def start
  @running = true
  FileUtils.mkdir_p(File.dirname(@socket_path))
  FileUtils.rm_f(@socket_path)  # stale socket from a previous run
  @listener = UNIXServer.new(@socket_path)
  @acceptor = Thread.new { accept_loop }
  @pusher = Thread.new { pusher_loop }
  @logger.debug("Socket server listening on #{@socket_path}")
  self
end

#stopObject

Stop accepting, close all connections, and remove the socket file.



57
58
59
60
61
62
63
64
# File 'lib/ask/app_server/socket_server.rb', line 57

def stop
  @running = false
  @acceptor&.kill rescue nil
  @pusher&.kill rescue nil
  @protocol.connections.each { |conn| @protocol.remove_connection(conn) }
  @listener&.close rescue nil
  FileUtils.rm_f(@socket_path) rescue nil
end