Top Level Namespace

Defined Under Namespace

Modules: Syntropy

Constant Summary collapse

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[:title], href: it[:url])
              }
            }
          }
        end
      }
      auto_refresh!
    }
  }
}
GEMS_DIR =
Gem.dir
SYNTROPY_DIR =
File.expand_path(File.join(__dir__, '../../../..'))

Instance Method Summary collapse

Instance Method Details

#call(req) ⇒ void

This method returns an undefined value.

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.

Parameters:



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/syntropy/applets/builtin/auto_refresh/watch.sse.rb', line 31

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 StandardError => 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



51
52
53
54
55
56
# File 'lib/syntropy/applets/builtin/default_error_handler.rb', line 51

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.respond_html(html, ':status' => status)
end

#error_response_raw(req, error) ⇒ Object



58
59
60
61
62
63
64
65
66
# File 'lib/syntropy/applets/builtin/default_error_handler.rb', line 58

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!void

This method returns an undefined value.

Signals a file change by pushing to all watcher queues.



21
22
23
# File 'lib/syntropy/applets/builtin/auto_refresh/watch.sse.rb', line 21

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

#transform_backtrace(backtrace) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/syntropy/applets/builtin/default_error_handler.rb', line 34

def transform_backtrace(backtrace)
  backtrace
    .map do
      if (m = it.match(/^(.+:\d+):?/))
        location = m[1]
        title = location.sub(GEMS_DIR, '...').sub(SYNTROPY_DIR, '...')
        { entry: it, url: "zed://file/#{location}", title: }
      else
        { entry: it, url: nil, title: it }
      end
    end
rescue Exception => e
  p e
  p e.backtrace
  exit!
end

#watchersHash

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

Returns:

  • (Hash)

    hash of watchers



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

def watchers
  @watchers ||= {}
end