forked from markjaquith/WP-TLC-Transients
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclass-tlc-transient.php
146 lines (128 loc) · 3.9 KB
/
class-tlc-transient.php
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<?php
class TLC_Transient {
public $key;
public $raw_key;
private $lock;
private $callback;
private $params;
private $expiration = 0;
private $extend_on_fail = 0;
private $force_background_updates = false;
public function __construct( $key ) {
$this->raw_key = $key;
$this->key = md5( $key );
}
public function get() {
$data = $this->raw_get();
if ( false === $data ) {
// Hard expiration
if ( $this->force_background_updates ) {
// In this mode, we never do a just-in-time update
// We return false, and schedule a fetch on shutdown
$this->schedule_background_fetch();
return false;
}
else {
// Bill O'Reilly mode: "We'll do it live!"
return $this->fetch_and_cache();
}
}
else {
// Soft expiration
if ( $data[0] !== 0 && $data[0] < time() )
$this->schedule_background_fetch();
return $data[1];
}
}
private function raw_get() {
return get_transient( 'tlc__' . $this->key );
}
private function schedule_background_fetch() {
if ( ! $this->has_update_lock() ) {
set_transient( 'tlc_up__' . $this->key, array( $this->new_update_lock(), $this->raw_key, $this->expiration, $this->callback, $this->params, $this->extend_on_fail ), 300 );
add_action( 'shutdown', array( $this, 'spawn_server' ) );
}
return $this;
}
private function has_update_lock() {
return (bool) $this->get_update_lock();
}
private function get_update_lock() {
$lock = get_transient( 'tlc_up__' . $this->key );
if ( $lock )
return $lock[0];
else
return false;
}
private function new_update_lock() {
$this->lock = uniqid( 'tlc_lock_', true );
return $this->lock;
}
public function fetch_and_cache() {
// If you don't supply a callback, we can't update it for you!
if ( empty( $this->callback ) )
return false;
if ( $this->has_update_lock() && ! $this->owns_update_lock() )
return; // Race... let the other process handle it
try {
$data = call_user_func_array( $this->callback, $this->params );
$this->set( $data );
} catch ( Exception $e ) {
if ( $this->extend_on_fail > 0 ) {
$data = $this->raw_get();
if ( $data ) {
$data = $data[1];
$old_expiration = $this->expiration;
$this->expiration = $this->extend_on_fail;
$this->set( $data );
$this->expiration = $old_expiration;
}
}
else {
$data = false;
}
}
$this->release_update_lock();
return $data;
}
private function owns_update_lock() {
return $this->lock == $this->get_update_lock();
}
public function set( $data ) {
// We set the timeout as part of the transient data.
// The actual transient has a far-future TTL. This allows for soft expiration.
$expiration = ( $this->expiration > 0 ) ? time() + $this->expiration : 0;
$transient_expiration = ( $this->expiration > 0 ) ? $this->expiration + 31536000 : 0; // 31536000 = 60*60*24*365 ~= one year
set_transient( 'tlc__' . $this->key, array( $expiration, $data ), $transient_expiration );
return $this;
}
private function release_update_lock() {
delete_transient( 'tlc_up__' . $this->key );
}
public function spawn_server() {
$server_url = home_url( '/?tlc_transients_request' );
wp_remote_post( $server_url, array( 'body' => array( '_tlc_update' => $this->lock, 'key' => $this->raw_key ), 'timeout' => 0.01, 'blocking' => false, 'sslverify' => apply_filters( 'https_local_ssl_verify', true ) ) );
}
public function updates_with( $callback, $params = array() ) {
$this->callback = $callback;
if ( is_array( $params ) )
$this->params = $params;
return $this;
}
public function expires_in( $seconds ) {
$this->expiration = (int) $seconds;
return $this;
}
public function extend_on_fail( $seconds ) {
$this->extend_on_fail = (int) $seconds;
return $this;
}
public function set_lock( $lock ) {
$this->lock = $lock;
return $this;
}
public function background_only() {
$this->force_background_updates = true;
return $this;
}
}