# coding: utf-8 # Copyright 2019 DragonRuby LLC # MIT License # api.rb has been released under MIT (*only this file*). module GTK class Api def initialize end def get_api_autocomplete args, req html = <<-S DragonRuby Game Toolkit Documentation
index
code

      
#{links} S req.respond 200, html, { 'Content-Type' => 'text/html' } end def post_api_autocomplete args, req json = ($gtk.parse_json req.body) index = json["index"].to_i text = json["text"] suggestions = args.gtk.suggest_autocompletion index: index, text: text list_as_string = suggestions.join("\n") req.respond 200, list_as_string, { 'Content-Type' => 'text/plain' } end define_method :links do <<-S S end def get_index args, req req.respond 200, <<-S, { 'Content-Type' => 'text/html' } DragonRuby Game Toolkit Documentation #{links} S end def source_code_links args links = args.gtk.reload_list_history.keys.map do |f| "
  • #{f}
  • " end <<-S S end def get_api_code args, req view = <<-S DragonRuby Game Toolkit Documentation #{source_code_links args} #{links} S req.respond 200, view, { 'Content-Type' => 'text/html' } end def code_edit_view args, file view = <<-S DragonRuby Game Toolkit Documentation
    #{file}:

    #{source_code_links args} #{links} S end def get_api_code_edit args, req file = req.uri.split('?').last.gsub("file=", "") view = code_edit_view args, file req.respond 200, view, { 'Content-Type' => 'text/html' } end def post_api_code_update args, req file = req.uri.split('?').last.gsub("file=", "") code = ($gtk.parse_json req.body)["code"] args.gtk.write_file file, code view = code_edit_view args, file req.respond 200, view, { 'Content-Type' => 'text/html' } end def get_api_boot args, req req.respond 200, args.gtk.read_file("tmp/src_backup/boot.txt"), { 'Content-Type' => 'text/plain' } end def get_api_trace args, req req.respond 200, args.gtk.read_file("logs/trace.txt"), { 'Content-Type' => 'text/plain' } end def get_api_log args, req req.respond 200, args.gtk.read_file("logs/log.txt"), { 'Content-Type' => 'text/plain' } end def post_api_log args, req Log.log req.body req.respond 200, "ok", { 'Content-Type' => 'text/plain' } end def get_api_puts args, req req.respond 200, args.gtk.read_file("logs/puts.txt"), { 'Content-Type' => 'text/plain' } end def get_api_changes args, req req.respond 200, args.gtk.read_file("tmp/src_backup/src_backup_changes.txt"), { 'Content-Type' => 'text/plain' } end def get_favicon_ico args, req @favicon ||= args.gtk.read_file('docs/favicon.ico') req.respond 200, @favicon, { "Content-Type" => 'image/x-icon' } end def get_src_backup args, req file_name = req.uri.gsub("/dragon/", "") req.respond 200, args.gtk.read_file("tmp/src_backup/#{file_name}"), { 'Content-Type' => 'text/plain' } end def get_not_found args, req puts("METHOD: #{req.method}"); puts("URI: #{req.uri}"); puts("HEADERS:"); req.headers.each { |k,v| puts(" #{k}: #{v}") } req.respond 404, "not found: #{req.uri}", { } end def get_docs_html args, req req.respond 200, args.gtk.read_file("docs/docs.html"), { 'Content-Type' => 'text/html' } end def get_docs_css args, req req.respond 200, args.gtk.read_file("docs/docs.css"), { 'Content-Type' => 'text/css' } end def get_docs_search_gif args, req req.respond 200, args.gtk.read_file("docs/docs_search.gif"), { 'Content-Type' => 'image/gif' } end def get_src_backup_index_html args, req req.respond 200, args.gtk.read_file("/tmp/src_backup/src_backup_index.html"), { 'Content-Type' => 'text/html' } end def get_src_backup_index_txt args, req req.respond 200, args.gtk.read_file("/tmp/src_backup/src_backup_index.txt"), { 'Content-Type' => 'text/txt' } end def get_src_backup_css args, req req.respond 200, args.gtk.read_file("/tmp/src_backup/src_backup.css"), { 'Content-Type' => 'text/css' } end def get_src_backup_changes_html args, req req.respond 200, args.gtk.read_file("/tmp/src_backup/src_backup_changes.html"), { 'Content-Type' => 'text/html' } end def get_src_backup_changes_txt args, req req.respond 200, args.gtk.read_file("/tmp/src_backup/src_backup_changes.txt"), { 'Content-Type' => 'text/txt' } end def get_api_eval args, req eval_view = <<-S Eval

    curl -H "Content-Type: application/json" --data '{ "code": "$result = $args.state" }' -X POST http://localhost:9001/dragon/eval/
    Eval Result:
    
        #{links}
      
    
    S
          req.respond 200,
                      eval_view,
                      { 'Content-Type' => 'text/html' }
        end
    
        def post_api_eval args, req
          if json? req
            code = ($gtk.parse_json req.body)["code"]
            code = code.gsub("$result", "$eval_result")
            Object.new.instance_eval do
              begin
                Kernel.eval code
              rescue Exception => e
                $eval_result = e
              end
            end
          end
    
          req.respond 200,
                      "#{$eval_result || $eval_results || "nil"}",
                      { 'Content-Type' => 'text/plain' }
    
          $eval_result  = nil
          $eval_results = nil
        end
    
        def api_css_string
    
        end
    
        def get_api_console args, req
          html = console_view "# write your code here and set $result.\n$result = $gtk.args.state"
          req.respond 200,
                      html,
                      { 'Content-Type' => 'text/html' }
        end
    
        def control_panel_view
          <<-S
    
      console
      
        
        
    #{links} S end def get_api_control_panel args, req req.respond 200, control_panel_view, { 'Content-Type' => 'text/html' } end def json? req req.headers.find { |k, v| k == "Content-Type" && (v.include? "application/json") } end def post_api_reset args, req $gtk.reset if json? req req.respond 200, control_panel_view, { 'Content-Type' => 'text/html' } end def post_api_record args, req $recording.start 100 if json? req req.respond 200, control_panel_view, { 'Content-Type' => 'text/html' } end def post_api_record_stop args, req $recording.stop 'replay.txt' if json? req req.respond 200, control_panel_view, { 'Content-Type' => 'text/html' } end def post_api_replay args, req $replay.start 'replay.txt' if json? req req.respond 200, control_panel_view, { 'Content-Type' => 'text/html' } end def post_api_show_console args, req $gtk.console.show if json? req req.respond 200, control_panel_view, { 'Content-Type' => 'text/html' } end def tick args args.inputs.http_requests.each do |req| match_candidate = { method: req.method.downcase.to_sym, uri: req.uri, uri_without_query_string: (req.uri.split '?').first, query_string: (req.uri.split '?').last, has_query_string: !!(req.uri.split '?').last, has_api_prefix: (req.uri.start_with? "/dragon"), end_with_rb: (req.uri.end_with? ".rb"), has_file_extension: file_extensions.find { |f| req.uri.include? f }, has_trailing_slash: (req.uri.split('?').first.end_with? "/") } if !match_candidate[:has_file_extension] if !match_candidate[:has_trailing_slash] match_candidate[:uri] = match_candidate[:uri_without_query_string] + "/" if match_candidate[:query_string] match_candidate[:uri] += "?#{match_candidate[:query_string]}" end end end context = { args: args, req: req, match_candidate: match_candidate } process! context: context, routes: routes end end def url_decode args, string args.fn.gsub string, '+', " ", '%27', "'", '%22', '"', '%0D%0A', "\n", '%3D', "=", '%3B', ";", '%7C', "|", '%28', "(", '%29', ")", '%7B', "{", '%7D', "}", '%2C', ",", '%3A', ":", '%5B', "[", '%5D', "]", '%23', "#", '%21', "!", '%3C', "<", '%3E', ">", '%2B', "+", '%2F', "/", '%40', "@", '%3F', "?", '%26', "&", '%24', "$", '%5C', "\\", '%60', "`", '%7E', "~", '%C2%B2', "²", '%5E', "^", '%C2%BA', "º", '%C2%A7', "§", '%20', " ", '%0A', "\n", '%25', "%", '%2A', "*" end def file_extensions [".html", ".css", ".gif", ".txt", ".ico", ".rb"] end def routes [{ match_criteria: { method: :get, uri: "/" }, handler: :get_index }, { match_criteria: { method: :get, uri: "/dragon/" }, handler: :get_index }, { match_criteria: { method: :get, uri: "/dragon/boot/" }, handler: :get_api_boot }, { match_criteria: { method: :get, uri: "/dragon/trace/" }, handler: :get_api_trace }, { match_criteria: { method: :get, uri: "/dragon/puts/" }, handler: :get_api_puts }, { match_criteria: { method: :get, uri: "/dragon/log/" }, handler: :get_api_log }, { match_criteria: { method: :post, uri: "/dragon/log/" }, handler: :post_api_log }, { match_criteria: { method: :get, uri: "/dragon/changes/" }, handler: :get_api_changes }, { match_criteria: { method: :get, uri: "/dragon/eval/" }, handler: :get_api_eval }, { match_criteria: { method: :post, uri: "/dragon/eval/" }, handler: :post_api_eval }, { match_criteria: { method: :get, uri: "/dragon/console/" }, handler: :get_api_console }, { match_criteria: { method: :post, uri: "/dragon/console/" }, handler: :post_api_console }, { match_criteria: { method: :get, uri: "/dragon/control_panel/" }, handler: :get_api_control_panel }, { match_criteria: { method: :post, uri: "/dragon/reset/" }, handler: :post_api_reset }, { match_criteria: { method: :post, uri: "/dragon/record/" }, handler: :post_api_record }, { match_criteria: { method: :post, uri: "/dragon/record_stop/" }, handler: :post_api_record_stop }, { match_criteria: { method: :post, uri: "/dragon/replay/" }, handler: :post_api_replay }, { match_criteria: { method: :post, uri: "/dragon/show_console/" }, handler: :post_api_show_console }, { match_criteria: { method: :get, uri: "/dragon/code/" }, handler: :get_api_code }, { match_criteria: { method: :get, uri: "/dragon/autocomplete/" }, handler: :get_api_autocomplete }, { match_criteria: { method: :post, uri: "/dragon/autocomplete/" }, handler: :post_api_autocomplete }, { match_criteria: { method: :get, uri_without_query_string: "/dragon/code/edit/", has_query_string: true }, handler: :get_api_code_edit }, { match_criteria: { method: :post, uri_without_query_string: "/dragon/code/update/", has_query_string: true }, handler: :post_api_code_update }, { match_criteria: { method: :get, uri: "/docs.html" }, handler: :get_docs_html }, { match_criteria: { method: :get, uri_without_query_string: "/docs.css" }, handler: :get_docs_css }, { match_criteria: { method: :get, uri: "/docs_search.gif" }, handler: :get_docs_search_gif }, { match_criteria: { method: :get, uri: "/src_backup_index.html" }, handler: :get_src_backup_index_html }, { match_criteria: { method: :get, uri: "/src_backup_index.txt" }, handler: :get_src_backup_index_txt }, { match_criteria: { method: :get, uri: "/src_backup_changes.html" }, handler: :get_src_backup_changes_html }, { match_criteria: { method: :get, uri: "/src_backup_changes.txt" }, handler: :get_src_backup_changes_txt }, { match_criteria: { method: :get, uri: "/src_backup.css" }, handler: :get_src_backup_css }, { match_criteria: { method: :get, uri: "/favicon.ico" }, handler: :get_favicon_ico }, { match_criteria: { method: :get, end_with_rb: true }, handler: :get_src_backup }, { match_criteria: { method: :get, end_with_rb: true }, handler: :get_src_backup } ] end def process! opts routes = opts[:routes] context = opts[:context] routes.each do |route| match_found = (process_single! route: route, context: context) return if match_found end end def process_single! opts match_criteria = opts[:route][:match_criteria] m = opts[:route][:handler] args = opts[:context][:args] req = opts[:context][:req] match_candidate = opts[:context][:match_candidate] match_criteria.each do |k, v| return false if match_candidate[k] != v end begin send m, args, req rescue Exception => e req.respond 200, "#{e}\n#{e.__backtrace_to_org__}", { 'Content-Type' => 'text/plain' } end return true end end end