Class: ToggleFleet::Client
- Inherits:
-
Object
- Object
- ToggleFleet::Client
- Defined in:
- lib/togglefleet.rb
Overview
A self-contained client. Use ToggleFleet.* for the process-wide singleton, or build your own (e.g. to talk to two environments at once): ToggleFleet::Client.new(config).
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
Instance Method Summary collapse
-
#all(actor: nil, groups: nil) ⇒ Object
Snapshot every known flag for an actor — handy for bootstrapping a JS client.
-
#enabled?(flag, actor: nil, groups: nil) ⇒ Boolean
The whole point: evaluate locally, no network call here.
-
#initialize(config) ⇒ Client
constructor
A new instance of Client.
-
#register_group(name, &block) ⇒ Object
Register a group predicate.
-
#start ⇒ Object
Pull the config once and start the background refresh thread.
-
#sync ⇒ Object
Force a refresh now (returns true if the config changed).
Constructor Details
#initialize(config) ⇒ Client
Returns a new instance of Client.
48 49 50 51 52 53 54 55 56 |
# File 'lib/togglefleet.rb', line 48 def initialize(config) @config = config @groups = {} # name => predicate proc @flags = {} # flag key => state hash @etag = nil @loaded = false @mutex = Mutex.new @poller = nil end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
46 47 48 |
# File 'lib/togglefleet.rb', line 46 def config @config end |
Instance Method Details
#all(actor: nil, groups: nil) ⇒ Object
Snapshot every known flag for an actor — handy for bootstrapping a JS client.
94 95 96 97 98 |
# File 'lib/togglefleet.rb', line 94 def all(actor: nil, groups: nil) ensure_loaded keys = @mutex.synchronize { @flags.keys } keys.each_with_object({}) { |k, h| h[k] = enabled?(k, actor: actor, groups: groups) } end |
#enabled?(flag, actor: nil, groups: nil) ⇒ Boolean
The whole point: evaluate locally, no network call here.
82 83 84 85 86 87 88 89 90 91 |
# File 'lib/togglefleet.rb', line 82 def enabled?(flag, actor: nil, groups: nil) ensure_loaded state = @mutex.synchronize { @flags[flag.to_s] } result = state ? evaluate(state, actor, groups) : @config.default @config.on_evaluation&.call(flag.to_s, actor, result) result rescue StandardError => e log("enabled?(#{flag}) error: #{e.class}: #{e.}") @config.default end |
#register_group(name, &block) ⇒ Object
Register a group predicate. Group membership is decided in YOUR code, so a flag enabled for :admins turns on for any actor where the block returns true.
60 61 62 63 64 |
# File 'lib/togglefleet.rb', line 60 def register_group(name, &block) raise ArgumentError, "register_group needs a block" unless block @mutex.synchronize { @groups[name.to_s] = block } self end |
#start ⇒ Object
Pull the config once and start the background refresh thread. Idempotent.
67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/togglefleet.rb', line 67 def start sync @mutex.synchronize do @poller ||= Thread.new do loop do sleep(@config.refresh_interval) begin; sync; rescue StandardError => e; log("refresh failed: #{e.class}: #{e.}"); end end end @poller.name = "togglefleet-refresh" if @poller.respond_to?(:name=) end self end |
#sync ⇒ Object
Force a refresh now (returns true if the config changed).
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/togglefleet.rb', line 101 def sync uri = URI.join(@config.url + "/", "v1/config") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = uri.scheme == "https" http.open_timeout = @config.open_timeout http.read_timeout = @config.read_timeout req = Net::HTTP::Get.new(uri) req["Authorization"] = "Bearer #{@config.sdk_key}" req["If-None-Match"] = @etag if @etag req["User-Agent"] = "togglefleet-ruby/#{VERSION}" res = http.request(req) case res when Net::HTTPNotModified false when Net::HTTPSuccess flags = JSON.parse(res.body).fetch("flags", {}) @mutex.synchronize { @flags = flags; @etag = res["ETag"]; @loaded = true } true when Net::HTTPUnauthorized raise Error, "invalid SDK key (401) — check config.sdk_key" else raise Error, "config fetch failed: HTTP #{res.code}" end end |