2022-10-22 22:30:40 +01:00
|
|
|
module OBSWS
|
2023-08-11 22:05:01 +01:00
|
|
|
class Identified
|
|
|
|
attr_accessor :state
|
|
|
|
|
|
|
|
def initialize
|
|
|
|
@state = :pending
|
|
|
|
end
|
|
|
|
|
|
|
|
def error_message
|
|
|
|
case @state
|
|
|
|
when :passwordless
|
|
|
|
"auth enabled but no password provided"
|
|
|
|
else
|
|
|
|
"failed to identify client with the websocket server"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-22 22:30:40 +01:00
|
|
|
class Base
|
2023-07-26 14:37:35 +01:00
|
|
|
include Logging
|
2023-07-26 16:55:59 +01:00
|
|
|
include Driver::Director
|
2022-10-22 22:30:40 +01:00
|
|
|
include Mixin::OPCodes
|
|
|
|
|
2023-08-11 22:05:01 +01:00
|
|
|
attr_reader :closed, :identified
|
2023-07-26 10:51:38 +01:00
|
|
|
attr_writer :updater
|
2022-10-22 22:30:40 +01:00
|
|
|
|
|
|
|
def initialize(**kwargs)
|
|
|
|
host = kwargs[:host] || "localhost"
|
|
|
|
port = kwargs[:port] || 4455
|
|
|
|
@password = kwargs[:password] || ""
|
|
|
|
@subs = kwargs[:subs] || 0
|
2023-08-11 22:05:01 +01:00
|
|
|
@identified = Identified.new
|
2023-08-17 16:28:43 +01:00
|
|
|
setup_driver(host, port) and start_driver
|
2022-10-22 22:30:40 +01:00
|
|
|
WaitUtil.wait_for_condition(
|
2022-11-25 17:57:56 +00:00
|
|
|
"successful identification",
|
2022-10-22 22:30:40 +01:00
|
|
|
delay_sec: 0.01,
|
2023-08-11 16:14:53 +01:00
|
|
|
timeout_sec: kwargs[:connect_timeout] || 3
|
2023-08-11 22:05:01 +01:00
|
|
|
) { @identified.state != :pending }
|
2022-10-22 22:30:40 +01:00
|
|
|
end
|
|
|
|
|
2023-07-26 10:51:38 +01:00
|
|
|
private
|
|
|
|
|
2022-10-22 22:30:40 +01:00
|
|
|
def auth_token(salt:, challenge:)
|
|
|
|
Digest::SHA256.base64digest(
|
|
|
|
Digest::SHA256.base64digest(@password + salt) + challenge
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2022-10-25 00:03:43 +01:00
|
|
|
def identify(auth)
|
2022-11-25 18:05:10 +00:00
|
|
|
payload = {
|
|
|
|
op: Mixin::OPCodes::IDENTIFY,
|
|
|
|
d: {
|
|
|
|
rpcVersion: 1,
|
|
|
|
eventSubscriptions: @subs
|
|
|
|
}
|
|
|
|
}
|
2022-11-25 17:57:56 +00:00
|
|
|
if auth
|
|
|
|
if @password.empty?
|
2023-08-11 22:05:01 +01:00
|
|
|
@identified.state = :passwordless
|
|
|
|
return
|
2022-11-25 17:57:56 +00:00
|
|
|
end
|
2023-07-26 14:37:35 +01:00
|
|
|
logger.info("initiating authentication")
|
2022-11-25 17:57:56 +00:00
|
|
|
payload[:d][:authentication] = auth_token(**auth)
|
|
|
|
end
|
2022-10-22 22:30:40 +01:00
|
|
|
@driver.text(JSON.generate(payload))
|
|
|
|
end
|
|
|
|
|
|
|
|
def msg_handler(data)
|
2022-10-23 23:33:30 +01:00
|
|
|
case data[:op]
|
2022-10-22 22:30:40 +01:00
|
|
|
when Mixin::OPCodes::HELLO
|
2022-10-25 00:03:43 +01:00
|
|
|
identify(data[:d][:authentication])
|
2022-10-22 22:30:40 +01:00
|
|
|
when Mixin::OPCodes::IDENTIFIED
|
2023-08-11 22:05:01 +01:00
|
|
|
@identified.state = :identified
|
2022-10-22 22:30:40 +01:00
|
|
|
when Mixin::OPCodes::EVENT, Mixin::OPCodes::REQUESTRESPONSE
|
2023-07-26 10:51:38 +01:00
|
|
|
@updater.call(data[:op], data[:d])
|
2022-10-22 22:30:40 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-07-26 10:51:38 +01:00
|
|
|
public def req(id, type_, data = nil)
|
2022-10-22 22:30:40 +01:00
|
|
|
payload = {
|
|
|
|
op: Mixin::OPCodes::REQUEST,
|
|
|
|
d: {
|
|
|
|
requestType: type_,
|
|
|
|
requestId: id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
payload[:d][:requestData] = data if data
|
2023-07-26 14:37:35 +01:00
|
|
|
logger.debug("sending request: #{payload}")
|
2023-07-21 06:04:09 +01:00
|
|
|
@driver.text(JSON.generate(payload))
|
2022-10-22 22:30:40 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|