#!/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
Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'template','template.html')))
end
end
class Put < Riddl::Implementation
def response
Dir.mkdir(File.join('data',@r.last)) rescue nil
File.write(File.join('data',@r.last,'num'),@p[0].value)
File.write(File.join('data',@r.last,'total'),@p[1].value)
File.write(File.join('data',@r.last,'style.url'),@p[2].value)
image = Typhoeus.get(@p[3].value).response_body rescue ''
File.write(File.join('data',@r.last,'image.xml'),image)
if @p[4]&.name == 'errors_url'
errors = Typhoeus.get(@p[4].value).response_body rescue ''
File.write(File.join('data',@r.last,'errors.xml'),errors)
end
if @p[4]&.name == 'info'
File.write(File.join('data',@r.last,'info.json'),@p[4].value)
end
if @p[5]&.name == 'info'
File.write(File.join('data',@r.last,'info.json'),@p[5].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 Delete < Riddl::Implementation
def response
if cbu = File.read(File.join('data',@r.last,'callback'))
send = { 'operation' => @p[0].value }
case send['operation']
when 'jump'
send['target'] = @p[1].value
when 'error'
send['reason'] = @p[1].value
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,'num')) rescue nil
File.unlink(File.join('data',@r.last,'total')) rescue nil
File.unlink(File.join('data',@r.last,'style.url')) rescue nil
File.unlink(File.join('data',@r.last,'image.xml')) rescue nil
File.unlink(File.join('data',@r.last,'errors.xml')) rescue nil
if @p[0].value == 'finish' || @p[0].value == 'error'
@a[0].send('reset')
end
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],'image.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],'image.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 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 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 '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!