let the patching commence
This commit is contained in:
parent
947e717920
commit
9447e65acd
|
@ -7,12 +7,15 @@ require_once __DIR__ . '/../startup.php';
|
|||
|
||||
$request = Http\HttpRequest::create();
|
||||
|
||||
header('Content-Type: ' . FWIF::CONTENT_TYPE);
|
||||
header('Content-Type: ' . (PAT_DEBUG ? 'text/plain; charset=us-ascii' : FWIF::CONTENT_TYPE));
|
||||
|
||||
$tPlat = Platform::getUser();
|
||||
|
||||
// ONLY EXACT MATCHES ↓
|
||||
|
||||
if($request->match('GET', '/packages')) {
|
||||
$tags = explode(';', (string)$request->getQueryParam('tags', FILTER_SANITIZE_STRING));
|
||||
$packages = empty($tags) ? Patchouli::getPackages() : Patchouli::getPackagesWithTags($tags);
|
||||
header('Content-Type: text/plain; charset=us-ascii');
|
||||
echo FWIF::encode($packages);
|
||||
return;
|
||||
}
|
||||
|
@ -25,5 +28,17 @@ if($request->match('GET', '/')) {
|
|||
return;
|
||||
}
|
||||
|
||||
http_response_code(404);
|
||||
echo '{"code":404,"message":"Path not found."}';
|
||||
// REGEX MATCHES ↓
|
||||
|
||||
if($request->match('GET', '#^/packages/([a-z0-9-]+)/?$#', $args)) {
|
||||
try {
|
||||
$packageInfo = Patchouli::getPackage($args[0]);
|
||||
} catch(PackageNotFoundException $ex) {
|
||||
http_response_code(404);
|
||||
$packageInfo = new ErrorResponse(404, 'Package not found.');
|
||||
}
|
||||
echo FWIF::encode($packageInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
echo FWIF::encode(new ErrorResponse(404, 'Path not found.'));
|
||||
|
|
|
@ -17,6 +17,17 @@ class DummyPackage implements IPackage {
|
|||
return new Version;
|
||||
}
|
||||
|
||||
public function getFiles(): array {
|
||||
return [
|
||||
new DummyPackageFile('filename.bin'),
|
||||
new DummyPackageFile('boobs.png'),
|
||||
];
|
||||
}
|
||||
|
||||
public function getTargets(): array {
|
||||
return [new DummyPackageTarget];
|
||||
}
|
||||
|
||||
public function getDependencies(): array {
|
||||
return [];
|
||||
}
|
||||
|
@ -25,57 +36,10 @@ class DummyPackage implements IPackage {
|
|||
$data = [
|
||||
'id' => $this->getId(),
|
||||
'name' => $this->getName(),
|
||||
'version' => $this->getVersion(),
|
||||
'ver' => $this->getVersion(),
|
||||
'files' => $this->getFiles(),
|
||||
'targ' => $this->getTargets(),
|
||||
'deps' => [],
|
||||
/*'null' => null,
|
||||
'true' => true,
|
||||
'false' => false,
|
||||
'zero' => 0,
|
||||
'u8' => 0x42,
|
||||
'u16' => 0x4344,
|
||||
'u24' => 0x454647,
|
||||
'u32' => 0x58596061,
|
||||
'u40' => 0x6263646566,
|
||||
'u48' => 0x676869707172,
|
||||
'u56' => 0x73747576777879,
|
||||
'u64' => 0x7481828384858687,
|
||||
'neg32' => -12345678,
|
||||
'neg64' => -1234567890987654,
|
||||
'float' => 12345.6789,
|
||||
'float2' => 8.0,
|
||||
'floatNeg' => -12345.6789,
|
||||
'floatPi' => M_PI,
|
||||
'floatE' => M_E,
|
||||
'floatLog2E' => M_LOG2E,
|
||||
'floatLog10E' => M_LOG10E,
|
||||
'floatLn2' => M_LN2,
|
||||
'floatLn10' => M_LN10,
|
||||
'floatPi2' => M_PI_2,
|
||||
'floatPi4' => M_PI_4,
|
||||
'floatM1Pi' => M_1_PI,
|
||||
'floatM2Pi' => M_2_PI,
|
||||
'floatSqrtPi' => M_SQRTPI,
|
||||
'float2SqrtPi' => M_2_SQRTPI,
|
||||
'floatSqrt2' => M_SQRT2,
|
||||
'floatSqrt3' => M_SQRT3,
|
||||
'floatSqrt12' => M_SQRT1_2,
|
||||
'floatLnPi' => M_LNPI,
|
||||
'floatEuler' => M_EULER,
|
||||
'floatNaN' => NAN,
|
||||
'floatInf' => INF,
|
||||
'floatNegInf' => -INF,
|
||||
'floatZero' => 0.0,
|
||||
'floatNegZero' => -0.0,
|
||||
'invalid' => "\xFF\x25\x25\x02\xFF蠕。蝮F鄒守清\xFF\xFF\xFF",
|
||||
'datetime' => new \DateTime('2013-01-27 23:14:44 CET'),
|
||||
'datetimeNegative' => new \DateTime('-2013-01-27 23:14:44 CET'),
|
||||
'datetimeNow' => new \DateTime(),
|
||||
'period' => (new \DateTime())->diff(new \DateTime('2013-01-27 23:14:44 CET')),
|
||||
'periodNegative' => (new \DateTime('2013-01-27 23:14:44 CET'))->diff(new \DateTime()),
|
||||
'periodZero' => (new \DateTime())->diff(new \DateTime()),
|
||||
'array' => ['e', 'a', 0x55],
|
||||
'object' => new \stdClass,
|
||||
'misaka' => '御坂 美琴',*/
|
||||
];
|
||||
foreach($this->getDependencies() as $dependency)
|
||||
$data['deps'][] = $dependency->getName();
|
||||
|
|
40
src/Dummy/DummyPackageFile.php
Normal file
40
src/Dummy/DummyPackageFile.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
namespace Patchouli\Dummy;
|
||||
|
||||
use Patchouli\IPackageFile;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class DummyPackageFile implements IPackageFile {
|
||||
private string $filename;
|
||||
|
||||
public function __construct(string $filename) {
|
||||
$this->filename = $filename;
|
||||
}
|
||||
|
||||
public function getFileName(): string {
|
||||
return $this->filename;;
|
||||
}
|
||||
|
||||
public function getFileType(): string {
|
||||
return 'application/octet-stream';
|
||||
}
|
||||
|
||||
public function isRemote(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getRemoteUrl(): string {
|
||||
return 'http://flash.moe/assets/errors/404.jpg';
|
||||
}
|
||||
|
||||
public function getLocalStream() {
|
||||
throw new UnexpectedValueException;
|
||||
}
|
||||
|
||||
public function fwifSerialize(): array {
|
||||
return [
|
||||
'name' => $this->getFileName(),
|
||||
'type' => $this->getFileType(),
|
||||
];
|
||||
}
|
||||
}
|
32
src/Dummy/DummyPackageTarget.php
Normal file
32
src/Dummy/DummyPackageTarget.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
namespace Patchouli\Dummy;
|
||||
|
||||
use Patchouli\Platform;
|
||||
use Patchouli\IPackageTarget;
|
||||
|
||||
class DummyPackageTarget implements IPackageTarget {
|
||||
function getPlatform(): Platform {
|
||||
return Platform::get(Platform::WIN_IA32);
|
||||
}
|
||||
|
||||
public function getFiles(): array {
|
||||
return [
|
||||
new DummyPackageFile('poop.exe'),
|
||||
];
|
||||
}
|
||||
|
||||
public function getDependencies(): array {
|
||||
return [];
|
||||
}
|
||||
|
||||
public function fwifSerialize(): array {
|
||||
$data = [
|
||||
'plat' => $this->getPlatform(),
|
||||
'files' => $this->getFiles(),
|
||||
'deps' => [],
|
||||
];
|
||||
foreach($this->getDependencies() as $pack)
|
||||
$data['deps'][] = $pack->getName();
|
||||
return $data;
|
||||
}
|
||||
}
|
21
src/ErrorResponse.php
Normal file
21
src/ErrorResponse.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
namespace Patchouli;
|
||||
|
||||
use FWIF\FWIFSerializable;
|
||||
|
||||
class ErrorResponse implements FWIFSerializable {
|
||||
private int $code;
|
||||
private string $message;
|
||||
|
||||
public function __construct(int $code, string $message = 'An unspecified error occurred.') {
|
||||
$this->code = $code;
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
public function fwifSerialize() {
|
||||
return [
|
||||
'c' => $this->code,
|
||||
'm' => $this->message,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -6,5 +6,7 @@ use FWIF\FWIFSerializable;
|
|||
interface IPackage extends FWIFSerializable {
|
||||
function getName(): string;
|
||||
function getVersion(): Version;
|
||||
function getFiles(): array;
|
||||
function getTargets(): array;
|
||||
function getDependencies(): array;
|
||||
}
|
||||
|
|
12
src/IPackageFile.php
Normal file
12
src/IPackageFile.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
namespace Patchouli;
|
||||
|
||||
use FWIF\FWIFSerializable;
|
||||
|
||||
interface IPackageFile extends FWIFSerializable {
|
||||
function getFileName(): string;
|
||||
function getFileType(): string;
|
||||
function isRemote(): bool;
|
||||
function getRemoteUrl(): string;
|
||||
function getLocalStream();
|
||||
}
|
10
src/IPackageTarget.php
Normal file
10
src/IPackageTarget.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
namespace Patchouli;
|
||||
|
||||
use FWIF\FWIFSerializable;
|
||||
|
||||
interface IPackageTarget extends FWIFSerializable {
|
||||
function getPlatform(): Platform;
|
||||
function getFiles(): array;
|
||||
function getDependencies(): array;
|
||||
}
|
4
src/PackageNotFoundException.php
Normal file
4
src/PackageNotFoundException.php
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
namespace Patchouli;
|
||||
|
||||
class PackageNotFoundException extends PatchouliException {}
|
|
@ -13,6 +13,7 @@ class Patchouli extends SingleInstance {
|
|||
}
|
||||
|
||||
public function _getPackage(string $packageName): IPackage {
|
||||
//throw new PackageNotFoundException;
|
||||
return new DummyPackage;
|
||||
}
|
||||
}
|
||||
|
|
4
src/PatchouliException.php
Normal file
4
src/PatchouliException.php
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
namespace Patchouli;
|
||||
|
||||
class PatchouliException extends \Exception {}
|
144
src/Platform.php
Normal file
144
src/Platform.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
namespace Patchouli;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use FWIF\FWIFSerializable;
|
||||
|
||||
class Platform implements FWIFSerializable {
|
||||
public const ANY = '*';
|
||||
|
||||
public const WINDOWS = 'win';
|
||||
public const OSX = 'mac';
|
||||
public const LINUX = 'lin';
|
||||
|
||||
public const IA32 = 'ia32';
|
||||
public const AMD64 = 'amd64';
|
||||
public const ARMSF = 'armsf';
|
||||
public const ARMHF = 'armhf';
|
||||
public const ARM64 = 'arm64';
|
||||
|
||||
public const ANY_ANY = self::ANY . '/' . self::ANY;
|
||||
|
||||
public const ANY_IA32 = self::ANY . '/' . self::IA32;
|
||||
public const ANY_AMD64 = self::ANY . '/' . self::AMD64;
|
||||
public const ANY_ARMSF = self::ANY . '/' . self::ARMSF;
|
||||
public const ANY_ARMHF = self::ANY . '/' . self::ARMHF;
|
||||
public const ANY_ARM64 = self::ANY . '/' . self::ARM64;
|
||||
|
||||
public const WIN_ANY = self::WINDOWS . '/' . self::ANY;
|
||||
public const WIN_IA32 = self::WINDOWS . '/' . self::IA32;
|
||||
public const WIN_AMD64 = self::WINDOWS . '/' . self::AMD64;
|
||||
public const WIN_ARM64 = self::WINDOWS . '/' . self::ARM64;
|
||||
|
||||
public const OSX_ANY = self::OSX . '/' . self::ANY;
|
||||
public const OSX_AMD64 = self::OSX . '/' . self::AMD64;
|
||||
public const OSX_ARM64 = self::OSX . '/' . self::ARM64;
|
||||
|
||||
public const LIN_ANY = self::LINUX . '/' . self::ANY;
|
||||
public const LIN_IA32 = self::LINUX . '/' . self::IA32;
|
||||
public const LIN_AMD64 = self::LINUX . '/' . self::AMD64;
|
||||
public const LIN_ARMSF = self::LINUX . '/' . self::ARMSF;
|
||||
public const LIN_ARMHF = self::LINUX . '/' . self::ARMHF;
|
||||
public const LIN_ARM64 = self::LINUX . '/' . self::ARM64;
|
||||
|
||||
private static $platforms = [];
|
||||
|
||||
public static function get(string $platform): self {
|
||||
if(empty(self::$platforms[$platform]))
|
||||
self::$platforms[$platform] = new static($platform);
|
||||
return self::$platforms[$platform];
|
||||
}
|
||||
|
||||
public static function getUser(?string $os = null, ?string $arch = null): self {
|
||||
$os ??= filter_input(INPUT_GET, 'os', FILTER_SANITIZE_STRING);
|
||||
$arch ??= filter_input(INPUT_GET, 'arch', FILTER_SANITIZE_STRING);
|
||||
if(empty($os) || !ctype_alnum($os))
|
||||
$os = self::ANY;
|
||||
if(empty($arch) || !ctype_alnum($arch))
|
||||
$arch = self::ANY;
|
||||
return self::get(sprintf('%s/%s', strtolower($os), strtolower($arch)));
|
||||
}
|
||||
|
||||
public static function isMatch(string $platform, Platform $other): bool {
|
||||
return self::get($platform)->match($other);
|
||||
}
|
||||
|
||||
public static function isWindows(Platform $other): bool { return self::isMatch(self::WIN_ANY, $other); }
|
||||
public static function isMacOS(Platform $other) : bool { return self::isMatch(self::OSX_ANY, $other); }
|
||||
public static function isLinux(Platform $other) : bool { return self::isMatch(self::LIN_ANY, $other); }
|
||||
|
||||
private string $os;
|
||||
private string $arch;
|
||||
private ?Version $version;
|
||||
|
||||
public function __construct(string $os, ?string $arch = null, ?Version $version = null) {
|
||||
if($arch == null) {
|
||||
if(strpos($os, '/') === true)
|
||||
throw new InvalidArgumentException('$arch cannot be null if $os doesn\'t contain a slash.');
|
||||
$parts = explode('/', $os, 2);
|
||||
$os = $parts[0];
|
||||
$arch = $parts[1];
|
||||
}
|
||||
|
||||
$this->os = $os;
|
||||
$this->arch = $arch;
|
||||
$this->version = $version;
|
||||
}
|
||||
|
||||
public function getOperatingSystem(): string {
|
||||
return $this->os;
|
||||
}
|
||||
|
||||
public function getArchitecture(): string {
|
||||
return $this->arch;
|
||||
}
|
||||
|
||||
public function hasVersion(): bool {
|
||||
return $this->version !== null;
|
||||
}
|
||||
public function getVersion(): Version {
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
public function withVersion(Version $version): self {
|
||||
return new static($this->getOperatingSystem(), $this->getArchitecture(), $version);
|
||||
}
|
||||
|
||||
public function matchOperatingSystem(Platform $other): bool {
|
||||
if($this->getOperatingSystem() === '*'
|
||||
|| $other->getOperatingSystem() === '*')
|
||||
return true;
|
||||
return $this->getOperatingSystem() === $other->getOperatingSystem();
|
||||
}
|
||||
|
||||
public function matchArchitecture(Platform $other): bool {
|
||||
if($this->getArchitecture() === '*'
|
||||
|| $other->getArchitecture() === '*')
|
||||
return true;
|
||||
return $this->getArchitecture() === $other->getArchitecture();
|
||||
}
|
||||
|
||||
public function matchVersion(Platform $other): bool {
|
||||
if(!$this->hasVersion())
|
||||
return !$other->hasVersion();
|
||||
if(!$other->hasVersion())
|
||||
return false;
|
||||
return $this->getVersion()->match($other->getVersion());
|
||||
}
|
||||
|
||||
public function match(Platform $other, bool $matchVersion = false): bool {
|
||||
if(!$this->matchOperatingSystem($other) || !$this->matchArchitecture($other))
|
||||
return false;
|
||||
if($matchVersion && !$this->matchVersion($other))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
return sprintf('%s/%s', $this->getOperatingSystem(), $this->getArchitecture());
|
||||
}
|
||||
|
||||
public function fwifSerialize() {
|
||||
return (string)$this;
|
||||
}
|
||||
}
|
|
@ -4,11 +4,15 @@ namespace Patchouli;
|
|||
use FWIF\FWIFSerializable;
|
||||
|
||||
class Version implements FWIFSerializable {
|
||||
public function fwifSerialize(): string {
|
||||
return (string)$this;
|
||||
public function match(Version $other): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
return '1.0.0';
|
||||
}
|
||||
|
||||
public function fwifSerialize(): string {
|
||||
return (string)$this;
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue