Class: Waithook

Inherits:
Object
  • Object
show all
Defined in:
lib/waithook.rb,
lib/waithook/cli.rb,
lib/waithook/version.rb,
lib/waithook/websocket_client.rb

Defined Under Namespace

Modules: CLI, WithColor Classes: Webhook, WebsocketClient

Constant Summary collapse

SERVER_HOST =

Default server host

"waithook.com"
SERVER_PORT =

Default server port

80
VERSION =
"0.4.2"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Waithook

Available options:

  • :host

  • :port

  • :auto_connect - whenever connect to server automatically when instance is created (default is true)

  • :path

  • :timeout

  • :logger_level - logger level, default :info

  • :output - output stream for default logger. If value == false then it will be silent, default is $stdout

  • :logger - custom logger object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/waithook.rb', line 67

def initialize(options = {})
  @options = {
    host: SERVER_HOST,
    port: SERVER_PORT,
    auto_connect: true,
    path: self.class.default_path
  }.merge(options)

  if @options[:path] == nil
    raise ArgumentError, ":path is missing. Please add :path to options argument or set Waithook.default_path = 'foo'"
  end

  # TODO: add SSL options
  @client = WebsocketClient.new(
    path: @options[:path],
    host: @options[:host],
    port: @options[:port],
    logger: @options[:logger],
    logger_level: @options[:logger_level],
    output: @options[:output]
  )

  @messages = []
  @filter = nil
  @started = false

  connect! if @options[:auto_connect]
end

Instance Attribute Details

#clientObject (readonly)

Websocket client, instance of Waithook::WebsocketClient



53
54
55
# File 'lib/waithook.rb', line 53

def client
  @client
end

#filterObject

Filter (Proc), can be used to to filter incoming messages



49
50
51
# File 'lib/waithook.rb', line 49

def filter
  @filter
end

#messagesObject

Array of all received messages



51
52
53
# File 'lib/waithook.rb', line 51

def messages
  @messages
end

#optionsObject (readonly)

Connection options, hash



55
56
57
# File 'lib/waithook.rb', line 55

def options
  @options
end

Class Method Details

.default_pathObject

Accessor for @default_path



44
45
46
# File 'lib/waithook.rb', line 44

def self.default_path
  @default_path
end

.default_path=(value) ⇒ Object

Default path that it will be subscribed to



39
40
41
# File 'lib/waithook.rb', line 39

def self.default_path=(value)
  @default_path = value
end

.subscribe(options = {}, &block) ⇒ Object

Connect to server and start filter incoming messages (optionally)

Usage:

Waithook.default_path = 'my-notification-endpoint'
waithook = Waithook.subscribe(timeout: 10) do |message|
  message.json_body['user_name'] == 'John Doe' # will return messages only passing this criteria
end
waithook.forward_to('http://localhost:4567/webhook', raise_on_timeout: true)

options argument is will be passed to #initialize



29
30
31
32
33
34
35
36
# File 'lib/waithook.rb', line 29

def self.subscribe(options = {}, &block)
  instance = new(options)
  if block
    instance.filter = block
  end
  instance.connect! unless instance.started?
  instance
end

Instance Method Details

#close!Object

Close connection to server



168
169
170
171
# File 'lib/waithook.rb', line 168

def close!
  @client.close!
  @started = false
end

#connect!Object

Start connection to waithook server



105
106
107
108
109
110
111
112
# File 'lib/waithook.rb', line 105

def connect!
  raise "Waithook connection already started" if @started
  @started = true
  @client.connect!.wait_handshake!
  start_pinger_thread!

  self
end

#forward_to(url, options = {}) ⇒ Object

Send all incoming webhook requests to running HTTP server

webhook = Waithook.subscribe(path: 'my-webhooks').forward_to('http://localhost:3000/notification')


139
140
141
142
# File 'lib/waithook.rb', line 139

def forward_to(url, options = {})
  webhook = wait_message(options)
  webhook.send_to(url) unless webhook.nil?
end

#loggerObject

Logger object



97
98
99
100
101
102
# File 'lib/waithook.rb', line 97

def logger
  @logger ||= LoggerWithTrace.new(@options[:logger] ? $stdout : StringIO.new).setup(
    progname: self.class.name,
    level: @options[:logger_level] || :info
  )
end

#start_pinger_thread!Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/waithook.rb', line 114

def start_pinger_thread!
  Thread.new do
    begin
      logger.debug("Sending ping every 60 seconds")
      client.ping_sender
      logger.debug("Exit ping sender thread")
    rescue => error
      if error.message == "closed stream" && !@client.socket_open?
        logger.debug("Connection closed, stopping ping sender thread")
      else
        logger.warn("Error in ping sender thread: #{error.message} (#{error.class})\n#{error.backtrace.join("\n")}")
      end
    end
  end
end

#started?Boolean

Whenever connected to server or not

Returns:

  • (Boolean)


131
132
133
# File 'lib/waithook.rb', line 131

def started?
  !!@started
end

#wait_message(options = {}) ⇒ Object

Wait incoming request information (wait message on websocket connection)



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/waithook.rb', line 145

def wait_message(options = {})
  raise_timeout_error = options.has_key?(:raise_on_timeout) ? options[:raise_on_timeout] : true
  timeout = options[:timeout] || @options[:timeout] || 0

  start_time = Time.new.to_f
  Timeout.timeout(timeout) do
    while true
      _, data = @client.wait_message
      webhook = Webhook.new(data, logger)
      if @filter && @filter.call(webhook) || !@filter
        @messages << webhook
        return webhook
      end
    end
  end
rescue Timeout::Error => error
  time_diff = (Time.now.to_f - start_time.to_i).round(3)
  logger.error "#{error.class}: #{error.message} (after #{time_diff} seconds)"
  raise error if raise_timeout_error
  return nil
end