File: cache.rb

package info (click to toggle)
mikutter 3.8.6%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 10,544 kB
  • sloc: ruby: 20,548; sh: 99; makefile: 19
file content (112 lines) | stat: -rw-r--r-- 3,157 bytes parent folder | download
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# -*- coding: utf-8 -*-

require_relative "basic"
require "fileutils"
require 'digest/md5'

module MikuTwitter::Cache
  CACHE_EXPIRE = 60 * 60 * 24 * 2

  def cache(api, url, options, method)
    if :get == method and options[:cache]
      if(:keep == options[:cache])
        _cache_keep(api, url, options, method, &Proc.new)
      else
        _cache_get(api, url, options, method, &Proc.new) end
    else
      yield end end

  def cache_write(path, body)
    begin
      cachefn = cache_file_path(path)
      FileUtils.mkdir_p(File::dirname(cachefn))
      FileUtils.rm_rf(cachefn) if FileTest.exist?(cachefn) and not FileTest.file?(cachefn)
      file_put_contents(cachefn, body)
    rescue => e
      warn "cache write failed"
      warn e end end

  def cache_clear(path)
    begin
      FileUtils.rm_rf(cache_file_path(path))
    rescue => e
      warn "cache clear failed"
      warn e end end

  def get_cache(path)
    begin
      cache_path = cache_file_path(path)
      if FileTest.file?(cache_path)
        return Class.new{
          define_method(:body){
            file_get_contents(cache_path) }
          define_method(:code){
            '200' } }.new end
    rescue => e
      warn "cache read failed"
      warn e
      nil end end

  # パスからAPIのキャッシュファイルを返す
  # ==== Args
  # [path] APIのパス。例: "statuses/home_timeline.json?include_entities=1"
  # ==== Return
  # キャッシュファイルのローカルのパス
  def cache_file_path(path)
    cache_path = File.join(Environment::CACHE, 'mikutwitter'.freeze, account_identity, path)
    name, query_string = *cache_path.split('?', 2)
    if(query_string)
      md5_query_string = Digest::MD5.hexdigest(query_string)
      File::expand_path(File.join("#{name}.q", md5_query_string[0], md5_query_string))
    else
      File::expand_path(name)
    end
  end

  def self.garbage_collect
    begin
      delete_files = Dir.glob(File.expand_path(File.join(Environment::CACHE, '**'.freeze, '*'.freeze))).select(&method(:is_tooold))
      FileUtils.rm_rf(delete_files)
      delete_files
    rescue => e
      error e end end

  # キャッシュファイル _file_ が期限切れの場合真を返す。
  # ==== Args
  # [file] ファイル名
  # ==== Return
  # 削除すべきなら真
  def self.is_tooold(file)
    Time.now - File.mtime(file) > CACHE_EXPIRE end

  private
  def _cache_keep(api, url, options, method)
    path = "#{api}.json" + get_args(options)
    result = yield
    if result and '200' == result.code
      cache_write(path, result.body)
    else
      cached_value = get_cache(path)
      if cached_value
        return cached_value end end
    result
  rescue => e
    cached_value = get_cache(path)
    if cached_value
      cached_value
    else
      raise e end end

  def _cache_get(api, url, options, method)
    path = "#{api}.json" + get_args(options)
    cached_value = get_cache(path)
    if cached_value
      return cached_value end
    result = yield
    if result and '200' == result.code
      cache_write(path, result.body) end
    result end

end

class MikuTwitter; include MikuTwitter::Cache end