require 'sinatra/base' require 'sinatra-websocket' require 'thin' module Junkie module Webinterface # Class that represents the web interface for junkie. It is based on # WebSockets, so that updates are sent to the connected clients. # class Interface < Sinatra::Base include Log, Config DEFAULT_CONFIG = { port: 8080, } set :server, 'thin' def self.setup(channels) @@channels = channels @@config = Config.get_config(self) set :port, @@config[:port] @@stats = Hash.new @@encrypted_episodes = Hash.new # every connected client connects to the following channel, so infos # pushed to this channel are transmitted to the clients @@ws_channel = EM::Channel.new # subscribe to the channel that holds the stats from various parts of # junkie @@channels[:info].subscribe do |info| @@stats[info[:key]] = info @@ws_channel.push(info) end # get new encrypted episode links @@channels[:episodes].subscribe do |episode| next unless episode.status == :encrypted @@encrypted_episodes[episode.uuid] = episode publish_encrypted_count end run! end def self.publish_encrypted_count @@channels[:push_episode_count].push(@@encrypted_episodes.length) @@channels[:info].push( { key: "Pending Encrypted Links", desc: "Number of encrypted links that need to be decrypted.", value: @@encrypted_episodes.length, additional: @@encrypted_episodes.values.map { |e| "%s (%s)" % [e.series, e.id] } } ) end get '/' do if !request.websocket? @junkie_version = Junkie::VERSION @server = request.host_with_port erb :index else request.websocket do |ws| ws.onopen do log.debug("Opened WebSocket from #{ request.ip }") # send all cached stats to the client @@stats.values.each { |s| ws.send(s.to_json) } @@ws_channel.subscribe do |info| ws.send(info.to_json) end end ws.onclose do log.debug("Closed WebSocket from #{ request.ip }") # TODO unsubscribe from @@ws_channel end end end end get '/links/encrypted' do content_type :json @@encrypted_episodes.values.map {|e| e.to_hash }.to_json end post '/links/decrypt/:uuid' do uuid = params["uuid"] decrypted_links = JSON.parse(request.body.read).fetch("links") { [] } if @@encrypted_episodes.has_key?(uuid) and !decrypted_links.empty? episode = @@encrypted_episodes.delete(uuid) episode.status = :decrypted episode.links = decrypted_links @@channels[:episodes].push(episode) Interface.publish_encrypted_count status 201 decrypted_links.to_json else status 404 end end post "/app/:service" do registration_id = JSON.parse(request.body.read).fetch('regid') { nil } if params['service'] != 'gcm' or registration_id == nil status 404 else @@channels[:push_registration].push([:gcm, registration_id]) status 201 end end end end end