Rackspace files CDN (Cloudfiles) implementatie in Drupal

02 Jun 2015

Thomas Dik - Lead Developer
+31 (0)20 - 261 14 99

Voor het 100lives.com project probeerden we gebruik te maken van de Cloudfiles module om alle Drupal files op de Rackspace CDN the krijgen. Deze module bleek redelijk outdated qua API maar bevatte een goede basis voor de cloud implementatie. De module maakt gebruik van de php-opencloud library waar alle benodigde functies in zitten. We hebben een en andere getweaked om de Drupal files op de Rackspace CDN werkend te krijgen:

Tweaking Rackspace Cloudfiles module

Alleerst hebben de _cloud_file_get_client() gewijzigd: in de API is de authenticate() functie toegevoegd aan exportCredentials() waardoor de authenticate een overbodige extra call werd. Een belangrijkere wijziging was de check of de token nog goed was. In plaats er vanuit te gaan dat de token correct is totdat deze expired is, hebben we een andere check ingebouwd. Een vergelijking: door een export te doen waardoor je een token terug krijgt die je kunt vergelijken met de oude.

  // Tenant should be an int and caused errors as a string.  $credentials->data['tenant'] = (int) $credentials->data['tenant'];  $client->importCredentials($credentials->data);  // Export credentials for comparing the tokens.  $newCredentials = $client->exportCredentials();  if (!empty($newCredentials['token']) && $newCredentials['token'] != $credentials->data['token']) {       cache_set("rackspace_cloud_credentials", $newCredentials, 'cache', CACHE_TEMPORARY);  }

Het gebeurde namelijk wel vaker dat deze verlopen was, nog voordat de expire bereikt was. Met deze wijziging is de cloud files module prima te gebruiken. De module bevat een 'streamwrapper' zodat je buiten de standaard public en private wrappers van Drupal ook kunt kiezen voor de cloud variant. Mocht je deze module gaan gebruiken vergeet hem dan niet per veld te configureren.

Uitbreiding: uitpakken van bestanden.

We hebben ook een uitbreiding toegevoegd voor de cloud files voor dit project. In de php-opencloud module zit de bulkExtract functie, hiermee kan je tar, tar.gz en tar.bz2 files uitgepakt naar de server streamen. Deze functie heeft een path, een file-stream en de extensie nodig. De path parameter is eem combinatie van de container en een eventuele map. Wij hebben gebruik gemaakt van de een map en de fid zodat deze eenvoudig terug te vinden zijn. In code ziet dat er zo uit:

  $file = file_load($fid);  if (stristr($file->filename,'.tar.gz')) {    $extension = 'tar.gz';  }  elseif (stristr($file->filename,'.tar.bz2')) {    $extension = 'tar.bz2';  }  else {    $extension = substr(strrchr($file->filename, "."), 1);  }  // Get url to file and get the data for extracting.  // Local files OR file_create_url($file->url) for remote files.  $path = drupal_realpath($file->uri);  // drupal_realpath  $file_data = fopen($path, 'r');  // Build string requirements for extraction.  $rackspace_cloud_container = variable_get('rackspace_cloud_container');  $remote_path = $rackspace_cloud_container . '/assets/' . $file->fid . '/';

De verbinding naar Cloud files voor het uitpakken en streamen gaat als volgt:

  // Create cloud files client.  $client = _cloud_files_get_client();  $region = variable_get('rackspace_cloud_region');  // Create service.  $service = new OpenCloud\ObjectStore\Service($client, NULL, NULL, $region);  // Attempt to extract the file.  $response = $service->bulkExtract($remote_path, $file_data, $extension);

Het is echter handiger om een lijst met bestanden te hebben na deze actie. Verder is het afhandelen van fouten ook handig om te hebben. Om "folders" uit te lezen binnen de cloud files moet je gebruik maken van de container. Folders heb ik tussen aanhalingstekens gezet omdat deze niet bestaan binnen cloud files, deze worden ge-prepend voor de bestandsnaam. 

Vandaar dat je als je zoekt naar folders niets terug zult vinden binnen de API. Het zoeken naar bestanden gaat dan ook aan de hand van deze prefix. Dit gebeurt met de objectList functie binnen het container object. Dit hebben wij als volgt verwerkt:

  // On success get file listing.  if ($response->getStatusCode() == '200') {    // Get container.    $container = $service->getContainer(variable_get('rackspace_cloud_container'));    // Get files in container with prefix.    $pages     = $container->objectList(array('prefix' => 'assets/' . $file->fid));    $files_list = array();    while ($item = $pages->next()) {      $files_list[] = $item->getName();    }    // Store files list for this node.    variable_set('assets_' . $nid, drupal_json_encode($files_list));  }  else {    // Something went wrong.    watchdog('error', $response->getMessage());  }

De bestanden worden als json object in de database opgeslagen. Voor je eigen project kan je dit natuurlijk anders afhandelen. De fouten worden gelogt met watchdog waardoor de site admin snel inzicht heeft in de errors.

Wrap up

Ik hoop dat ik jullie een beetje op weg heb kunnen helpen, vragen of feedback? Let us know! 

Comments

Nóg meer
kennis nodig?

Check ons ons blog archief >