require'travis/client'require'forwardable'require'json'ifrequire'pusher-client'# it's us that has been loading pusher-client# so let's assume we can mess with it - yay for global statePusherClient.logger.level=5endmoduleTravismoduleClientclassListenerclassSocket<PusherClient::Socketattr_accessor:session,:signaturesdefinitialize(application_key,options={})@session=options.fetch(:session)@signatures={}superbind('pusher:error')do|data|handle_error(data)endenddefsubscribe_all# bulk auth on connectfetch_auth(*channels.channels.keys)superenddeffetch_auth(*channels)channels.select!{|c|signatures[c].nil?ifc.start_with?'private-'}signatures.merge!session.post_raw('/pusher/auth',:channels=>channels,:socket_id=>socket_id)['channels']ifchannels.any?enddefget_private_auth(channel)fetch_auth(channel.name)signatures[channel.name]enddefhandle_error(data)code,message=data["code"],data["message"]ifdata.is_a?Hashmessage||=data.inspectcasecodewhen4100thenreconnect(1)when4200,4201,4202thenreconnectelseraiseTravis::Client::Error,"Pusher error: %s (code: %p)"%[message,code]endenddefreconnect(delay=nil)disconnectifconnectedsleepdelayifdelayanddelay>0connectendendEVENTS=%w[
build:created build:started build:finished
job:created job:started job:log job:finished
]Event=Struct.new(:type,:repository,:build,:job,:payload)classEntityListenerattr_reader:listener,:entitiesextendForwardabledef_delegators:listener,:disconnect,:on_connect,:subscribedefinitialize(listener,entities)@listener,@entities=listener,Array(entities)enddefon(*events)listener.on(*events){|e|yield(e)ifdispatch?(e)}endprivatedefdispatch?(event)entities.include?event.repositoryorentities.include?event.buildorentities.include?event.jobendendattr_reader:session,:socketdefinitialize(session)@session=session@socket=Socket.new(pusher_key,pusher_options)@channels=[]@callbacks=[]enddefsubscribe(*entities)entities=entities.mapdo|entity|entity=entity.pusher_entitywhileentity.respond_to?:pusher_entity@channels.concat(entity.pusher_channels)entityendyieldentities.any??EntityListener.new(self,entities):selfifblock_given?enddefon(*events,&block)events=events.flat_map{|e|e.respond_to?(:to_str)?e.to_str:EVENTS.grep(e)}.uniqevents.each{|e|@callbacks<<[e,block]}enddefon_connectsocket.bind('pusher:connection_established'){yield}enddeflisten@channels=default_channelsif@channels.empty?@channels.map!{|c|c.start_with?('private-')?c:"private-#{c}"}ifsession.private_channels?@channels.uniq.each{|c|socket.subscribe(c)}@callbacks.each{|e,b|socket.bind(e){|d|dispatch(e,d,&b)}}socket.connectenddefdisconnectsocket.disconnectendprivatedefdispatch(type,json)payload=JSON.parse(json)entities=session.loadformat_payload(type,payload)yieldEvent.new(type,entities['repository'],entities['build'],entities['job'],payload)enddefformat_payload(type,payload)casetypewhen"job:log"thenformat_log(payload)when/job:/thenformat_job(payload)elsepayloadendenddefformat_job(payload)build={"id"=>payload["build_id"],"repository_id"=>payload["repository_id"]}repo={"id"=>payload["repository_id"],"slug"=>payload["repository_slug"]}build["number"]=payload["number"][/^[^\.]+/]ifpayload["number"]{"job"=>payload,"build"=>build,"repository"=>repo}enddefformat_log(payload)job=session.job(payload['id']){"job"=>{"id"=>job.id},"build"=>{"id"=>job.build.id},"repository"=>{"id"=>job.repository.id}}enddefdefault_channelsreturn['common']ifsession.access_token.nil?session.user.channelsenddefpusher_optionspusher_options=session.config['pusher']||{}encrypted=pusher_options['scheme']!='http'options={:encrypted=>encrypted,:session=>session}options[:ws_host]=pusher_options['host']ifpusher_options['host']options[:wss_port]=pusher_options['port']ifencryptedandpusher_options['port']options[:ws_port]=pusher_options['port']if!encryptedandpusher_options['port']options[:ws_path]=pusher_options['path']ifpusher_options['path']options[:ws_path]='/'<<options[:ws_path]unlessoptions[:ws_path].nil?oroptions[:ws_path].start_with?'/'options[:ssl_verify]=session.ssl.fetch(:verify,true)optionsenddefpusher_keysession.config.fetch('pusher').fetch('key')rescueIndexErrorraiseTravis::Client::Error,"#{session.api_endpoint} is missing pusher key"endendendend