Class: CopyTunerClient::Cache

Inherits:
Object
  • Object
show all
Defined in:
lib/copy_tuner_client/cache.rb

Overview

Manages synchronization of copy between I18nBackend and Client. Acts like a Hash. Applications using the client will not need to interact with this class directly.

Responsible for locking down access to data used by both threads.

Constant Summary collapse

STATUS_NOT_READY =

rubocop:disable Metrics/ClassLength

:not_ready
STATUS_PENDING =
:pending
STATUS_READY =
:ready

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client, options) ⇒ Cache

Usually instantiated when CopyTunerClient::Configuration#apply is invoked.

Parameters:

  • client (Client)

    the client used to fetch and upload data

  • options (Hash)

Options Hash (options):

  • :logger (Logger)

    where errors should be logged



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/copy_tuner_client/cache.rb', line 19

def initialize(client, options)
  @client = client
  @logger = options[:logger]
  @mutex = Mutex.new
  @exclude_key_regexp = options[:exclude_key_regexp]
  @local_first_key_regexp = options[:local_first_key_regexp]
  @upload_disabled = options[:upload_disabled]
  @ignored_keys = options.fetch(:ignored_keys, [])
  @ignored_key_handler = options.fetch(:ignored_key_handler, -> (e) { raise e })
  @locales = Array(options[:locales]).map(&:to_s)
  # mutable states
  @blurbs = {}
  @blank_keys = Set.new
  @queued = {}
  @status = STATUS_NOT_READY
end

Instance Attribute Details

#blank_keysObject (readonly)

blank_keys を公開しているのは、MCP ツール等の外部利用者が「キーは登録済みだが翻訳なし」と「キー未登録」を区別するため(このリポジトリ内では参照箇所がない)。



38
39
40
# File 'lib/copy_tuner_client/cache.rb', line 38

def blank_keys
  @blank_keys
end

#blurbsObject (readonly)

blank_keys を公開しているのは、MCP ツール等の外部利用者が「キーは登録済みだが翻訳なし」と「キー未登録」を区別するため(このリポジトリ内では参照箇所がない)。



38
39
40
# File 'lib/copy_tuner_client/cache.rb', line 38

def blurbs
  @blurbs
end

#last_downloaded_atObject (readonly)

blank_keys を公開しているのは、MCP ツール等の外部利用者が「キーは登録済みだが翻訳なし」と「キー未登録」を区別するため(このリポジトリ内では参照箇所がない)。



38
39
40
# File 'lib/copy_tuner_client/cache.rb', line 38

def last_downloaded_at
  @last_downloaded_at
end

#last_uploaded_atObject (readonly)

blank_keys を公開しているのは、MCP ツール等の外部利用者が「キーは登録済みだが翻訳なし」と「キー未登録」を区別するため(このリポジトリ内では参照箇所がない)。



38
39
40
# File 'lib/copy_tuner_client/cache.rb', line 38

def last_uploaded_at
  @last_uploaded_at
end

#queuedObject (readonly)

blank_keys を公開しているのは、MCP ツール等の外部利用者が「キーは登録済みだが翻訳なし」と「キー未登録」を区別するため(このリポジトリ内では参照箇所がない)。



38
39
40
# File 'lib/copy_tuner_client/cache.rb', line 38

def queued
  @queued
end

Instance Method Details

#[](key) ⇒ String

Returns content for the given blurb.

Parameters:

  • key (String)

    the key of the desired blurb

Returns:

  • (String)

    the contents of the blurb



43
44
45
# File 'lib/copy_tuner_client/cache.rb', line 43

def [](key)
  lock { @blurbs[key] }
end

#[]=(key, value) ⇒ Object

Sets content for the given blurb. The content will be pushed to the server on the next flush.

Parameters:

  • key (String)

    the key of the blurb to update

  • value (String)

    the new contents of the blurb



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/copy_tuner_client/cache.rb', line 51

def []=(key, value)
  return if @exclude_key_regexp && key.match?(@exclude_key_regexp)
  return unless key.include?('.')
  return if @locales.present? && !@locales.member?(key.split('.').first)
  return if @upload_disabled

  # NOTE: config/locales以下のファイルに除外キーが残っていた場合の対応
  key_without_locale = key.split('.')[1..].join('.')
  # NOTE: local_first_key_regexp にマッチするキーは copy_tuner と完全分離するためアップロードしない
  return if @local_first_key_regexp && key_without_locale.match?(@local_first_key_regexp)

  if @ignored_keys.include?(key_without_locale)
    @ignored_key_handler.call(IgnoredKey.new("Ignored key: #{key_without_locale}"))
  end

  lock do
    return if @blank_keys.member?(key) || @blurbs.key?(key)

    @queued[key] = value
  end
end

#downloadObject



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/copy_tuner_client/cache.rb', line 124

def download
  @status = STATUS_PENDING unless ready?

  res = client.download(cache_fallback: pending?) do |downloaded_blurbs|
    blank_keys = Set.new
    blurbs = {}
    downloaded_blurbs.each { |key, value| value == '' ? blank_keys << key : blurbs[key] = value }
    lock do
      @blank_keys = blank_keys
      @blurbs = blurbs
    end
  end

  @last_downloaded_at = Time.now.utc
  @status = STATUS_READY unless ready?

  res
rescue ConnectionError => e
  logger.error e.message
  raise e unless ready?
end

#exportString

Yaml representation of all blurbs

Returns:

  • (String)

    yaml



81
82
83
84
# File 'lib/copy_tuner_client/cache.rb', line 81

def export
  tree_hash = to_tree_hash
  tree_hash.present? ? tree_hash.to_yaml : nil
end

#flushObject



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/copy_tuner_client/cache.rb', line 112

def flush
  res = with_queued_changes do |queued|
    client.upload queued
  end

  @last_uploaded_at = Time.now.utc

  res
rescue ConnectionError => e
  logger.error e.message
end

#inspectObject



152
153
154
# File 'lib/copy_tuner_client/cache.rb', line 152

def inspect
  "#<CopyTunerClient::Cache:#{object_id}>"
end

#keysArray<String>

Keys for all blurbs stored on the server.

Returns:

  • (Array<String>)

    keys



75
76
77
# File 'lib/copy_tuner_client/cache.rb', line 75

def keys
  lock { @blurbs.keys }
end

#pending?Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/copy_tuner_client/cache.rb', line 156

def pending?
  @status == STATUS_PENDING
end

#ready?Boolean

Returns:

  • (Boolean)


160
161
162
# File 'lib/copy_tuner_client/cache.rb', line 160

def ready?
  @status == STATUS_READY
end

#syncObject

Downloads and then flushes



147
148
149
150
# File 'lib/copy_tuner_client/cache.rb', line 147

def sync
  download
  flush
end

#to_tree_hashHash

ツリー構造のハッシュを返す(I18nBackend用)

Returns:

  • (Hash)

    ツリー構造に変換されたblurbs



88
89
90
# File 'lib/copy_tuner_client/cache.rb', line 88

def to_tree_hash
  lock { @blurbs.present? ? DottedHash.to_h(@blurbs) : {} }
end

#versionString?

キャッシュの更新バージョンを返す(ツリーキャッシュの無効化判定用)ETags を使用してサーバーサイドの更新を検知

Returns:

  • (String, nil)

    現在のETag値



95
96
97
# File 'lib/copy_tuner_client/cache.rb', line 95

def version
  client.etag
end

#wait_for_downloadObject

Waits until the first download has finished.



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/copy_tuner_client/cache.rb', line 100

def wait_for_download
  return unless pending?

  logger.info 'Waiting for first download'

  if logger.respond_to? :flush
    logger.flush
  end

  sleep 0.1 while pending?
end