Class: GripControl
- Inherits:
-
Object
- Object
- GripControl
- Defined in:
- lib/gripcontrol.rb
Overview
The GripControl class provides functionality that is used in conjunction with GRIP proxies. This includes facilitating the creation of hold instructions for HTTP long-polling and HTTP streaming, parsing GRIP URIs into config objects, validating the GRIP-SIG header coming from GRIP proxies, creating GRIP channel headers, and also WebSocket-over-HTTP features such as encoding/decoding web socket events and generating control messages.
Class Method Summary collapse
-
.create_grip_channel_header(channels) ⇒ Object
Create a GRIP channel header for the specified channels.
-
.create_hold(mode, channels, response, timeout = nil) ⇒ Object
Create GRIP hold instructions for the specified mode, channels, response and optional timeout value.
-
.create_hold_response(channels, response = nil, timeout = nil) ⇒ Object
A convenience method for creating GRIP hold response instructions for HTTP long-polling.
-
.create_hold_stream(channels, response = nil) ⇒ Object
A convenience method for creating GRIP hold stream instructions for HTTP streaming.
-
.decode_websocket_events(body) ⇒ Object
Decode the specified HTTP request body into an array of WebSocketEvent instances when using the WebSocket-over-HTTP protocol.
-
.encode_websocket_events(events) ⇒ Object
Encode the specified array of WebSocketEvent instances.
-
.parse_grip_uri(uri) ⇒ Object
Parse the specified GRIP URI into a config object that can then be passed to the GripPubControl class.
-
.validate_sig(token, key) ⇒ Object
Validate the specified JWT token and key.
-
.websocket_control_message(type, args = nil) ⇒ Object
Generate a WebSocket control message with the specified type and optional arguments.
Class Method Details
.create_grip_channel_header(channels) ⇒ Object
Create a GRIP channel header for the specified channels. The channels parameter can be specified as a string representing the channel name, a Channel instance, or an array of Channel instances. The returned GRIP channel header is used when sending instructions to GRIP proxies via HTTP headers.
129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/gripcontrol.rb', line 129 def self.create_grip_channel_header(channels) channels = parse_channels(channels) parts = [] channels.each do |channel| s = channel.name if !channel.prev_id.nil? s += '; prev-id=%s' % [channel.prev_id] end parts.push(s) end return parts.join(', ') end |
.create_hold(mode, channels, response, timeout = nil) ⇒ Object
Create GRIP hold instructions for the specified mode, channels, response and optional timeout value. The channel parameter can be specified as either a string representing the channel name, a Channel instance or an array of Channel instances. The response parameter can be specified as either a string representing the response body or a Response instance.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/gripcontrol.rb', line 34 def self.create_hold(mode, channels, response, timeout=nil) hold = Hash.new hold['mode'] = mode channels = GripControl.parse_channels(channels) ichannels = GripControl.get_hold_channels(channels) hold['channels'] = ichannels if !timeout.nil? hold['timeout'] = timeout end iresponse = GripControl.get_hold_response(response) instruct = Hash.new instruct['hold'] = hold if !iresponse.nil? instruct['response'] = iresponse end return instruct.to_json end |
.create_hold_response(channels, response = nil, timeout = nil) ⇒ Object
A convenience method for creating GRIP hold response instructions for HTTP long-polling. This method simply passes the specified parameters to the create_hold method with ‘response’ as the hold mode.
145 146 147 |
# File 'lib/gripcontrol.rb', line 145 def self.create_hold_response(channels, response=nil, timeout=nil) return GripControl.create_hold('response', channels, response, timeout) end |
.create_hold_stream(channels, response = nil) ⇒ Object
A convenience method for creating GRIP hold stream instructions for HTTP streaming. This method simply passes the specified parameters to the create_hold method with ‘stream’ as the hold mode.
152 153 154 |
# File 'lib/gripcontrol.rb', line 152 def self.create_hold_stream(channels, response=nil) return create_hold('stream', channels, response) end |
.decode_websocket_events(body) ⇒ Object
Decode the specified HTTP request body into an array of WebSocketEvent instances when using the WebSocket-over-HTTP protocol. A RuntimeError is raised if the format is invalid.
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/gripcontrol.rb', line 159 def self.decode_websocket_events(body) out = [] start = 0 while start < body.length do at = body.index("\r\n", start) if at.nil? raise 'bad format' end typeline = body[start..at - 1] start = at + 2 at = typeline.index(' ') event = nil if !at.nil? etype = typeline[0..at - 1] clen = ('0x' + typeline[at + 1..-1]).to_i(16) content = body[start..start + clen - 1] start += clen + 2 event = WebSocketEvent.new(etype, content) else event = WebSocketEvent.new(typeline) end out.push(event) end return out end |
.encode_websocket_events(events) ⇒ Object
Encode the specified array of WebSocketEvent instances. The returned string value should then be passed to a GRIP proxy in the body of an HTTP response when using the WebSocket-over-HTTP protocol.
188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/gripcontrol.rb', line 188 def self.encode_websocket_events(events) out = '' events.each do |event| if !event.content.nil? out += "%s %x\r\n%s\r\n" % [event.type, event.content.length, event.content] else out += "%s\r\n" % [event.type] end end return out end |
.parse_grip_uri(uri) ⇒ Object
Parse the specified GRIP URI into a config object that can then be passed to the GripPubControl class. The URI can include ‘iss’ and ‘key’ JWT authentication query parameters as well as any other required query string parameters. The JWT ‘key’ query parameter can be provided as-is or in base64 encoded format.
57 58 59 60 61 62 63 64 65 66 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 95 96 97 98 99 100 101 102 103 |
# File 'lib/gripcontrol.rb', line 57 def self.parse_grip_uri(uri) uri = URI(uri) params = {} if (uri.query) params = CGI.parse(uri.query) end iss = nil key = nil if params.key?('iss') iss = params['iss'][0] params.delete('iss') end if params.key?('key') key = params['key'][0] params.delete('key') end if !key.nil? and key.start_with?('base64:') key = Base64.decode64(key[7..-1]) end qs = [] params.map do |name,values| values.map do |value| qs.push("#{CGI.escape name}=#{CGI.escape value}") end end qs = qs.join('&') path = uri.path if path.end_with?('/') path = path[0..-2] end port = '' if uri.port != 80 port = ':' + uri.port.to_s end control_uri = uri.scheme + '://' + uri.host + port + path if !qs.nil? and !qs.empty? control_uri += '?' + qs end out = {'control_uri' => control_uri} if !iss.nil? out['control_iss'] = iss end if !key.nil? out['key'] = key end return out end |
.validate_sig(token, key) ⇒ Object
Validate the specified JWT token and key. This method is used to validate the GRIP-SIG header coming from GRIP proxies such as Pushpin or Fanout.io. Note that the token expiration is also verified.
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/gripcontrol.rb', line 108 def self.validate_sig(token, key) token = token.encode('utf-8') begin claim = JWT.decode(token, key, true, {verify_expiration: false}) rescue return false end if claim.length == 0 or !claim[0].key?('exp') return false end if Time.now.utc.to_i >= claim[0]['exp'] return false end return true end |
.websocket_control_message(type, args = nil) ⇒ Object
Generate a WebSocket control message with the specified type and optional arguments. WebSocket control messages are passed to GRIP proxies and example usage includes subscribing/unsubscribing a WebSocket connection to/from a channel.
205 206 207 208 209 210 211 212 213 |
# File 'lib/gripcontrol.rb', line 205 def self.(type, args=nil) if !args.nil? out = Marshal.load(Marshal.dump(args)) else out = Hash.new end out['type'] = type return out.to_json end |