getPathToPhoto($photo, $thumbnail); // Create or update our cache record $b2Cache = $this->getB2FileFromCache($pathOnStorage); if (is_null($b2Cache)) { return; } $this->getClient()->deleteFile($b2Cache->b2_file_id, $pathOnStorage); $b2Cache->delete(); } /** * Fetches the contents of a thumbnail for a photo. * @param Photo $photo Photo to fetch the thumbnail for. * @param string $thumbnail Thumbnail to fetch (or null to fetch the original.) * @return Stream */ public function fetchPhotoContent(Photo $photo, $thumbnail = null) { $pathOnStorage = $this->getPathToPhoto($photo, $thumbnail); // First we need the file ID $b2Cache = $this->getB2FileFromCache($pathOnStorage); if (is_null($b2Cache)) { return stream_for(''); } return stream_for($this->getClient()->downloadFile($b2Cache->b2_file_id)); } /** * Gets the name of this album source. * @return string */ public function getName() { return 'global.album_sources.backblaze_b2'; } /** * Gets the absolute URL to the given photo file. * @param Photo $photo Photo to get the URL to. * @param string $thumbnail Thumbnail to get the image to. * @return string */ public function getUrlToPhoto(Photo $photo, $thumbnail = null) { $client = $this->getClient(); $pathOnStorage = $this->getPathToPhoto($photo, $thumbnail); switch ($this->bucketType) { case self::BUCKET_TYPE_PRIVATE: if (is_null($this->downloadToken)) { $this->downloadToken = $client->getDownloadAuthToken(); } // Once I sort out the issue with b2_download_file_by_id, this line can be removed return sprintf('%s/file/%s/%s?Authorization=%s', $client->getDownloadUrl(), $this->configuration->container_name, $pathOnStorage, $this->downloadToken); $b2Cache = $this->getB2FileFromCache($pathOnStorage); if (is_null($b2Cache)) { return ''; } return sprintf('%s/b2api/v2/b2_download_file_by_id?fileId=%s&Authorization=%s', $client->getDownloadUrl(), urlencode($b2Cache->b2_file_id), urlencode($this->downloadToken)); case self::BUCKET_TYPE_PUBLIC: /* * From https://www.backblaze.com/b2/docs/b2_download_file_by_name.html: * The base URL to use comes from the b2_authorize_account call, and looks something like * https://f345.backblazeb2.com. The "f" in the URL stands for "file", and the number is the cluster * number containing your account. To this base, you add "file/", your bucket name, a "/", and then the * name of the file. The file name may itself include more "/" characters. */ return sprintf('%s/file/%s/%s', $client->getDownloadUrl(), $this->configuration->container_name, $pathOnStorage); } } /** * Saves a generated thumbnail to its permanent location. * @param Photo $photo Photo the image relates to. * @param string $tempFilename Filename containing the image. * @param string $thumbnail Name of the thumbnail (or null for the original.) * @return mixed */ public function saveThumbnail(Photo $photo, $tempFilename, $thumbnail = null) { $pathOnStorage = $this->getPathToPhoto($photo, $thumbnail); $b2Cache = $this->getB2FileFromCache($pathOnStorage); if (!is_null($b2Cache)) { // Delete the current file version if we're replacing a file that already exists $this->getClient()->deleteFile($b2Cache->b2_file_id, $pathOnStorage); } // Upload the file to B2 $b2FileID = $this->getClient()->uploadFile($tempFilename, $pathOnStorage); // Create or update our cache record if (is_null($b2Cache)) { $b2Cache = new BackblazeB2FileIdCache([ 'photo_id' => $photo->id, 'storage_path' => $pathOnStorage, 'b2_file_id' => $b2FileID ]); } else { $b2Cache->b2_file_id = $b2FileID; } $b2Cache->save(); } public function setConfiguration(Storage $configuration) { parent::setConfiguration($configuration); } /** * @param $pathOnStorage * @return BackblazeB2FileIdCache|null */ private function getB2FileFromCache($pathOnStorage) { $b2Cache = BackblazeB2FileIdCache::where('storage_path', $pathOnStorage)->first(); if (is_null($b2Cache)) { // TODO: lookup the file on B2 to get the file ID Log::warning(sprintf('B2 file ID not found in cache: %s', $pathOnStorage)); return null; } return $b2Cache; } private function getClient() { if (is_null($this->backblaze)) { $this->backblaze = new BackblazeB2Service(); $this->backblaze->setCredentials(decrypt($this->configuration->access_key), decrypt($this->configuration->secret_key)); $this->backblaze->authorizeAccount(); $this->backblaze->setBucketName($this->configuration->container_name); if (intval($this->configuration->b2_bucket_type) == self::BUCKET_TYPE_AUTO) { /* Auto-detect the type of bucket in use on B2 */ switch ($this->backblaze->getBucketType()) { case 'allPrivate': $this->configuration->b2_bucket_type = self::BUCKET_TYPE_PRIVATE; break; case 'allPublic': $this->configuration->b2_bucket_type = self::BUCKET_TYPE_PUBLIC; break; } $this->configuration->save(); } // Set the bucket type $this->bucketType = $this->configuration->b2_bucket_type; } return $this->backblaze; } private function getOriginalsFolder() { return '_originals'; } private function getPathToPhoto(Photo $photo, $thumbnail = null) { return sprintf( '%s/%s/%s', $this->album->url_alias, is_null($thumbnail) ? $this->getOriginalsFolder() : $thumbnail, $photo->storage_file_name ); } }