the browser-facing portion of osu!
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #9882 from nanaya/separate-ip-lookup

Separate ipv4 and ipv6 lookup

authored by

bakaneko and committed by
GitHub
ff978dba ca94ba56

+78 -44
+2 -2
.gitignore
··· 83 83 /storage/htmlpurifier/ 84 84 /storage/paypal_auth.cache 85 85 86 - /database/ip2asn.idx 87 - /database/ip2asn.tsv 86 + /database/ip2asn/*.idx 87 + /database/ip2asn/*.tsv
+14
app/Libraries/Ip.php
··· 1 + <?php 2 + 3 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4 + // See the LICENCE file in the repository root for full licence text. 5 + 6 + declare(strict_types=1); 7 + 8 + namespace App\Libraries; 9 + 10 + enum Ip: string 11 + { 12 + case V4 = 'v4'; 13 + case V6 = 'v6'; 14 + }
+38 -31
app/Libraries/Ip2Asn.php
··· 8 8 namespace App\Libraries; 9 9 10 10 use Exception; 11 + use WeakMap; 11 12 12 13 class Ip2Asn 13 14 { 14 - private $dbFh; 15 - private string $index; 16 - private int $count; 15 + private WeakMap $count; 16 + private WeakMap $dbFh; 17 + private WeakMap $index; 17 18 18 19 public function __construct() 19 20 { 20 - $this->dbFh = fopen(Ip2AsnUpdater::getDbPath(), 'r'); 21 - $index = file_get_contents(Ip2AsnUpdater::getIndexPath()); 22 - if ($this->dbFh === false || $index === false) { 23 - throw new Exception('failed opening ip2asn database or index'); 21 + $this->count = new WeakMap(); 22 + $this->dbFh = new WeakMap(); 23 + $this->index = new WeakMap(); 24 + 25 + foreach (Ip::cases() as $version) { 26 + $this->dbFh[$version] = fopen(Ip2AsnUpdater::getDbPath($version), 'r'); 27 + $index = file_get_contents(Ip2AsnUpdater::getIndexPath($version)); 28 + if ($this->dbFh[$version] === false || $index === false) { 29 + throw new Exception("failed opening ip2asn {$version} database or index"); 30 + } 31 + $this->index[$version] = $index; 32 + 33 + // 4 bytes per entry (int32) 34 + $this->count[$version] = strlen($this->index[$version]) / 4; 35 + } 36 + } 37 + 38 + public function lookup(string $ip): string 39 + { 40 + switch (true) { 41 + case filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false: 42 + return $this->lookupByVersion(Ip::V4, $ip); 43 + case filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false: 44 + return $this->lookupByVersion(Ip::V6, $ip); 24 45 } 25 - $this->index = $index; 26 46 27 - // 4 bytes per entry (int32) 28 - $this->count = strlen($this->index) / 4; 47 + return '0'; 29 48 } 30 49 31 - public function lookup(string $ip): string 50 + private function lookupByVersion(Ip $version, string $ip): string 32 51 { 52 + $dbFh = $this->dbFh[$version]; 53 + $index = $this->index[$version]; 33 54 $start = 0; 34 - $end = $this->count - 1; 35 - $search = inet_pton($this->prefixIPv4($ip)); 36 - 37 - if ($search === false) { 38 - return '0'; 39 - } 55 + $end = $this->count[$version] - 1; 56 + $search = inet_pton($ip); 40 57 41 58 while ($start <= $end) { 42 59 $current = (int) (($start + $end) / 2); 43 - $loc = unpack('l', substr($this->index, $current * 4, 4))[1]; 44 - fseek($this->dbFh, $loc); 45 - $row = fgets($this->dbFh); 60 + $loc = unpack('l', substr($index, $current * 4, 4))[1]; 61 + fseek($dbFh, $loc); 62 + $row = fgets($dbFh); 46 63 $data = explode("\t", $row, 4); 47 - $compare = inet_pton($this->prefixIPv4($data[1])); 64 + $compare = inet_pton($data[1]); 48 65 $asn = $data[2]; 49 66 if ($compare === $search) { 50 67 return $asn; ··· 57 74 } 58 75 59 76 return $lastInnerSearchAsn ?? $asn; 60 - } 61 - 62 - /** 63 - * Prefix IPv4 so it's sortable as IPv6 64 - */ 65 - private function prefixIPv4(string $ip): string 66 - { 67 - return strpos($ip, ':') === false 68 - ? "::{$ip}" 69 - : $ip; 70 77 } 71 78 }
+23 -10
app/Libraries/Ip2AsnUpdater.php
··· 11 11 12 12 class Ip2AsnUpdater 13 13 { 14 - public static function getDbPath() 14 + public static function getDbPath(Ip $version): string 15 15 { 16 - return database_path('ip2asn.tsv'); 16 + return database_path("ip2asn/{$version->value}.tsv"); 17 17 } 18 18 19 - public static function getIndexPath() 19 + public static function getIndexPath(Ip $version): string 20 20 { 21 - return database_path('ip2asn.idx'); 21 + return database_path("ip2asn/{$version->value}.idx"); 22 22 } 23 23 24 24 public function run(?callable $logger = null): void 25 25 { 26 - $logger ??= function (string $message) { 27 - Log::info("ip2asn: {$message}"); 28 - }; 26 + foreach (Ip::cases() as $version) { 27 + $prefixedLogger = function (string $message) use ($logger, $version): void { 28 + $prefixedMessage = "[{$version->value}] $message"; 29 + 30 + if (isset($logger)) { 31 + $logger($prefixedMessage); 32 + } else { 33 + Log::info("ip2asn: {$prefixedMessage}"); 34 + } 35 + }; 29 36 37 + $this->update($version, $prefixedLogger); 38 + } 39 + } 40 + 41 + private function update(Ip $version, callable $logger): void 42 + { 30 43 $logger('Checking db for updates'); 31 44 32 - $dbPath = static::getDbPath(); 33 - $indexPath = static::getIndexPath(); 45 + $dbPath = static::getDbPath($version); 46 + $indexPath = static::getIndexPath($version); 34 47 35 48 $dbExists = file_exists($dbPath); 36 49 ··· 46 59 47 60 if ($newDb) { 48 61 $logger('Db file is outdated. Downloading'); 49 - $tsv = gzdecode(file_get_contents('https://iptoasn.com/data/ip2asn-combined.tsv.gz')); 62 + $tsv = gzdecode(file_get_contents("https://iptoasn.com/data/ip2asn-{$version->value}.tsv.gz")); 50 63 } else { 51 64 $tsv = file_get_contents($dbPath); 52 65 }
database/ip2asn/.keep

This is a binary file and will not be displayed.

+1 -1
docker/development/prepare.sh
··· 69 69 cp .docker/.my.cnf.example .docker/.my.cnf 70 70 fi 71 71 72 - if [ ! -f database/ip2asn.tsv ]; then 72 + if [ ! -f database/ip2asn/v6.tsv ]; then 73 73 _run artisan ip2asn:update 74 74 fi 75 75