#!/usr/bin/ruby # # This file is part of centurio.work/ing/commands. # # centurio.work/ing/commands is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # centurio.work/ing/commands is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along with # centurio.work/ing/commands (file COPYING in the main directory). If not, see # . require 'rubygems' require 'json' require 'xml/smart' require 'riddl/server' require 'fileutils' require 'typhoeus' class Get < Riddl::Implementation def response if @r[0] == 'test' Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'template','test.html'))) else Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'template','template.html'))) end end end class Put < Riddl::Implementation def response puts "AAAAAAAAAAAAAAAAAAA" Dir.mkdir(File.join('data',@r.last)) rescue nil File.write(File.join('data',@r.last,'style.url'),@p[0].value) File.write(File.join('data',@r.last,'document.xml'),@p[1].value) File.write(File.join('data',@r.last,'frames.json'),JSON.dump(JSON.parse('{"data":[]}'))) if @p[2]&.name == 'info' File.write(File.join('data',@r.last,'info.json'),@p[2].value) end File.write(File.join('data',@r.last,'callback'),@h['CPEE_CALLBACK']) @a[0].send('new') nil end def headers Riddl::Header.new('CPEE-CALLBACK', 'true') end end class NewFrame < Riddl::Implementation def response path = File.join('data',@r.last,'frames.json') file = File.read(path) data_hash = JSON::parse(file) #puts "Before " + JSON.dump(data_hash); data_hash["data"].each do | c | if doOverlap(c['lx'], c['ly'], c['rx'], c['ry'], @p[0].value.to_i, @p[1].value.to_i, (@p[0].value.to_i + @p[2].value.to_i - 1), (@p[1].value.to_i + @p[3].value.to_i - 1)) data_hash["data"].delete(c) end end hash = {lx: @p[0].value.to_i, ly: @p[1].value.to_i, rx: (@p[0].value.to_i + @p[2].value.to_i - 1), ry: (@p[1].value.to_i + @p[3].value.to_i - 1), url: @p[4].value}; File.write(path, JSON.dump(data_hash)) @a[0].send(JSON.dump(hash)) nil end end def doOverlap(l1x, l1y, r1x, r1y, l2x, l2y, r2x, r2y) if l1x > r2x || l2x > r1x return false; end if l1y > r2y || l2y > r1y return false; end return true; end class Delete < Riddl::Implementation def response if cbu = File.read(File.join('data',@r.last,'callback')) send = { 'operation' => @p[0].value } case send['operation'] when 'result' send['target'] = JSON::parse(@p[1].value.read) end cbu += '/' unless cbu[-1] == '/' Typhoeus.put(cbu, body: JSON::generate(send), headers: { 'content-type' => 'application/json'}) end File.unlink(File.join('data',@r.last,'callback')) rescue nil File.unlink(File.join('data',@r.last,'style.url')) rescue nil File.unlink(File.join('data',@r.last,'document.xml')) rescue nil File.unlink(File.join('data',@r.last,'info.json')) rescue nil @a[0].send('reset') nil end end class GetInfo < Riddl::Implementation #{{{ def response fname = File.join('data',@r[-2],'info.json') if File.exists? fname Riddl::Parameter::Complex.new('value','application/json',File.read(fname)) else @status = 404 end end end #}}} class GetLangs < Riddl::Implementation #{{{ def response fname = File.join('data',@r[-2],'document.xml') if File.exists? fname doc = XML::Smart.open_unprotected(fname) ndoc = XML::Smart.string('') doc.find('//@lang').each do |e| ndoc.root.add('language',e.value) end Riddl::Parameter::Complex.new('value','text/xml',ndoc.to_s) else @status = 404 end end end #}}} class GetStyle < Riddl::Implementation #{{{ def response fname = File.join('data',@r[-2],'style.url') if File.exists? fname Riddl::Parameter::Complex.new('url','text/plain',File.read(fname).strip) else @status = 404 end end end #}}} class GetDocument < Riddl::Implementation #{{{ def response fname = File.join('data',@r[-3],'document.xml') if File.exists? fname doc = XML::Smart.open_unprotected(fname) val = nil doc.find("//variant[@lang='#{@r[-1]}']").each do |e| val = e.text end if val Riddl::Parameter::Complex.new('url','text/plain',val.strip) else @status = 404 end else @status = 404 end end end #}}} class GetButton < Riddl::Implementation #{{{ def response fname = File.join('data',@r[-3],'document.xml') if File.exists? fname doc = XML::Smart.open_unprotected(fname) val = nil doc.find("//variant[@lang='#{@r[-1]}']").each do |e| val = e.attributes['button'] end if val Riddl::Parameter::Complex.new('url','text/plain',val.strip) else @status = 404 end else @status = 404 end end end #}}} class SSE < Riddl::SSEImplementation #{{{ def onopen signals = @a[0] signals.add self send 'started' end def onclose signals = @a[0] signals.remove self nil end end #}}} class Signaling # {{{ def initialize @binding = [] end def add(binding) @binding << binding end def remove(binding) @binding.delete(binding) end def length @binding.length end def send(value) @binding.each do |b| b.send(value) end end end #}}} server = Riddl::Server.new(File.join(__dir__,'/frames.xml'), :host => 'localhost') do |opts| accessible_description true cross_site_xhr true opts[:signals] = {} parallel do loop do opts[:signals].each do |k,v| v.send('keepalive') end sleep 5 end end on resource do on resource do |r| idx = r[:r][0] opts[:signals][idx] ||= Signaling.new run Get if get run NewFrame, opts[:signals][idx] if post 'frame' run Put, opts[:signals][idx] if put 'input' run Delete, opts[:signals][idx] if delete 'opa' run Delete, opts[:signals][idx] if delete 'opb' on resource 'sse' do run SSE, opts[:signals][idx] if sse end on resource 'languages' do run GetLangs if get end on resource 'style.url' do run GetStyle if get end on resource 'info.json' do run GetInfo if get end on resource 'buttons' do on resource '[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*' do run GetButton if get end end on resource 'documents' do on resource '[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*' do run GetDocument if get end end end end end.loop!