File: image_file_cache.rb

package info (click to toggle)
mikutter 3.5.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 10,256 kB
  • ctags: 2,165
  • sloc: ruby: 19,079; sh: 205; makefile: 20
file content (91 lines) | stat: -rw-r--r-- 2,430 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
# -*- coding: utf-8 -*-

require 'moneta'

Plugin.create :image_file_cache do

  @queue = Delayer.generate_class(priority: %i[none check_subdirs check_dirs],
                                  default: :none,
                                  expire: 0.02)
  @cache_directory = File.join(Environment::CACHE, 'image_file_cache').freeze
  @db = ::Moneta.build(&->(dir){ ->(this){
                                   this.use :Transformer, key: %i[md5 spread]
                                   this.adapter(:File, dir: dir)
                                 } }.(@cache_directory))

  on_image_file_cache_cache do |url|
    photos = Enumerator.new{|y|
      Plugin.filtering(:photo_filter, url, y)
    }
    Plugin.call(:image_file_cache_photo, photos.first)
  end

  on_image_file_cache_photo do |photo|
    cache_it(photo)
  end

  # キャッシュがあれば画像を返す
  filter_image_cache do |url, image, &stop|
    begin
      body = @db[url]
      if body
        stop.call([url, body]) end
      [url, image]
    rescue => e
      error e
      [url, image] end end

  # キャッシュの有効期限を秒単位で返す
  def cache_expire
    (UserConfig[:image_file_cache_expire] || 7) * 24 * 60 * 60 end

  def cache_it(photo)
    notice "cache added #{photo.uri}"
    photo.download.next{|downloaded|
      @db[downloaded.uri.to_s] = downloaded.blob
    }
  end

  def check_subdirs(dir)
    @queue.new(:check_subdirs) do
      Dir.foreach(dir)
        .map{|x| File.join(dir, x) }
        .select{|x| FileTest.file?(x) }
        .each{|x|
        Reserver.new((File.atime(x) rescue File.mtime(x)) + cache_expire, thread: SerialThread) do
          notice "cache deleted #{x}"
          File.delete(x) if FileTest.file?(x)
          if Dir.foreach(dir).select{|y| File.file? File.join(dir, y) }.empty?
            Dir.delete(dir) rescue nil end end
      }
    end
  end

  def check_dirs
    @queue.new(:check_dirs) do
      Dir.foreach(@cache_directory)
        .select{|x| x =~ %r<\A[a-fA-F0-9]{2}\Z> }
        .shuffle
        .each{|subdir|
        check_subdirs(File.join(@cache_directory, subdir))
      }
      Reserver.new(cache_expire, thread: SerialThread) do
        check_dirs end
    end
  end

  def _loop
    Reserver.new(60, thread: SerialThread) do
      if @queue
        @queue.run
        _loop  end end end

  on_unload do
    @db.close
    @db = @queue = nil
  end

  check_dirs
  _loop

end