Index: branches/FileBackend/phase3/includes/filerepo/backend/FSFileBackend.php |
— | — | @@ -19,6 +19,9 @@ |
20 | 20 | |
21 | 21 | /** |
22 | 22 | * @see FileBackend::__construct() |
| 23 | + * Additional $config params include: |
| 24 | + * containerPaths : Map of container names to absolute file system paths |
| 25 | + * fileMode : Octal UNIX file permissions to use on files stored |
23 | 26 | */ |
24 | 27 | function __construct( array $config ) { |
25 | 28 | parent::__construct( $config ); |
Index: branches/FileBackend/phase3/includes/filerepo/backend/SwiftFileBackend.php |
— | — | @@ -9,22 +9,35 @@ |
10 | 10 | * Status messages should avoid mentioning the Swift account name |
11 | 11 | * Likewise, error suppression should be used to avoid path disclosure. |
12 | 12 | * |
| 13 | + * @FIXME: resuse connections with auto-connect and don't let connection |
| 14 | + * exceptions bubble up from read/write operations. |
| 15 | + * |
13 | 16 | * @ingroup FileBackend |
14 | 17 | */ |
15 | 18 | class SwiftFileBackend extends FileBackend { |
16 | | - protected $swiftuser, |
17 | | - $swiftkey, |
18 | | - $authurl, |
19 | | - $container; |
| 19 | + protected $swiftUser; // string |
| 20 | + protected $swiftKey; // string |
| 21 | + protected $swiftAuthUrl; // string |
| 22 | + protected $swiftProxyUser; // string |
20 | 23 | |
| 24 | + /** |
| 25 | + * @see FileBackend::__construct() |
| 26 | + * Additional $config params include: |
| 27 | + * swiftAuthUrl : Swift authentication server URL |
| 28 | + * swiftUser : Swift user used by MediaWiki |
| 29 | + * swiftKey : Authentication key for the above user (used to get sessions) |
| 30 | + * swiftProxyUser : Swift user used for end-user hits to proxy server |
| 31 | + */ |
21 | 32 | function __construct( array $config ) { |
22 | 33 | parent::__construct( $config ); |
23 | | - |
24 | 34 | // Required settings |
25 | | - $this->swiftuser = $config['user']; |
26 | | - $this->swiftkey = $config['key']; |
27 | | - $this->authurl = $config['authurl']; |
28 | | - $this->container = $config['container']; |
| 35 | + $this->swiftUser = $config['swiftUser']; |
| 36 | + $this->swiftKey = $config['swiftKey']; |
| 37 | + $this->swiftAuthUrl = $config['swiftAuthUrl']; |
| 38 | + // Optional settings |
| 39 | + $this->swiftProxyUser = isset( $config['swiftProxyUser'] ) |
| 40 | + ? $config['swiftProxyUser'] |
| 41 | + : ''; |
29 | 42 | } |
30 | 43 | |
31 | 44 | /** |
— | — | @@ -33,13 +46,14 @@ |
34 | 47 | * @return CF_Connection |
35 | 48 | */ |
36 | 49 | protected function connect() { |
37 | | - $auth = new CF_Authentication( $this->swiftuser, $this->swiftkey, NULL, $this->authurl ); |
| 50 | + $auth = new CF_Authentication( |
| 51 | + $this->swiftUser, $this->swiftKey, NULL, $this->swiftAuthUrl ); |
38 | 52 | try { |
39 | 53 | $auth->authenticate(); |
40 | 54 | } catch ( AuthenticationException $e ) { |
41 | 55 | throw new MWException( "We can't authenticate ourselves." ); |
42 | 56 | # } catch (InvalidResponseException $e) { |
43 | | - # throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
| 57 | + # throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
44 | 58 | } |
45 | 59 | return new CF_Connection( $auth ); |
46 | 60 | } |
— | — | @@ -58,12 +72,13 @@ |
59 | 73 | } catch ( NoSuchContainerException $e ) { |
60 | 74 | throw new MWException( "A container we thought existed, doesn't." ); |
61 | 75 | # } catch (InvalidResponseException $e) { |
62 | | - # throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
| 76 | + # throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
63 | 77 | } |
64 | 78 | } |
65 | 79 | |
66 | 80 | /** |
67 | 81 | * Copy a file from one place to another place |
| 82 | + * |
68 | 83 | * @param $srcContainer CF_Container |
69 | 84 | * @param $srcRel String: relative path to the source file. |
70 | 85 | * @param $dstContainer CF_Container |
— | — | @@ -87,25 +102,31 @@ |
88 | 103 | try { |
89 | 104 | $obj = $dstContainer->get_object( $dstRel ); |
90 | 105 | } catch ( NoSuchObjectException $e ) { |
91 | | - throw new MWException( 'The object we just created does not exist: ' . $dstContainer->name . "/$dstRel: $e" ); |
| 106 | + throw new MWException( 'The object we just created does not exist: ' . |
| 107 | + $dstContainer->name . "/$dstRel: $e" ); |
92 | 108 | } |
93 | 109 | |
94 | 110 | try { |
95 | 111 | $srcObj = $srcContainer->get_object( $srcRel ); |
96 | 112 | } catch ( NoSuchObjectException $e ) { |
97 | | - throw new MWException( 'Source file does not exist: ' . $srcContainer->name . "/$srcRel: $e" ); |
| 113 | + throw new MWException( 'Source file does not exist: ' . |
| 114 | + $srcContainer->name . "/$srcRel: $e" ); |
98 | 115 | } |
99 | 116 | |
100 | 117 | try { |
101 | 118 | $dstContainer->copy_object_from($srcObj,$srcContainer,$dstRel); |
102 | 119 | } catch ( SyntaxException $e ) { |
103 | | - throw new MWException( 'Source file does not exist: ' . $srcContainer->name . "/$srcRel: $e" ); |
| 120 | + throw new MWException( 'Source file does not exist: ' . |
| 121 | + $srcContainer->name . "/$srcRel: $e" ); |
104 | 122 | } catch ( MisMatchedChecksumException $e ) { |
105 | 123 | throw new MWException( "Checksums do not match: $e" ); |
106 | 124 | } |
107 | 125 | } |
108 | 126 | |
109 | | - function store( array $params ) { |
| 127 | + /** |
| 128 | + * @see FileBackend::doStore() |
| 129 | + */ |
| 130 | + function doStore( array $params ) { |
110 | 131 | $status = Status::newGood(); |
111 | 132 | |
112 | 133 | list( $destc, $dest ) = $this->resolveStoragePath( $params['dst'] ); |
— | — | @@ -123,7 +144,7 @@ |
124 | 145 | return $status; |
125 | 146 | } |
126 | 147 | $exists = true; |
127 | | - } catch (NoSuchObjectException $e) { |
| 148 | + } catch ( NoSuchObjectException $e ) { |
128 | 149 | $exists = false; |
129 | 150 | } |
130 | 151 | |
— | — | @@ -142,7 +163,10 @@ |
143 | 164 | return $status; |
144 | 165 | } |
145 | 166 | |
146 | | - function copy( array $params ) { |
| 167 | + /** |
| 168 | + * @see FileBackend::doCopy() |
| 169 | + */ |
| 170 | + function doCopy( array $params ) { |
147 | 171 | $status = Status::newGood(); |
148 | 172 | |
149 | 173 | list( $sourcec, $source ) = $this->resolveStoragePath( $params['src'] ); |
— | — | @@ -168,22 +192,21 @@ |
169 | 193 | return $status; |
170 | 194 | } |
171 | 195 | $exists = true; |
172 | | - } catch (NoSuchObjectException $e) { |
| 196 | + } catch ( NoSuchObjectException $e ) { |
173 | 197 | $exists = false; |
174 | 198 | } |
175 | 199 | try { |
176 | 200 | $this->swiftcopy( $srcc, $source, $dstc, $dest ); |
177 | | - } catch (InvalidResponseException $e ) { |
| 201 | + } catch ( InvalidResponseException $e ) { |
178 | 202 | $status->fatal( 'backend-fail-copy', $params['src'], $params['dst'] ); |
179 | | - } |
| 203 | + } |
180 | 204 | return $status; |
181 | 205 | } |
182 | 206 | |
183 | | - function canMove( array $params ) { |
184 | | - return false; |
185 | | - } |
186 | | - |
187 | | - function delete( array $params ) { |
| 207 | + /** |
| 208 | + * @see FileBackend::doDelete() |
| 209 | + */ |
| 210 | + function doDelete( array $params ) { |
188 | 211 | $status = Status::newGood(); |
189 | 212 | |
190 | 213 | list( $sourcec, $source ) = $this->resolveStoragePath( $params['src'] ); |
— | — | @@ -196,30 +219,33 @@ |
197 | 220 | $container = $this->get_container( $conn, $sourcec ); |
198 | 221 | |
199 | 222 | try { |
200 | | - $obj = $container->get_object( $source); |
| 223 | + $obj = $container->get_object( $source ); |
201 | 224 | $exists = true; |
202 | | - } catch (NoSuchObjectException $e) { |
| 225 | + } catch ( NoSuchObjectException $e ) { |
203 | 226 | if ( empty( $params['ignoreMissingSource'] ) ) { |
204 | 227 | $status->fatal( 'backend-fail-delete', $params['src'] ); |
205 | 228 | } |
206 | 229 | $exists = false; |
207 | 230 | } |
208 | 231 | |
209 | | - if ($exists) { |
| 232 | + if ( $exists ) { |
210 | 233 | try { |
211 | 234 | $container->delete_object( $source ); |
212 | 235 | } catch ( SyntaxException $e ) { |
213 | 236 | throw new MWException( "Swift object name not well-formed: '$e'" ); |
214 | 237 | } catch ( NoSuchObjectException $e ) { |
215 | 238 | throw new MWException( "Swift object we are trying to delete does not exist: '$e'" ); |
216 | | - } catch (InvalidResponseException $e) { |
| 239 | + } catch ( InvalidResponseException $e ) { |
217 | 240 | $status->fatal( 'backend-fail-delete', $params['src'] ); |
218 | 241 | } |
219 | 242 | } |
220 | 243 | return $status; // do nothing; either OK or bad status |
221 | 244 | } |
222 | 245 | |
223 | | - function concatenate( array $params ) { |
| 246 | + /** |
| 247 | + * @see FileBackend::doConcatenate() |
| 248 | + */ |
| 249 | + function doConcatenate( array $params ) { |
224 | 250 | $status = Status::newGood(); |
225 | 251 | |
226 | 252 | list( $destc, $dest ) = $this->resolveStoragePath( $params['dst'] ); |
— | — | @@ -238,17 +264,17 @@ |
239 | 265 | return $status; |
240 | 266 | } |
241 | 267 | $exists = true; |
242 | | - } catch (NoSuchObjectException $e) { |
| 268 | + } catch ( NoSuchObjectException $e ) { |
243 | 269 | $exists = false; |
244 | 270 | } |
245 | | - |
| 271 | + |
246 | 272 | try { |
247 | 273 | $biggie = $dstc->create_object( $dest ); |
248 | | - } catch (InvalidResponseException $e) { |
| 274 | + } catch ( InvalidResponseException $e ) { |
249 | 275 | $status->fatal( 'backend-fail-opentemp', $tmpPath ); |
250 | 276 | return $status; |
251 | 277 | } |
252 | | - |
| 278 | + |
253 | 279 | foreach ( $params['srcs'] as $virtualSource ) { |
254 | 280 | list( $sourcec, $source ) = $this->resolveStoragePath( $virtualSource ); |
255 | 281 | if ( $source === null ) { |
— | — | @@ -256,13 +282,16 @@ |
257 | 283 | return $status; |
258 | 284 | } |
259 | 285 | $srcc = $this->get_container( $conn, $sourcec ); |
260 | | - $obj = $srcc->get_object( $source); |
| 286 | + $obj = $srcc->get_object( $source ); |
261 | 287 | $biggie->write( $obj->read() ); |
262 | 288 | } |
263 | 289 | return $status; |
264 | 290 | } |
265 | 291 | |
266 | | - function create( array $params ) { |
| 292 | + /** |
| 293 | + * @see FileBackend::doCopy() |
| 294 | + */ |
| 295 | + function doCreate( array $params ) { |
267 | 296 | $status = Status::newGood(); |
268 | 297 | |
269 | 298 | list( $destc, $dest ) = $this->resolveStoragePath( $params['dst'] ); |
— | — | @@ -281,17 +310,18 @@ |
282 | 311 | return $status; |
283 | 312 | } |
284 | 313 | $exists = true; |
285 | | - } catch (NoSuchObjectException $e) { |
| 314 | + } catch ( NoSuchObjectException $e ) { |
286 | 315 | $exists = false; |
287 | 316 | } |
288 | 317 | |
289 | 318 | $obj = $dstc->create_object( $dest ); |
290 | 319 | //FIXME how do we know what the content type is? |
| 320 | + // This *should* work...cloudfiles can figure content type from strings too. |
291 | 321 | $obj->content_type = 'text/plain'; |
292 | 322 | |
293 | 323 | try { |
294 | 324 | $obj->write( $params['content'] ); |
295 | | - } catch (InvalidResponseException $e ) { |
| 325 | + } catch ( InvalidResponseException $e ) { |
296 | 326 | $status->fatal( 'backend-fail-create', $params['dst'] ); |
297 | 327 | return $status; |
298 | 328 | } |
— | — | @@ -299,21 +329,18 @@ |
300 | 330 | return $status; |
301 | 331 | } |
302 | 332 | |
303 | | - function prepare( array $params ) { |
304 | | - $status = Status::newGood(); |
305 | | - return $status; // we good. we so good, we BAD. |
306 | | - } |
307 | | - |
| 333 | + /** |
| 334 | + * @see FileBackend::secure() |
| 335 | + */ |
308 | 336 | function secure( array $params ) { |
309 | 337 | $status = Status::newGood(); |
| 338 | + // @TODO: restrict container from $this->swiftProxyUser |
310 | 339 | return $status; // badgers? We don't need no steenking badgers! |
311 | 340 | } |
312 | 341 | |
313 | | - function clean( array $params ) { |
314 | | - $status = Status::newGood(); |
315 | | - return $status; // can't delete what doesn't exist. |
316 | | - } |
317 | | - |
| 342 | + /** |
| 343 | + * @see FileBackend::fileExists() |
| 344 | + */ |
318 | 345 | function fileExists( array $params ) { |
319 | 346 | list( $sourcec, $source ) = $this->resolveStoragePath( $params['src'] ); |
320 | 347 | if ( $source === null ) { |
— | — | @@ -329,7 +356,10 @@ |
330 | 357 | } |
331 | 358 | return $exists; |
332 | 359 | } |
333 | | - |
| 360 | + |
| 361 | + /** |
| 362 | + * @see FileBackend::getFileTimestamp() |
| 363 | + */ |
334 | 364 | function getFileTimestamp( array $params ) { |
335 | 365 | list( $sourcec, $source ) = $this->resolveStoragePath( $params['src'] ); |
336 | 366 | if ( $source === null ) { |
— | — | @@ -345,14 +375,19 @@ |
346 | 376 | } |
347 | 377 | if ( $obj ) { |
348 | 378 | $thumbTime = $obj->last_modified; |
| 379 | + // @FIXME: strptime() UNIX-only (http://php.net/manual/en/function.strptime.php) |
349 | 380 | $tm = strptime( $thumbTime, '%a, %d %b %Y %H:%M:%S GMT' ); |
350 | | - $thumbGMT = gmmktime( $tm['tm_hour'], $tm['tm_min'], $tm['tm_sec'], $tm['tm_mon'] + 1, $tm['tm_mday'], $tm['tm_year'] + 1900 ); |
| 381 | + $thumbGMT = gmmktime( $tm['tm_hour'], $tm['tm_min'], $tm['tm_sec'], |
| 382 | + $tm['tm_mon'] + 1, $tm['tm_mday'], $tm['tm_year'] + 1900 ); |
351 | 383 | return ( gmdate( 'YmdHis', $thumbGMT ) ); |
352 | 384 | } else { |
353 | 385 | return false; // file not found. |
354 | 386 | } |
355 | 387 | } |
356 | 388 | |
| 389 | + /** |
| 390 | + * @see FileBackend::getFileList() |
| 391 | + */ |
357 | 392 | function getFileList( array $params ) { |
358 | 393 | list( $dirc, $dir ) = $this->resolveStoragePath( $params['dir'] ); |
359 | 394 | if ( $dir === null ) { // invalid storage path |
— | — | @@ -360,21 +395,16 @@ |
361 | 396 | } |
362 | 397 | |
363 | 398 | $conn = $this->connect(); |
| 399 | + // @TODO: return an Iterator class that pages via list_objects() |
364 | 400 | $container = $this->get_container( $conn, $dirc ); |
365 | | - $files = $container->list_objects( 0, NULL, $dir); |
| 401 | + $files = $container->list_objects( 0, NULL, $dir ); |
366 | 402 | // if there are no files matching the prefix, return empty array |
367 | 403 | return $files; |
368 | 404 | } |
369 | 405 | |
370 | | - function getLocalReference( array $params ) { |
371 | | - list( $c, $source ) = $this->resolveStoragePath( $params['src'] ); |
372 | | - if ( $source === null ) { |
373 | | - return null; |
374 | | - } |
375 | | - // FIXME! |
376 | | - return new FSFile( $source ); |
377 | | - } |
378 | | - |
| 406 | + /** |
| 407 | + * @see FileBackend::getLocalCopy() |
| 408 | + */ |
379 | 409 | function getLocalCopy( array $params ) { |
380 | 410 | list( $sourcec, $source ) = $this->resolveStoragePath( $params['src'] ); |
381 | 411 | if ( $source === null ) { |
— | — | @@ -392,7 +422,7 @@ |
393 | 423 | $tmpPath = $tmpFile->getPath(); |
394 | 424 | |
395 | 425 | $conn = $this->connect(); |
396 | | - $cont = $this->get_container( $conn, $sourcec); |
| 426 | + $cont = $this->get_container( $conn, $sourcec ); |
397 | 427 | |
398 | 428 | try { |
399 | 429 | $obj = $cont->get_object( $source ); |
— | — | @@ -411,5 +441,4 @@ |
412 | 442 | } |
413 | 443 | return $tmpFile; |
414 | 444 | } |
415 | | - |
416 | 445 | } |