class Locker::Label::Label

Proper Resource class

Attributes

id[R]

Public Class Methods

create(key) click to toggle source
# File lib/locker/label.rb, line 33
def self.create(key)
  raise 'Label key already exists' if Label.exists?(key)
  redis.sadd('label-list', Label.normalize(key))
  l = Label.new(key)
  l.state    = 'unlocked'
  l.owner_id = ''
  l.log('Created')
  l
end
delete(key) click to toggle source
# File lib/locker/label.rb, line 43
def self.delete(key)
  raise 'Unknown label key' unless Label.exists?(key)
  %w[state owner_id membership wait_queue journal observer_ids].each do |item|
    redis.del("label:#{key}:#{item}")
  end
  redis.srem('label-list', Label.normalize(key))
end
exists?(key) click to toggle source
# File lib/locker/label.rb, line 29
def self.exists?(key)
  redis.sismember('label-list', Label.normalize(key))
end
list() click to toggle source
# File lib/locker/label.rb, line 51
def self.list
  redis.smembers('label-list').sort
end
new(key) click to toggle source
# File lib/locker/label.rb, line 24
def initialize(key)
  raise 'Unknown label key' unless Label.exists?(key)
  @id = Label.normalize(key)
end
normalize(key) click to toggle source
# File lib/locker/label.rb, line 55
def self.normalize(key)
  key.strip.downcase
end

Public Instance Methods

add_observer!(observer_id) click to toggle source
# File lib/locker/label.rb, line 127
def add_observer!(observer_id)
  observer_ids.add(observer_id)
end
add_resource(resource) click to toggle source
# File lib/locker/label.rb, line 149
def add_resource(resource)
  log("Resource #{resource.id} added")
  resource.labels << id
  membership << resource.id
end
dedupe!() click to toggle source
# File lib/locker/label.rb, line 119
def dedupe!
  queued = wait_queue.to_a
  wait_queue.clear
  queued.chunk { |x| x }.map(&:first).each do |user|
    wait_queue << user
  end
end
give!(recipient_id) click to toggle source
# File lib/locker/label.rb, line 112
def give!(recipient_id)
  log("Given from #{owner.id} to #{recipient_id}")
  wait_queue.unshift(recipient_id)
  dedupe!
  unlock!
end
held_for() click to toggle source
# File lib/locker/label.rb, line 166
def held_for
  return '' unless locked?
  TimeLord::Time.new(Time.parse(taken_at.value) - 1).period.to_words
end
lock!(owner_id) click to toggle source
# File lib/locker/label.rb, line 59
def lock!(owner_id)
  if locked?
    wait_queue << owner_id if wait_queue.last != owner_id
    return false
  end

  coord_lock.lock do
    membership.each do |resource_name|
      r = Locker::Resource::Resource.new(resource_name)
      return false if r.locked?
    end
    # TODO: read-modify-write cycle, not the best
    membership.each do |resource_name|
      r = Locker::Resource::Resource.new(resource_name)
      r.lock!(owner_id)
    end
    self.owner_id = owner_id
    self.state = 'locked'
    self.taken_at = Time.now.utc
  end
  u = Lita::User.fuzzy_find(owner_id)
  log("Locked by #{u.name}")
  true
end
locked?() click to toggle source
# File lib/locker/label.rb, line 139
def locked?
  (state == 'locked')
end
log(statement) click to toggle source
# File lib/locker/label.rb, line 185
def log(statement)
  journal << "#{Time.now.utc}: #{statement}"
end
observer?(observer_id) click to toggle source
# File lib/locker/label.rb, line 135
def observer?(observer_id)
  observer_ids.member?(observer_id)
end
observers() click to toggle source
# File lib/locker/label.rb, line 143
def observers
  observer_ids.map do |observer_id|
    Lita::User.find_by_id(observer_id)
  end
end
owner() click to toggle source
# File lib/locker/label.rb, line 161
def owner
  return nil unless locked?
  Lita::User.find_by_id(owner_id.value)
end
remove_observer!(observer_id) click to toggle source
# File lib/locker/label.rb, line 131
def remove_observer!(observer_id)
  observer_ids.delete(observer_id)
end
remove_resource(resource) click to toggle source
# File lib/locker/label.rb, line 155
def remove_resource(resource)
  log("Resource #{resource.id} removed")
  resource.labels.delete(id)
  membership.delete(resource.id)
end
steal!(owner_id) click to toggle source
# File lib/locker/label.rb, line 105
def steal!(owner_id)
  log("Stolen from #{owner.id} to #{owner_id}")
  wait_queue.unshift(owner_id)
  dedupe!
  unlock!
end
to_json() click to toggle source
# File lib/locker/label.rb, line 171
def to_json
  val = { id: id,
          state: state.value,
          membership: membership }

  if locked?
    val[:owner_id] = owner_id.value
    val[:taken_at] = taken_at.value
    val[:wait_queue] = wait_queue
  end

  val.to_json
end
unlock!() click to toggle source
# File lib/locker/label.rb, line 84
def unlock!
  return true if state == 'unlocked'
  coord_lock.lock do
    self.owner_id = ''
    self.state = 'unlocked'
    self.taken_at = ''
    membership.each do |resource_name|
      r = Locker::Resource::Resource.new(resource_name)
      r.unlock!
    end
  end
  log('Unlocked')

  # FIXME: Possible race condition where resources become unavailable between unlock and relock
  if wait_queue.count > 0
    next_user = wait_queue.shift
    lock!(next_user)
  end
  true
end