Top Level Namespace

Defined Under Namespace

Modules: Syntropy

Constant Summary collapse

TAG_DEBUG_PROC =
->(level, fn, line, col) {
  {
    'data-syntropy-level' => level,
    'data-syntropy-fn'    => fn,
    'data-syntropy-loc'   => "vscode://file/#{fn}:#{line}:#{col}"
  }
}
ErrorPage =
->(error:, status:, backtrace:) {
  html {
    head {
      title "Syntropy error: #{error.message}"
      meta charset: 'utf-8'
      meta name: 'viewport', content: 'width=device-width, initial-scale=1.0'
      link rel: 'stylesheet', type: 'text/css', href: '/.syntropy/default_error_handler/style.css'
    }
    body {
      div {
        big status
        h2 error.message
        if backtrace
          p "Backtrace:"
          ul {
            backtrace.each {
              li {
                a(it[:entry], href: it[:url])
              }
            }
          }
        end
      }
      auto_refresh_watch!
    }
  }
}

Instance Method Summary collapse

Instance Method Details

#call(req) ⇒ Object

Handles incoming requests to the ‘watch.sse` route. Adds a queue to the list of watchers, and waits for the queue to be signalled. In the absence of file change, a timeout occurs after one minute, and the request is terminated.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/syntropy/applets/builtin/auto_refresh/watch.sse.rb', line 24

def call(req)
  queue = UM::Queue.new
  watchers[queue] = true

  req.send_headers('Content-Type' => 'text/event-stream')
  req.send_chunk("data: \n\n")
  @machine.timeout(60, Timeout::Error) do
    @machine.shift(queue)
    req.send_chunk("data: refresh\n\n")
  end
  req.send_chunk("retry: 0\n\n", done: true) rescue nil
rescue Timeout::Error
  req.send_chunk("retry: 0\n\n", done: true) rescue nil
rescue SystemCallError
  # ignore
rescue => e
  @logger&.error(
    message: 'Unexpected error encountered while serving auto refresh watcher',
    error: e
  )
  req.finish rescue nil
ensure
  watchers.delete(queue)
end

#error_response_html(req, error) ⇒ Object



38
39
40
41
42
43
# File 'lib/syntropy/applets/builtin/default_error_handler.rb', line 38

def error_response_html(req, error)
  status = Syntropy::Error.http_status(error)
  backtrace = transform_backtrace(error.backtrace)
  html = Papercraft.html(ErrorPage, error:, status:, backtrace:)
  req.html_response(html, ':status' => status)
end

#error_response_raw(req, error) ⇒ Object



45
46
47
48
49
50
51
52
53
# File 'lib/syntropy/applets/builtin/default_error_handler.rb', line 45

def error_response_raw(req, error)
  status = Syntropy::Error.http_status(error)
  response = {
    class: error.class.to_s,
    message: error.message,
    backtrace: error.backtrace
  }
  req.json_pretty_response(response, ':status' => status)
end

#signal!Object

Signals a file change by pushing to all watcher queues.



17
18
19
# File 'lib/syntropy/applets/builtin/auto_refresh/watch.sse.rb', line 17

def signal!
  watchers.each_key { @machine.push(it, true) }
end

#transform_backtrace(backtrace) ⇒ Object



31
32
33
34
35
36
# File 'lib/syntropy/applets/builtin/default_error_handler.rb', line 31

def transform_backtrace(backtrace)
  backtrace.map do
    location = it.match(/^(.+:\d+):/)[1]
    { entry: it, url: "vscode://file/#{location}" }
  end
end

#watchersObject

Returns a hash holding references to queues for ongoing ‘watch.sse` requests.



12
13
14
# File 'lib/syntropy/applets/builtin/auto_refresh/watch.sse.rb', line 12

def watchers
  @watchers ||= {}
end