Proper exceptions and Initial NetworkStream implementation.

This commit is contained in:
flash 2018-01-05 03:43:09 +01:00
parent e012221046
commit 7cf113d962
9 changed files with 197 additions and 28 deletions

View file

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

View file

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

View file

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

View file

@ -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 = [

View file

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

View file

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

View file

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

View file

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