lowloop 0.8.5 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2560511646de0f4456ed7f395847af7c588f8093cebd669c2e0920845fc95bb
4
- data.tar.gz: ee11a83dad0dce1c414a0e4251f4e17cd708f95acea2e1f8e492c43a7f0434f1
3
+ metadata.gz: a30797b16bfdc71adaec6a4879217a777d27662498ce0a7a7213578657a2c7fc
4
+ data.tar.gz: 7ec9f60a96218d13b33d2c2cec0ffa4666f6ec5c0d52773cd7f8277e92722efc
5
5
  SHA512:
6
- metadata.gz: 01a65f0e4569f0c1b6fc2e61f5c05b68fa27e06aa958ee0445fde2cdbdf513d7d3e26094093795d3c139562c6062fd49673d0ef54c08f4862cb4fea0a2e1c11f
7
- data.tar.gz: b6c9b778c647d7730a255a887198ffe025051764eba9be5afd56af9b5e73a051797fa1268865da849a73a8acbee80ea84bde343fa0ceeceba3deecf680dfb6b2
6
+ metadata.gz: 3006e7ec87770b925233c906827ae98d5e1db05e200e3614b98401d30f6f90475c6541e6e5fbf582da74382a99ce7e279a389472096ef4d0e9aff12980f859e7
7
+ data.tar.gz: 7538373e1451c78fbaafa9ba046e43ca6106382449262dc5d044a18c5f2ebaa4e2a2a05ce0f0cb39780522b4384633afee57b8fa7bde1778814f7c9f3425d6b0
data/lib/lowloop.rb CHANGED
@@ -23,7 +23,7 @@ class LowLoop
23
23
  @frame = LowFrame.new(renderer: (renderer if config.matrix_mode), fps: 10, show_output:)
24
24
 
25
25
  Low::Events::RequestEvent.define do |observers|
26
- observers << Low::FileServer.new(web_root: config.web_root, content_types: config.content_types)
26
+ observers << Low::FileServer.new(web_root: config.web_root, content_types: config.content_types, cache_control: config.cache_control)
27
27
  observers << router if router
28
28
  observers.push(self, action: :mirror) if config.mirror_mode
29
29
  end
@@ -7,13 +7,28 @@ module Low
7
7
  class << self
8
8
  def request(event:)
9
9
  file = event.file
10
+ return nil unless File.exist?(file.path)
10
11
 
11
- if File.exist?(file.path)
12
- response = ResponseFactory.file(path: file.path, content_type: file.content_type)
13
- return Events::ResponseEvent.new(response:).tap(&:branch)
14
- end
12
+ path = file.path
13
+ cache_control = file.cache_control
14
+ return respond(ResponseFactory.not_modified(path:, cache_control:)) if unchanged?(path, event.request)
15
15
 
16
- nil
16
+ respond(ResponseFactory.file(path:, content_type: file.content_type, cache_control:))
17
+ end
18
+
19
+ private
20
+
21
+ def respond(response)
22
+ Events::ResponseEvent.new(response:).tap(&:branch)
23
+ end
24
+
25
+ def unchanged?(path, request)
26
+ since = request&.headers&.[]('if-modified-since')
27
+ return false unless since
28
+
29
+ File.mtime(path).to_i <= Time.httpdate(Array(since).first.to_s).to_i
30
+ rescue ArgumentError
31
+ false
17
32
  end
18
33
  end
19
34
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cgi'
4
+ require 'time'
4
5
  require 'protocol/http'
5
6
  require 'protocol/http/body/file'
6
7
 
@@ -13,13 +14,24 @@ module Low
13
14
  Protocol::HTTP::Response.new('HTTP/1.1', 200, headers, body)
14
15
  end
15
16
 
16
- def file(path:, content_type:)
17
- headers = Protocol::HTTP::Headers.new([['content-type', content_type]])
17
+ def file(path:, content_type:, cache_control: nil)
18
+ headers = Protocol::HTTP::Headers.new([['content-type', content_type], *cache_headers(path, cache_control)])
18
19
  file = File.open(path, 'rb')
19
20
  body = Protocol::HTTP::Body::File.new(file)
20
21
  Protocol::HTTP::Response.new('HTTP/1.1', 200, headers, body)
21
22
  end
22
23
 
24
+ def not_modified(path:, cache_control: nil)
25
+ headers = Protocol::HTTP::Headers.new(cache_headers(path, cache_control))
26
+ Protocol::HTTP::Response.new('HTTP/1.1', 304, headers, nil)
27
+ end
28
+
29
+ def cache_headers(path, cache_control)
30
+ headers = [['last-modified', File.mtime(path).httpdate]]
31
+ headers << ['cache-control', cache_control] if cache_control
32
+ headers
33
+ end
34
+
23
35
  # Shows the error and where it happened in debug mode (or show a 500 status).
24
36
  def error(error:, debug: false)
25
37
  headers = Protocol::HTTP::Headers.new([['content-type', 'text/html']])
@@ -11,9 +11,10 @@ module Low
11
11
  include LowType
12
12
  include Observers
13
13
 
14
- def initialize(web_root:, content_types:)
14
+ def initialize(web_root:, content_types:, cache_control: nil)
15
15
  @web_root = web_root
16
16
  @content_types = content_types.transform_keys(&:to_s)
17
+ @cache_control = cache_control
17
18
 
18
19
  observers(Events::FileEvent) << FileResponse
19
20
  end
@@ -27,6 +28,12 @@ module Low
27
28
  extension
28
29
  end
29
30
 
31
+ def cache_control(extension)
32
+ return @cache_control unless @cache_control.is_a?(Hash)
33
+
34
+ @cache_control.transform_keys(&:to_s)[extension]
35
+ end
36
+
30
37
  def request(event: Events::RequestEvent)
31
38
  file_path = event.request.path
32
39
 
@@ -37,7 +44,7 @@ module Low
37
44
  return nil if extension.nil?
38
45
 
39
46
  file_path = url.local_path(@web_root)
40
- file = States::FileState.new(path: file_path, content_type: @content_types[extension])
47
+ file = States::FileState.new(path: file_path, content_type: @content_types[extension], cache_control: cache_control(extension))
41
48
 
42
49
  Events::FileEvent.take(file:, request: event.request)
43
50
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Low
4
4
  module States
5
- FileState = Data.define(:path, :content_type)
5
+ FileState = Data.define(:path, :content_type, :cache_control) do
6
+ def initialize(path:, content_type:, cache_control: nil) = super
7
+ end
6
8
  end
7
9
  end
data/lib/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Low
4
4
  module Loop
5
- VERSION = '0.8.5'
5
+ VERSION = '0.8.6'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lowloop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.5
4
+ version: 0.8.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
10
+ date: 2026-11-13 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: async
@@ -160,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
160
160
  - !ruby/object:Gem::Version
161
161
  version: '0'
162
162
  requirements: []
163
- rubygems_version: 4.0.6
163
+ rubygems_version: 3.6.2
164
164
  specification_version: 4
165
165
  summary: An event-driven event loop
166
166
  test_files: []