Class: Ovh::Client::Clock

Inherits:
Object
  • Object
show all
Defined in:
lib/ovh-client/client/clock.rb

Overview

Holds the offset between the OVH server clock and the local clock and supplies the signature timestamp. OVH rejects signatures whose timestamp drifts too far, so on a skewed host the offset is measured once (against OVH's /auth/time endpoint) and reused for every signed request.

Every access to @delta/@synced goes through a lock so a value written by one thread is visible to the others on runtimes without a global VM lock (JRuby, TruffleRuby), where an unsynchronized read could otherwise sign a request with a stale offset. The lock is a Monitor (reentrant), not a Mutex: #ensure_synced holds it while invoking the syncer, and the syncer calls #synchronize!, which re-acquires the same lock -- a plain Mutex would deadlock on that re-entry.

Instance Method Summary collapse

Constructor Details

#initialize(delta: 0, syncer: nil) ⇒ Clock

Returns a new instance of Clock.

Parameters:

  • delta (Integer) (defaults to: 0)

    initial offset in seconds

  • syncer (#call, nil) (defaults to: nil)

    callable that measures and applies the offset; invoked at most once by #ensure_synced



22
23
24
25
26
27
# File 'lib/ovh-client/client/clock.rb', line 22

def initialize(delta: 0, syncer: nil)
  @delta   = delta
  @syncer  = syncer
  @synced  = false
  @monitor = Monitor.new
end

Instance Method Details

#deltaInteger

Returns offset in seconds added to the local clock.

Returns:

  • (Integer)

    offset in seconds added to the local clock



35
36
37
# File 'lib/ovh-client/client/clock.rb', line 35

def delta
  @monitor.synchronize { @delta }
end

#ensure_syncedObject

Run the syncer exactly once. Guarded by the monitor so concurrent first requests trigger a single synchronization; the reentrant lock lets the syncer call #synchronize! without deadlocking.



57
58
59
60
61
62
63
64
# File 'lib/ovh-client/client/clock.rb', line 57

def ensure_synced
  @monitor.synchronize do
    break if @synced || @syncer.nil?

    @syncer.call
    @synced = true
  end
end

#nowInteger

Returns the OVH-aligned epoch used as the signature timestamp.

Returns:

  • (Integer)

    the OVH-aligned epoch used as the signature timestamp



30
31
32
# File 'lib/ovh-client/client/clock.rb', line 30

def now
  Time.now.to_i + @monitor.synchronize { @delta }
end

#synced?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'lib/ovh-client/client/clock.rb', line 39

def synced?
  @monitor.synchronize { @synced }
end

#synchronize!(delta) ⇒ Integer

Record a freshly measured offset and mark the clock synced so lazy synchronization won't run again.

Returns:

  • (Integer)

    the applied delta



46
47
48
49
50
51
52
# File 'lib/ovh-client/client/clock.rb', line 46

def synchronize!(delta)
  @monitor.synchronize do
    @delta  = delta
    @synced = true
  end
  delta
end