Proper exceptions and Initial NetworkStream implementation.
This commit is contained in:
parent
e012221046
commit
7cf113d962
9 changed files with 197 additions and 28 deletions
|
@ -3,6 +3,8 @@ namespace Misuzu;
|
||||||
|
|
||||||
use Aitemu\RouteCollection;
|
use Aitemu\RouteCollection;
|
||||||
use Misuzu\Config\ConfigManager;
|
use Misuzu\Config\ConfigManager;
|
||||||
|
use UnexpectedValueException;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the set up procedures.
|
* Handles the set up procedures.
|
||||||
|
@ -51,7 +53,7 @@ class Application extends ApplicationBase
|
||||||
public function startDatabase(): void
|
public function startDatabase(): void
|
||||||
{
|
{
|
||||||
if ($this->hasDatabase) {
|
if ($this->hasDatabase) {
|
||||||
throw new \Exception('Database module has already been started.');
|
throw new UnexpectedValueException('Database module has already been started.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addModule('database', new Database($this->config, self::DATABASE_CONNECTIONS[0]));
|
$this->addModule('database', new Database($this->config, self::DATABASE_CONNECTIONS[0]));
|
||||||
|
@ -70,7 +72,7 @@ class Application extends ApplicationBase
|
||||||
$section = 'Database.' . $name;
|
$section = 'Database.' . $name;
|
||||||
|
|
||||||
if (!$config->contains($section)) {
|
if (!$config->contains($section)) {
|
||||||
throw new \Exception("Database {$name} is not configured.");
|
throw new InvalidArgumentException("Database {$name} is not configured.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->addConnectionFromConfig($section, $name);
|
$database->addConnectionFromConfig($section, $name);
|
||||||
|
@ -83,7 +85,7 @@ class Application extends ApplicationBase
|
||||||
public function startTemplating(): void
|
public function startTemplating(): void
|
||||||
{
|
{
|
||||||
if ($this->hasTemplating) {
|
if ($this->hasTemplating) {
|
||||||
throw new \Exception('Templating module has already been started.');
|
throw new UnexpectedValueException('Templating module has already been started.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addModule('templating', $twig = new TemplateEngine);
|
$this->addModule('templating', $twig = new TemplateEngine);
|
||||||
|
@ -110,7 +112,7 @@ class Application extends ApplicationBase
|
||||||
public function startRouter(array $routes = null): void
|
public function startRouter(array $routes = null): void
|
||||||
{
|
{
|
||||||
if ($this->hasRouter) {
|
if ($this->hasRouter) {
|
||||||
throw new \Exception('Router module has already been started.');
|
throw new UnexpectedValueException('Router module has already been started.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addModule('router', $router = new RouteCollection);
|
$this->addModule('router', $router = new RouteCollection);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use UnexpectedValueException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all non-specific methods, for possibly using Misuzu as a framework for other things.
|
* Contains all non-specific methods, for possibly using Misuzu as a framework for other things.
|
||||||
*/
|
*/
|
||||||
|
@ -25,7 +28,7 @@ abstract class ApplicationBase
|
||||||
public static function getInstance(): ApplicationBase
|
public static function getInstance(): ApplicationBase
|
||||||
{
|
{
|
||||||
if (is_null(self::$instance) || !(self::$instance instanceof ApplicationBase)) {
|
if (is_null(self::$instance) || !(self::$instance instanceof ApplicationBase)) {
|
||||||
throw new \Exception('Invalid instance type.');
|
throw new UnexpectedValueException('Invalid instance type.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
|
@ -39,7 +42,7 @@ abstract class ApplicationBase
|
||||||
public static function start(...$params): ApplicationBase
|
public static function start(...$params): ApplicationBase
|
||||||
{
|
{
|
||||||
if (!is_null(self::$instance) || self::$instance instanceof ApplicationBase) {
|
if (!is_null(self::$instance) || self::$instance instanceof ApplicationBase) {
|
||||||
throw new \Exception('An Application has already been set up.');
|
throw new UnexpectedValueException('An Application has already been set up.');
|
||||||
}
|
}
|
||||||
|
|
||||||
self::$instance = new static(...$params);
|
self::$instance = new static(...$params);
|
||||||
|
@ -86,7 +89,7 @@ abstract class ApplicationBase
|
||||||
return $this->modules[$name];
|
return $this->modules[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \Exception('Invalid property.');
|
throw new InvalidArgumentException('Invalid property.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,7 +100,7 @@ abstract class ApplicationBase
|
||||||
public function addModule(string $name, $module): void
|
public function addModule(string $name, $module): void
|
||||||
{
|
{
|
||||||
if ($this->hasModule($name)) {
|
if ($this->hasModule($name)) {
|
||||||
throw new \Exception('This module has already been registered.');
|
throw new InvalidArgumentException('This module has already been registered.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->modules[$name] = $module;
|
$this->modules[$name] = $module;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
class Colour
|
class Colour
|
||||||
{
|
{
|
||||||
private const INHERIT = 0x40000000;
|
private const INHERIT = 0x40000000;
|
||||||
|
@ -106,7 +108,7 @@ class Colour
|
||||||
if ($hex_length === 3) {
|
if ($hex_length === 3) {
|
||||||
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
|
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
|
||||||
} elseif ($hex_length != 6) {
|
} elseif ($hex_length != 6) {
|
||||||
throw new \Exception('Invalid hex colour format! (find a more appropiate exception type)');
|
throw new InvalidArgumentException('Invalid hex colour format!');
|
||||||
}
|
}
|
||||||
|
|
||||||
return static::fromRGB(
|
return static::fromRGB(
|
||||||
|
|
|
@ -3,6 +3,7 @@ namespace Misuzu;
|
||||||
|
|
||||||
use Illuminate\Database\Capsule\Manager as LaravelDatabaseManager;
|
use Illuminate\Database\Capsule\Manager as LaravelDatabaseManager;
|
||||||
use Misuzu\Config\ConfigManager;
|
use Misuzu\Config\ConfigManager;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
class Database extends LaravelDatabaseManager
|
class Database extends LaravelDatabaseManager
|
||||||
{
|
{
|
||||||
|
@ -44,13 +45,13 @@ class Database extends LaravelDatabaseManager
|
||||||
public function addConnectionFromConfig(string $section, string $name = 'default'): void
|
public function addConnectionFromConfig(string $section, string $name = 'default'): void
|
||||||
{
|
{
|
||||||
if (!$this->configManager->contains($section, 'driver')) {
|
if (!$this->configManager->contains($section, 'driver')) {
|
||||||
throw new \Exception('Config section not found!');
|
throw new InvalidArgumentException('Config section not found!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$driver = $this->configManager->get($section, 'driver');
|
$driver = $this->configManager->get($section, 'driver');
|
||||||
|
|
||||||
if (!in_array($driver, self::SUPPORTED_DB_ALS)) {
|
if (!in_array($driver, self::SUPPORTED_DB_ALS)) {
|
||||||
throw new \Exception('Unsupported driver.');
|
throw new InvalidArgumentException('Unsupported driver.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$args = [
|
$args = [
|
||||||
|
|
|
@ -221,7 +221,6 @@ class FileStream extends Stream
|
||||||
|
|
||||||
public function writeChar(int $char): void
|
public function writeChar(int $char): void
|
||||||
{
|
{
|
||||||
$this->ensureHandleActive();
|
|
||||||
$this->write(chr($char), 0, 1);
|
$this->write(chr($char), 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
149
src/IO/NetworkStream.php
Normal file
149
src/IO/NetworkStream.php
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\IO;
|
||||||
|
|
||||||
|
class NetworkStream extends Stream
|
||||||
|
{
|
||||||
|
protected $resourceHandle;
|
||||||
|
protected $host;
|
||||||
|
protected $port;
|
||||||
|
protected $timeout;
|
||||||
|
|
||||||
|
public function __construct(string $host, int $port = -1, ?int $timeout = null)
|
||||||
|
{
|
||||||
|
$this->host = $host;
|
||||||
|
$this->port = $port;
|
||||||
|
$this->timeout = $timeout ?? (int)ini_get('default_socket_timeout');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->resourceHandle = fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
|
||||||
|
} catch (ErrorException $ex) {
|
||||||
|
throw new IOException($ex->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->resourceHandle === false) {
|
||||||
|
throw new IOException("[{$errno}] {$errstr}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->ensureHandleActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
if (!is_resource($this->resourceHandle)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResource(): resource
|
||||||
|
{
|
||||||
|
$this->ensureHandleActive();
|
||||||
|
return $this->resourceHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function ensureHandleActive(): void
|
||||||
|
{
|
||||||
|
if (!is_resource($this->resourceHandle)) {
|
||||||
|
throw new IOException("No active file handle.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCanRead(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCanSeek(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCanTimeout(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCanWrite(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getLength(): int
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPosition(): int
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getReadTimeout(): int
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getWriteTimeout(): int
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flush(): void
|
||||||
|
{
|
||||||
|
$this->ensureHandleActive();
|
||||||
|
fflush($this->resourceHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close(): void
|
||||||
|
{
|
||||||
|
$this->ensureHandleActive();
|
||||||
|
fclose($this->resourceHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read(int $length): string
|
||||||
|
{
|
||||||
|
$this->ensureHandleActive();
|
||||||
|
|
||||||
|
$read = fread($this->resourceHandle, $length);
|
||||||
|
|
||||||
|
if ($read === false) {
|
||||||
|
throw new IOException('Read failed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $read;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readChar(): int
|
||||||
|
{
|
||||||
|
$this->ensureHandleActive();
|
||||||
|
|
||||||
|
return ord(fgetc($this->resourceHandle));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(string $data): int
|
||||||
|
{
|
||||||
|
$this->ensureHandleActive();
|
||||||
|
|
||||||
|
$write = fwrite($this->resourceHandle, $data);
|
||||||
|
|
||||||
|
if ($write === false) {
|
||||||
|
throw new IOException('Write failed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $write;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function writeChar(int $char): void
|
||||||
|
{
|
||||||
|
$this->write(chr($char), 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SuppressWarnings("unused")
|
||||||
|
*/
|
||||||
|
public function seek(int $offset, int $origin): void
|
||||||
|
{
|
||||||
|
throw new IOException('This stream cannot perform seek operations.');
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\IO;
|
namespace Misuzu\IO;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
abstract class Stream
|
abstract class Stream
|
||||||
{
|
{
|
||||||
public const ORIGIN_CURRENT = 0;
|
public const ORIGIN_CURRENT = 0;
|
||||||
|
@ -15,8 +17,7 @@ abstract class Stream
|
||||||
return $this->{$name}();
|
return $this->{$name}();
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: specialised exception type
|
throw new InvalidArgumentException;
|
||||||
throw new IOException('Invalid property.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract protected function getCanRead(): bool;
|
abstract protected function getCanRead(): bool;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Net;
|
namespace Misuzu\Net;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CIDR functions.
|
* CIDR functions.
|
||||||
* @package Misuzu\Net
|
* @package Misuzu\Net
|
||||||
|
@ -10,15 +12,15 @@ class CIDR
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Matches an IP to a CIDR range.
|
* Matches an IP to a CIDR range.
|
||||||
* @param string $ip
|
* @param string $ipAddr
|
||||||
* @param string $range
|
* @param string $range
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function match(string $ip, string $range): bool
|
public static function match(string $ipAddr, string $range): bool
|
||||||
{
|
{
|
||||||
[$net, $mask] = explode('/', $range);
|
[$net, $mask] = explode('/', $range);
|
||||||
|
|
||||||
$ipv = IP::version($ip);
|
$ipv = IP::version($ipAddr);
|
||||||
$rangev = IP::version($net);
|
$rangev = IP::version($net);
|
||||||
|
|
||||||
if (!$ipv || !$rangev || $ipv !== $rangev) {
|
if (!$ipv || !$rangev || $ipv !== $rangev) {
|
||||||
|
@ -27,44 +29,44 @@ class CIDR
|
||||||
|
|
||||||
switch ($ipv) {
|
switch ($ipv) {
|
||||||
case IP::V6:
|
case IP::V6:
|
||||||
return static::matchV6($ip, $net, $mask);
|
return static::matchV6($ipAddr, $net, $mask);
|
||||||
|
|
||||||
case IP::V4:
|
case IP::V4:
|
||||||
return static::matchV4($ip, $net, $mask);
|
return static::matchV4($ipAddr, $net, $mask);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
throw new InvalidArgumentException('Invalid IP type.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches an IPv4 to a CIDR range.
|
* Matches an IPv4 to a CIDR range.
|
||||||
* @param string $ip
|
* @param string $ipAddr
|
||||||
* @param string $net
|
* @param string $net
|
||||||
* @param int $mask
|
* @param int $mask
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private static function matchV4(string $ip, string $net, int $mask): bool
|
private static function matchV4(string $ipAddr, string $net, int $mask): bool
|
||||||
{
|
{
|
||||||
$ip = ip2long($ip);
|
$ipAddr = ip2long($ipAddr);
|
||||||
$net = ip2long($net);
|
$net = ip2long($net);
|
||||||
$mask = -1 << (32 - $mask);
|
$mask = -1 << (32 - $mask);
|
||||||
return ($ip & $mask) === $net;
|
return ($ipAddr & $mask) === $net;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches an IPv6 to a CIDR range.
|
* Matches an IPv6 to a CIDR range.
|
||||||
* @param string $ip
|
* @param string $ipAddr
|
||||||
* @param string $net
|
* @param string $net
|
||||||
* @param int $mask
|
* @param int $mask
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private static function matchV6(string $ip, string $net, int $mask): bool
|
private static function matchV6(string $ipAddr, string $net, int $mask): bool
|
||||||
{
|
{
|
||||||
$ip = inet_pton($ip);
|
$ipAddr = inet_pton($ipAddr);
|
||||||
$net = inet_pton($net);
|
$net = inet_pton($net);
|
||||||
$mask = static::createV6Mask($mask);
|
$mask = static::createV6Mask($mask);
|
||||||
return ($ip & $mask) === $net;
|
return ($ipAddr & $mask) === $net;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,6 +3,7 @@ namespace MisuzuTests;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Misuzu\Colour;
|
use Misuzu\Colour;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
class ColourTest extends TestCase
|
class ColourTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -79,4 +80,13 @@ class ColourTest extends TestCase
|
||||||
$this->assertEquals($colour->blue, static::BLUE_HEX3);
|
$this->assertEquals($colour->blue, static::BLUE_HEX3);
|
||||||
$this->assertFalse($colour->inherit);
|
$this->assertFalse($colour->inherit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Invalid hex colour format!
|
||||||
|
*/
|
||||||
|
public function testHexException()
|
||||||
|
{
|
||||||
|
Colour::fromHex('invalid hex code');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue