瀏覽代碼

Add batch api for download notifications

Jordi Boggiano 12 年之前
父節點
當前提交
c5d43a5223
共有 2 個文件被更改,包括 59 次插入14 次删除
  1. 58 14
      src/Packagist/WebBundle/Controller/ApiController.php
  2. 1 0
      src/Packagist/WebBundle/Package/Dumper.php

+ 58 - 14
src/Packagist/WebBundle/Controller/ApiController.php

@@ -21,6 +21,7 @@ use Composer\Package\Loader\ArrayLoader;
 use Packagist\WebBundle\Package\Updater;
 use Packagist\WebBundle\Entity\Package;
 use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Console\Output\OutputInterface;
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
@@ -101,25 +102,70 @@ class ApiController extends Controller
      */
     public function trackDownloadAction(Request $request, $name)
     {
-        $result = $this->get('doctrine.dbal.default_connection')->fetchAssoc(
+        $result = $this->getPackageAndVersionId($name, $request->request->get('version_normalized'));
+
+        if (!$result) {
+            return new JsonResponse(array('status' => 'error', 'message' => 'Package not found'), 200);
+        }
+
+        $this->trackDownload($result['id'], $result['vid'], $request->getClientIp());
+
+        return new JsonResponse(array('status' => 'success'), 201);
+    }
+
+    /**
+     * Expects a json like:
+     *
+     * {
+     *     "downloads": [
+     *         {"name": "foo/bar", "version": "1.0.0.0"},
+     *         // ...
+     *     ]
+     * }
+     *
+     * The version must be the normalized one
+     *
+     * @Route("/downloads/", name="track_download_batch", defaults={"_format" = "json"})
+     * @Method({"POST"})
+     */
+    public function trackDownloadsAction(Request $request)
+    {
+        $contents = json_decode($request->getContent(), true);
+        if (empty($contents['downloads']) || !is_array($contents['downloads'])) {
+            return new JsonResponse(array('status' => 'error', 'message' => 'Invalid request format, must be a json object containing a downloads key filled with an array of name/version objects'), 200);
+        }
+
+        foreach ($contents['downloads'] as $package) {
+            $result = $this->getPackageAndVersionId($package['name'], $package['version']);
+
+            if (!$result) {
+                return new JsonResponse(array('status' => 'error', 'message' => 'Package '.json_encode($package).' not found'), 200);
+            }
+
+            $this->trackDownload($result['id'], $result['vid'], $request->getClientIp());
+        }
+
+        return new JsonResponse(array('status' => 'success'), 201);
+    }
+
+    protected function getPackageAndVersionId($name, $version)
+    {
+        return $this->get('doctrine.dbal.default_connection')->fetchAssoc(
             'SELECT p.id, v.id vid
             FROM package p
             LEFT JOIN package_version v ON p.id = v.package_id
             WHERE p.name = ?
             AND v.normalizedVersion = ?
             LIMIT 1',
-            array($name, $request->request->get('version_normalized'))
+            array($name, $version)
         );
+    }
 
-        if (!$result) {
-            return new Response('{"status": "error", "message": "Package not found"}', 200);
-        }
-
+    protected function trackDownload($id, $vid, $ip)
+    {
         $redis = $this->get('snc_redis.default');
-        $id = $result['id'];
-        $version = $result['vid'];
 
-        $throttleKey = 'dl:'.$id.':'.$request->getClientIp().':'.date('Ymd');
+        $throttleKey = 'dl:'.$id.':'.$ip.':'.date('Ymd');
         $requests = $redis->incr($throttleKey);
         if (1 === $requests) {
             $redis->expire($throttleKey, 86400);
@@ -131,12 +177,10 @@ class ApiController extends Controller
             $redis->incr('dl:'.$id.':'.date('Ym'));
             $redis->incr('dl:'.$id.':'.date('Ymd'));
 
-            $redis->incr('dl:'.$id.'-'.$version);
-            $redis->incr('dl:'.$id.'-'.$version.':'.date('Ym'));
-            $redis->incr('dl:'.$id.'-'.$version.':'.date('Ymd'));
+            $redis->incr('dl:'.$id.'-'.$vid);
+            $redis->incr('dl:'.$id.'-'.$vid.':'.date('Ym'));
+            $redis->incr('dl:'.$id.'-'.$vid.':'.date('Ymd'));
         }
-
-        return new Response('{"status": "success"}', 201);
     }
 
     protected function receivePost(Request $request, $urlRegex)

+ 1 - 0
src/Packagist/WebBundle/Package/Dumper.php

@@ -237,6 +237,7 @@ class Dumper
         }
         $url = $this->router->generate('track_download', array('name' => 'VND/PKG'));
         $this->files['p/packages.json']['notify'] = str_replace('VND/PKG', '%package%', $url);
+        $this->files['p/packages.json']['notify_batch'] = $this->router->generate('track_download_batch');
 
         if ($verbose) {
             echo 'Dumping individual listings'.PHP_EOL;