let the patching commence

This commit is contained in:
flash 2020-12-29 02:40:16 +00:00
parent 947e717920
commit 9447e65acd
13 changed files with 309 additions and 56 deletions

View file

@ -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.'));

View file

@ -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();

View 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(),
];
}
}

View 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
View 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,
];
}
}

View file

@ -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
View 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
View file

@ -0,0 +1,10 @@
<?php
namespace Patchouli;
use FWIF\FWIFSerializable;
interface IPackageTarget extends FWIFSerializable {
function getPlatform(): Platform;
function getFiles(): array;
function getDependencies(): array;
}

View file

@ -0,0 +1,4 @@
<?php
namespace Patchouli;
class PackageNotFoundException extends PatchouliException {}

View file

@ -13,6 +13,7 @@ class Patchouli extends SingleInstance {
}
public function _getPackage(string $packageName): IPackage {
//throw new PackageNotFoundException;
return new DummyPackage;
}
}

View file

@ -0,0 +1,4 @@
<?php
namespace Patchouli;
class PatchouliException extends \Exception {}

144
src/Platform.php Normal file
View 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;
}
}

View file

@ -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;
}
}