前面幾篇我們已經針對建構 WebSocket 做了一定程度的準備,接下來就要將 WebSocket 連線從預設的行為接手回來改為用我們自己的方式來進行管理。這樣我們才能將接收到的指令轉換為 Ruby 可以理解的格式,並且呼叫對應的方法來進行處理。
在修改 Unlight 為能夠支援 WebSocket 的版本時就想過一個問題,普通的 TCPSocket 伺服器跟 WebSocket 伺服器有沒有機會並存。因此在設計這個範例的時候預先假設我們會使用多個協定(Protocol)來提供服務,因此就採用了當伺服器接收連線後應該要轉交到不同協定上處理的預定。
雖然實際上要怎麼設計比較嗆大還沒有確定下來,不過先讓我們簡單的以 WebSocket 做一個雛形出來看看。
# app/network/protocol/websocket.rb
# frozen_string_literal: true
module Protocol
class WebSocket
class InvalidRequest < RuntimeError; end
def initialize(env)
@env = env
setup
end
def websocket?
Faye::WebSocket.websocket?(@env)
end
def response
@ws.rack_response
end
private
def receive(event)
# TODO
end
def setup
raise InvalidRequest unless websocket?
@ws = Faye::WebSocket.new(@env)
@ws.on :message, method(:receive)
end
end
end
這邊首先要注意的是 websocket
因為也是例外詞,所以需要用 Inflector 調整名稱。這個檔案我們先大致上的把處理的架構定義出來,因為進入這個物件後就預設一定是 WebSocket 連線,因此也把原本在 WebSocketServer 的判斷改到這邊,並且用 Exception 的方式呼叫外部的人員支援。
同樣的我們需要調整 WebSocketServer 物件來支援新定義的協定物件:
module WebSocketServer
UNSUPPORT_RESPONSE = [501, { 'Content-Type' => 'text/plain' }, ['Unsupport']].freeze
def self.call(env)
ws = Protocol::WebSocket.new(env)
ws.response
rescue Protocol::WebSocket::InvalidRequest
UNSUPPORT_RESPONSE
end
end
當我們處理好協定的部分後,需要做出一個抽象的連線物件用來統一操作的介面。這樣在往後如果要拓展 TCPSocket 支援的時候就只需要調整介面到能讓這個物件呼叫就能夠擴充。
# app/network/connection.rb
# frozen_string_literal: true
class Connection
def initialize(socket)
@socket = socket
end
def write(data)
@socket.write(data)
end
def receive(data)
# TODO: Parse Command and Execute
end
end
我們做了一個很簡單的介面,讓 Connection 物件可以支援接收資料並處理以及將資料發送出去的兩個行為。接下來我們要調整一下 Protocol::WebSocket 物件將資料轉發到 Connection 物件上。
# app/network/protocol/websocket.rb
# frozen_string_literal: true
module Protocol
class WebSocket
class InvalidRequest < RuntimeError; end
def initialize(env)
@env = env
@conn = Connection.new(self)
setup
end
# ...
private
def receive(event)
@conn.receive(event.data)
end
# ...
end
end
如此一來,當我們的 WebSocket 伺服器接收到資料後,會將資料轉給 Connection 物件處理,而 Connection 物件則成為處理的中樞,如果要發送或者接收都要透過他才能夠執行。下一篇我們就來討論將接收到的指令透過 Connection 處理後呼叫 Controller 執行的方式。
我的個人部落格是弦而時習之平常會把自己發現的一些新技巧紀錄在上面,也歡迎大家來逛逛。