|
@@ -0,0 +1,463 @@
|
|
|
+#!/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
|
|
|
+# <http://www.gnu.org/licenses/>.
|
|
|
+
|
|
|
+require 'rubygems'
|
|
|
+require 'json'
|
|
|
+require 'xml/smart'
|
|
|
+require 'riddl/server'
|
|
|
+require 'fileutils'
|
|
|
+require 'typhoeus'
|
|
|
+
|
|
|
+# process:
|
|
|
+# https://centurio.work/customers/evva/flow/?monitor=https://centurio.work/flow-test/engine/729/
|
|
|
+
|
|
|
+
|
|
|
+class NewInstance < Riddl::Implementation
|
|
|
+ def response
|
|
|
+
|
|
|
+ entries = Dir.entries(File.join('data')).size
|
|
|
+ Dir.mkdir(File.join('data',entries.to_s)) rescue nil
|
|
|
+
|
|
|
+ Riddl::Parameter::Complex.new('text','text/plain',entries.to_s)
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+class Index < Riddl::Implementation
|
|
|
+ def response
|
|
|
+ Riddl::Parameter::Complex.new('url','text/html',File.open(File.join(__dir__,'template','index.html')))
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+class Builder < Riddl::Implementation
|
|
|
+ def response
|
|
|
+ Riddl::Parameter::Complex.new('url','text/html',File.open(File.join(__dir__,'template','builder.html')))
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+class DisplayForm < Riddl::Implementation
|
|
|
+ def response
|
|
|
+ #Riddl::Parameter::Complex.new('url','text/html',File.open(File.join('data',@r[0],'form_min.html')))
|
|
|
+ Riddl::Parameter::Complex.new('url','text/html',File.open(File.join(__dir__,'template','form.html')))
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+class SaveForm < Riddl::Implementation
|
|
|
+ def response
|
|
|
+ File.write(File.join('data',@r[0],'form.json'),@p[0].value.read)
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+class SaveHtmlForm < Riddl::Implementation
|
|
|
+ def response
|
|
|
+ file = File.read(File.join(__dir__,'template','form_min.html'))
|
|
|
+ File.write(File.join('data',@r[0],'form_min.html'),(file.sub! '<!--FormComesHere-->', @p[0].value.read))
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+class GetJson < Riddl::Implementation #{{{
|
|
|
+ def response
|
|
|
+ fname = File.join('data',@r[-2],'form.json')
|
|
|
+ if File.exists? fname
|
|
|
+ Riddl::Parameter::Complex.new('value','application/json',File.read(fname))
|
|
|
+ else
|
|
|
+ @status = 404
|
|
|
+ end
|
|
|
+ end
|
|
|
+end #}}}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+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')))
|
|
|
+ elsif @r[0] == 'menu'
|
|
|
+ Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'template','menu.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
|
|
|
+ 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":[]}')))
|
|
|
+
|
|
|
+
|
|
|
+ File.write(File.join('data',@r.last,'info.json'),JSON.dump(JSON.parse('{"x_amount":' + @p[2].value + ', "y_amount":' + @p[3].value + ', "lang":"' + @p[4].value + '", "langs":["' + @p[4].value + '"]}')))
|
|
|
+
|
|
|
+
|
|
|
+ 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)
|
|
|
+
|
|
|
+ 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
|
|
|
+
|
|
|
+# example
|
|
|
+# myObj = {
|
|
|
+# "lx":3,
|
|
|
+# "ly":3,
|
|
|
+# "rx":3,
|
|
|
+# "ry":3,
|
|
|
+# "url": {
|
|
|
+# "de-at":"xyz.at",
|
|
|
+# "en-us":"xyz.com"
|
|
|
+# }
|
|
|
+# }
|
|
|
+ urls = JSON::parse(@p[4].value);
|
|
|
+
|
|
|
+ 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: urls};
|
|
|
+ data_hash["data"].push(hash)
|
|
|
+ File.write(path, JSON.dump(data_hash))
|
|
|
+
|
|
|
+ #only send active url to client
|
|
|
+ infofile = File.join('data',@r.last,'info.json')
|
|
|
+ infojson = JSON::parse(File.read(infofile))
|
|
|
+ hash["url"] = urls[infojson["lang"]]
|
|
|
+
|
|
|
+ @a[0].send(JSON.dump(hash))
|
|
|
+ nil
|
|
|
+
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+class NewFramePut < Riddl::Implementation
|
|
|
+ def response
|
|
|
+ path = File.join('data',@r.last,'frames.json')
|
|
|
+ file = File.read(path)
|
|
|
+ data_hash = JSON::parse(file)
|
|
|
+
|
|
|
+ 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
|
|
|
+
|
|
|
+ urls = JSON::parse(@p[4].value);
|
|
|
+
|
|
|
+ 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: urls, callback: @h['CPEE_CALLBACK']};
|
|
|
+ data_hash["data"].push(hash)
|
|
|
+ File.write(path, JSON.dump(data_hash))
|
|
|
+
|
|
|
+ #only send active url to client
|
|
|
+ infofile = File.join('data',@r.last,'info.json')
|
|
|
+ infojson = JSON::parse(File.read(infofile))
|
|
|
+ hash["url"] = urls[infojson["lang"]]
|
|
|
+
|
|
|
+ @a[0].send(JSON.dump(hash))
|
|
|
+ nil
|
|
|
+
|
|
|
+ end
|
|
|
+
|
|
|
+ def headers
|
|
|
+ Riddl::Header.new('CPEE-CALLBACK', 'true')
|
|
|
+ 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 GetFrames < Riddl::Implementation #{{{
|
|
|
+ def response
|
|
|
+ fname = File.join('data',@r[-2],'frames.json')
|
|
|
+ if File.exists? fname
|
|
|
+
|
|
|
+ infofile = File.join('data',@r[-2],'info.json')
|
|
|
+ infojson = JSON::parse(File.read(infofile))
|
|
|
+
|
|
|
+ #remove not used languages
|
|
|
+ file = JSON::parse(File.read(fname))
|
|
|
+ file["data"].each do |child|
|
|
|
+ child["url"] = child["url"][infojson["lang"]]
|
|
|
+ end
|
|
|
+
|
|
|
+ Riddl::Parameter::Complex.new('value','application/json',JSON.dump(file))
|
|
|
+ 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('<languages/>')
|
|
|
+ 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 SetLang < Riddl::Implementation #{{{
|
|
|
+ def response
|
|
|
+ fname = File.join('data',@r[-2],'info.json')
|
|
|
+ if File.exists? fname
|
|
|
+ infojson = JSON::parse(File.read(fname))
|
|
|
+ infojson["lang"] = @p[0].value
|
|
|
+
|
|
|
+
|
|
|
+ #add to langs
|
|
|
+ if !infojson["langs"].include?(@p[0].value)
|
|
|
+ infojson["langs"].push(@p[0].value)
|
|
|
+ end
|
|
|
+
|
|
|
+ File.write(fname, JSON.dump(infojson))
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ @a[0].send('reset')
|
|
|
+ nil
|
|
|
+ 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__,'/forms.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
|
|
|
+ run Index if get
|
|
|
+ run NewInstance if post
|
|
|
+
|
|
|
+ on resource do |r|
|
|
|
+
|
|
|
+ run DisplayForm if get
|
|
|
+
|
|
|
+ on resource 'builder' do
|
|
|
+ run Builder if get
|
|
|
+ run SaveForm if post 'form'
|
|
|
+ run SaveHtmlForm if post 'htmlform'
|
|
|
+ end
|
|
|
+ on resource 'json' do
|
|
|
+ run GetJson if get
|
|
|
+ end
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ idx = r[:r][0]
|
|
|
+ opts[:signals][idx] ||= Signaling.new
|
|
|
+
|
|
|
+ run Put, opts[:signals][idx] if put 'input'
|
|
|
+
|
|
|
+ run NewFrame, opts[:signals][idx] if post 'frame'
|
|
|
+ run NewFramePut, opts[:signals][idx] if put 'frame'
|
|
|
+ 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
|
|
|
+ run SetLang, opts[:signals][idx] if post 'lang'
|
|
|
+ end
|
|
|
+ on resource 'style.url' do
|
|
|
+ run GetStyle if get
|
|
|
+ end
|
|
|
+ on resource 'frames.json' do
|
|
|
+ run GetFrames 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!
|