Class: AsyncRender::Middleware

Inherits:
Object
  • Object
show all
Defined in:
lib/async_render/middleware.rb

Constant Summary collapse

HTML_TYPE =
%r{\Atext/html}.freeze
PATTERN_PREFIX =
"<!--ASYNC-PLACEHOLDER:".freeze
PATTERN_REGEXP =
/<!--ASYNC-PLACEHOLDER:([0-9a-z\.\/]+)-->/.freeze

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ Middleware

Returns a new instance of Middleware.



13
14
15
# File 'lib/async_render/middleware.rb', line 13

def initialize(app)
  @app = app
end

Instance Method Details

#call(env) ⇒ Object

# puts 2

      # puts html2
    end
  end
end

end



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/async_render/middleware.rb', line 53

def call(env)
  status, headers, body = @app.call(env)

  return [ status, headers, body ] if skip?

  if html?(headers)
    html = +""
    begin
      body.each { |part| html << part }
    ensure
      body.close if body.respond_to?(:close)
    end

    return [ status, headers, [ html ] ] if !html.include?(PATTERN_PREFIX)

    # Wait with timeout and collect fragments
    token_to_fragment = {}
    futures_hash = AsyncRender::Current.async_futures

    if futures_hash.any?
      # Create array of [token, future] pairs to maintain association
      futures_array = futures_hash.to_a

      # Wait for all futures to complete with timeout
      all_futures = Concurrent::Promises.zip(*futures_array.map(&:last))
      all_futures.wait(AsyncRender.timeout)

      # Collect results - check each future individually
      futures_array.each do |token, future|
        token_to_fragment[token] = future.fulfilled? ? future.value : ""
      end
    end

    # token_to_fragment.each do |token, fragment|
    #   Rails.logger.info { "[AsyncRender] Replacing: #{token}" } if Rails.env.local?
    #   html[token] = fragment
    # end

    # Single-pass replacement using regex
    html.gsub!(PATTERN_REGEXP) do |match|
      token = Regexp.last_match(1)
      Rails.logger.info { "[AsyncRender] Replacing: #{token}" } if Rails.env.local?
      token_to_fragment.fetch(token, "")
    end

    AsyncRender::Current.async_futures.clear
    AsyncRender::Current.warmup_partials.clear

    headers["Content-Length"] = html.bytesize.to_s if headers["Content-Length"]
    [ status, headers, [ html ] ]
  else
    [ status, headers, body ]
  end
end