/** * Using the configured image identifier generator, attempt to generate a unique image * identifier for the given image until we either have found a unique ID or we hit the maximum * allowed attempts. * * @param EventInterface $event The current event * @param Image $image The event to generate the image identifier for * @return string * @throws ImageException */ private function generateImageIdentifier(EventInterface $event, Image $image) { $database = $event->getDatabase(); $config = $event->getConfig(); $user = $event->getRequest()->getUser(); $imageIdentifierGenerator = $config['imageIdentifierGenerator']; if (is_callable($imageIdentifierGenerator) && !$imageIdentifierGenerator instanceof GeneratorInterface) { $imageIdentifierGenerator = $imageIdentifierGenerator(); } if ($imageIdentifierGenerator->isDeterministic()) { return $imageIdentifierGenerator->generate($image); } // Continue generating image identifiers until we get one that does not already exist $maxAttempts = 100; $attempts = 0; do { $imageIdentifier = $imageIdentifierGenerator->generate($image); $attempts++; } while ($attempts < $maxAttempts && $database->imageExists($user, $imageIdentifier)); // Did we reach our max attempts limit? if ($attempts === $maxAttempts) { $e = new ImageException('Failed to generate unique image identifier', 503); $e->setImboErrorCode(Exception::IMAGE_IDENTIFIER_GENERATION_FAILED); // Tell the client it's OK to retry later $event->getResponse()->headers->set('Retry-After', 1); throw $e; } return $imageIdentifier; }
/** * Handle GET requests * * @param EventInterface $event The current event */ public function get(EventInterface $event) { $response = $event->getResponse(); $database = $event->getDatabase(); $storage = $event->getStorage(); $databaseStatus = $database->getStatus(); $storageStatus = $storage->getStatus(); if (!$databaseStatus || !$storageStatus) { if (!$databaseStatus && !$storageStatus) { $message = 'Database and storage error'; } else { if (!$storageStatus) { $message = 'Storage error'; } else { $message = 'Database error'; } } $response->setStatusCode(503, $message); } $response->setMaxAge(0)->setPrivate(); $response->headers->addCacheControlDirective('no-store'); $statusModel = new Model\Status(); $statusModel->setDate(new DateTime('now', new DateTimeZone('UTC')))->setDatabaseStatus($databaseStatus)->setStorageStatus($storageStatus); $response->setModel($statusModel); }
/** * Handle POST requests * * @param EventInterface $event The current event */ public function post(EventInterface $event) { $request = $event->getRequest(); $event->getManager()->trigger('db.metadata.update', ['metadata' => json_decode($request->getContent(), true)]); $model = new Model\Metadata(); $model->setData($event->getDatabase()->getMetadata($request->getUser(), $request->getImageIdentifier())); $event->getResponse()->setModel($model); }
/** * Fetch an image via a short URL * * @param EventInterface $event */ public function getImage(EventInterface $event) { $request = $event->getRequest(); $route = $request->getRoute(); $params = $event->getDatabase()->getShortUrlParams($route->get('shortUrlId')); if (!$params) { throw new ResourceException('Image not found', 404); } $route->set('publicKey', $params['publicKey']); $route->set('imageIdentifier', $params['imageIdentifier']); $route->set('extension', $params['extension']); $request->query = new ParameterBag($params['query']); $event->getResponse()->headers->set('X-Imbo-ShortUrl', $request->getUri()); $event->getManager()->trigger('image.get'); }
/** * Insert an image * * @param EventInterface $event An event instance */ public function insertImage(EventInterface $event) { $request = $event->getRequest(); $user = $request->getUser(); $image = $request->getImage(); $imageIdentifier = $image->getImageIdentifier(); $blob = $image->getBlob(); try { $exists = $event->getStorage()->imageExists($user, $imageIdentifier); $event->getStorage()->store($user, $imageIdentifier, $blob); } catch (StorageException $e) { $event->getDatabase()->deleteImage($user, $imageIdentifier); throw $e; } $event->getResponse()->setStatusCode($exists ? 200 : 201); }
/** * Delete a single short URL * * @param EventInterface $event */ public function deleteShortUrl(EventInterface $event) { $database = $event->getDatabase(); $request = $event->getRequest(); $publicKey = $request->getPublicKey(); $imageIdentifier = $request->getImageIdentifier(); $shortUrlId = $request->getRoute()->get('shortUrlId'); if (!($params = $database->getShortUrlParams($shortUrlId))) { throw new ResourceException('ShortURL not found', 404); } if ($params['publicKey'] !== $publicKey || $params['imageIdentifier'] !== $imageIdentifier) { throw new ResourceException('ShortURL not found', 404); } $database->deleteShortUrls($publicKey, $imageIdentifier, $shortUrlId); $model = new ArrayModel(); $model->setData(array('id' => $shortUrlId)); $event->getResponse()->setModel($model); }
/** * Load stats * * @param EventInterface $event An event instance */ public function loadStats(EventInterface $event) { $response = $event->getResponse(); $database = $event->getDatabase(); $userLookup = $event->getUserLookup(); $publicKeys = $userLookup->getPublicKeys(); $users = array(); foreach ($publicKeys as $key) { $users[$key] = array('numImages' => $database->getNumImages($key), 'numBytes' => $database->getNumBytes($key)); } $statsModel = new Model\Stats(); $statsModel->setUsers($users); $response->setModel($statsModel); }
/** * Fetch POI from metadata for the image * * @param EventInterface $event * @param Image $image * @return array|false Array with x and y coordinate, or false if no POI was found */ private function getPoiFromMetadata(EventInterface $event, Image $image) { $metadata = $event->getDatabase()->getMetadata($image->getUser(), $image->getImageIdentifier()); $poi = isset($metadata['poi'][0]) ? $metadata['poi'][0] : false; // Fetch POI from metadata. Array used if we want to expand with multiple POIs in the future if ($poi && isset($poi['cx']) && isset($poi['cy'])) { return [(int) $poi['cx'], (int) $poi['cy']]; } else { if ($poi && isset($poi['x']) && isset($poi['y']) && isset($poi['width']) && isset($poi['height'])) { return [(int) $poi['x'] + $poi['width'] / 2, (int) $poi['y'] + $poi['height'] / 2]; } } return false; }
/** * Save metadata to database * * @param EventInterface $event The triggered event * @throws RuntimeException */ public function save(EventInterface $event) { $request = $event->getRequest(); $database = $event->getDatabase(); $publicKey = $request->getPublicKey(); $imageIdentifier = $request->getImage()->getChecksum(); try { $database->updateMetadata($publicKey, $imageIdentifier, $this->properties); } catch (DatabaseException $e) { $database->deleteImage($publicKey, $imageIdentifier); throw new RuntimeException('Could not store EXIF-metadata', 500); } }
/** * Delete all short URLs for a given image * * @param EventInterface $event */ public function deleteImageShortUrls(EventInterface $event) { $request = $event->getRequest(); $publicKey = $request->getPublicKey(); $imageIdentifier = $request->getImageIdentifier(); $event->getDatabase()->deleteShortUrls($publicKey, $imageIdentifier); if ($event->getName() === 'shorturls.delete') { // If the request is against the shorturls resource directly we need to supply a // response model. If this method is triggered because of an image has been deleted // the image resource will supply the response model $model = new ArrayModel(); $model->setData(array('imageIdentifier' => $imageIdentifier)); $event->getResponse()->setModel($model); } }
/** * Fetch POIs from metadata for the image * * @param EventInterface $event * @param Image $image * @return array Array with POIs */ private function getPoisFromMetadata(EventInterface $event, Image $image) { $metadata = $event->getDatabase()->getMetadata($image->getUser(), $image->getImageIdentifier()); return isset($metadata['poi']) ? $metadata['poi'] : []; }
/** * Load stats * * @param EventInterface $event An event instance */ public function loadStats(EventInterface $event) { $response = $event->getResponse(); $database = $event->getDatabase(); $statsModel = new Model\Stats(); $statsModel->setNumUsers($database->getNumUsers()); $statsModel->setNumBytes($database->getNumBytes()); $statsModel->setNumImages($database->getNumImages()); $response->setModel($statsModel); }