diff --git a/.gitignore b/.gitignore
old mode 100755
new mode 100644
index 659c53b..4ffc936
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
/vendor/
/.vscode/
composer.lock
+phpunit.xml
diff --git a/README.md b/README.md
old mode 100755
new mode 100644
index e4364df..d91546d
--- a/README.md
+++ b/README.md
@@ -1 +1,100 @@
-web-socket
+
+# Socket
+
+## This is a layer for client and server socket connections.
+
+### PHP extension which have to be installed before to work:
+* [PHP 8.0](https://www.php.net/downloads)
+* [Yaml](https://www.php.net/manual/en/book.yaml.php)
+* [Sockets](https://www.php.net/manual/en/book.sockets.php)
+
+### Four actions you have to make:
+* Configure your configuration file.
+* Create client.php or server.php file
+* Call methods
+* Run from CLI or extends
+
+### Examples of TCP and UNIX sockets:
+
+#### 1) Create configuration file. File can be **ONLY** with yaml(yml) or json extensions
+
+##### * TCP socket configuration using YAML
+```
+settings:
+ socket_type: tcp
+ address: 127.0.0.1
+ port: 8000
+ content_length: 2048
+```
+
+##### * UNIX socket configuration using YAML
+```
+settings:
+ socket_type: unix
+ address: socket.sock
+ content_length: 2048
+```
+
+#### 2) Create client and server file handlers.
+
+##### server.php
+```
+runServer(function(ServerSocket $socket) {
+ echo $socket->send('Hello from server!');
+});
+```
+
+##### client.php
+```
+runClient(function(ClinetSocket $socket) {
+ echo $socket->send('Hello from client!');
+});
+```
+
+#### 3) Run from CLI
+```
+ john@doe:/workdir/$ php server.php
+ john@doe:/workdir/$ php client.php
+```
+
+#### 4) Extends from QonsilliumSocket
+```
+runClient(function(ClientSocket $client) use ($myMessage) {
+ return $client->send($myMessage);
+ });
+
+ if ($serverMessage === 'Hello from server!') {
+ // handle this action
+ }
+ }
+}
+```
+
+But when you will instantiate handler class don't forget to set configuration file with socket settings in constructor method
diff --git a/composer.json b/composer.json
old mode 100755
new mode 100644
index fd49e93..2d65aa5
--- a/composer.json
+++ b/composer.json
@@ -1,12 +1,14 @@
{
- "name": "rubyqorn/socket",
+ "name": "qonsillium/socket",
"description": "Socket layer over PHP socket api",
+ "keywords": ["socket", "stream", "datagram", "client", "server", "ipv6", "tcp", "udp", "icmp", "unix", "udg"],
+ "homepage": "https://github.com/rubyqorn/socket.git",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Anton Hideger",
- "email": "rubyqorn@example.com"
+ "email": "antonhideger1337@gmail.com"
}
],
"autoload": {
@@ -14,7 +16,11 @@
"Qonsillium\\": "src/"
}
},
- "require": {
+ "require-dev": {
"phpunit/phpunit": "^9.3"
+ },
+ "require": {
+ "php": "^8.0",
+ "ext-sockets": "*"
}
}
diff --git a/phpunit.xml b/phpunit.xml
deleted file mode 100755
index 3801934..0000000
--- a/phpunit.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- ./tests/unit/*
- ./tests/unit/SocketTest.php
- ./tests/unit/SocketCredentialsTest.php
-
-
\ No newline at end of file
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..0bafd3a
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,8 @@
+
+
+
+
+ tests/unit
+
+
+
\ No newline at end of file
diff --git a/src/AbstractSocket.php b/src/AbstractSocket.php
new file mode 100644
index 0000000..af3a120
--- /dev/null
+++ b/src/AbstractSocket.php
@@ -0,0 +1,25 @@
+credentials->getCredential('host');
+ }
+
+ /**
+ * Returns socket read legnth
+ * @return int
+ */
+ private function getReadLength()
+ {
+ return $this->credentials->getCredential('content_length');
+ }
+
+ /**
+ * @return \Qonsillium\Actions\SocketConnector
+ */
+ public function getConnector(string $type)
+ {
+ return new SocketConnector($this->getAddress(), $type);
+ }
+
+ /**
+ * @return \Qonsillium\Actions\SocketAcceptor
+ */
+ public function getAcceptor(): SocketAcceptor
+ {
+ return new SocketAcceptor();
+ }
+
+ /**
+ * @return \Qonsillium\Actions\SocketReader
+ */
+ public function getReader(): SocketReader
+ {
+ return new SocketReader($this->getReadLength());
+ }
+
+ /**
+ * @return \Qonsillium\Actions\SocketWriter
+ */
+ public function getWriter(): SocketWriter
+ {
+ return new SocketWriter();
+ }
+
+ /**
+ * @return \Qonsillium\Actions\SocketCloser
+ */
+ public function getCloser(): SocketCloser
+ {
+ return new SocketCloser();
+ }
+}
diff --git a/src/Actions/AbstractSocketAction.php b/src/Actions/AbstractSocketAction.php
new file mode 100644
index 0000000..1a3b665
--- /dev/null
+++ b/src/Actions/AbstractSocketAction.php
@@ -0,0 +1,45 @@
+make();
+ }
+
+ /**
+ * @param resource $socket
+ * @return void
+ */
+ public function setSocket($socket)
+ {
+ $this->socket = $socket;
+ }
+
+ /**
+ * @return resource
+ */
+ public function getSocket()
+ {
+ return $this->socket;
+ }
+
+ /**
+ * Make socket action
+ * @return mixed
+ */
+ abstract public function make();
+}
diff --git a/src/Actions/Connections/ClientConnection.php b/src/Actions/Connections/ClientConnection.php
new file mode 100644
index 0000000..2db7938
--- /dev/null
+++ b/src/Actions/Connections/ClientConnection.php
@@ -0,0 +1,20 @@
+getAddress(),
+ $errno,
+ $errstr,
+ $this->getTimeout() ?? $this->getTimeout()
+ );
+ }
+}
diff --git a/src/Actions/Connections/Connection.php b/src/Actions/Connections/Connection.php
new file mode 100644
index 0000000..2d33307
--- /dev/null
+++ b/src/Actions/Connections/Connection.php
@@ -0,0 +1,58 @@
+address = $address;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAddress()
+ {
+ return $this->address;
+ }
+
+ /**
+ * @param int $timeout
+ * @return void
+ */
+ public function setTimeout(int $timeout)
+ {
+ $this->timeout = $timeout;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTimeout()
+ {
+ return $this->timeout;
+ }
+
+ /**
+ * Create client or server socket connection
+ * @return resource
+ */
+ abstract public function create();
+}
diff --git a/src/Actions/Connections/ConnectionFactory.php b/src/Actions/Connections/ConnectionFactory.php
new file mode 100644
index 0000000..550679a
--- /dev/null
+++ b/src/Actions/Connections/ConnectionFactory.php
@@ -0,0 +1,20 @@
+getAddress(),
+ $errno,
+ $errstr
+ );
+ }
+}
diff --git a/src/Actions/SocketAcceptor.php b/src/Actions/SocketAcceptor.php
new file mode 100644
index 0000000..00a5a1f
--- /dev/null
+++ b/src/Actions/SocketAcceptor.php
@@ -0,0 +1,15 @@
+getSocket());
+ }
+}
diff --git a/src/Actions/SocketCloser.php b/src/Actions/SocketCloser.php
new file mode 100644
index 0000000..e69a4d3
--- /dev/null
+++ b/src/Actions/SocketCloser.php
@@ -0,0 +1,15 @@
+getSocket());
+ }
+}
diff --git a/src/Actions/SocketConnector.php b/src/Actions/SocketConnector.php
new file mode 100644
index 0000000..fb72e26
--- /dev/null
+++ b/src/Actions/SocketConnector.php
@@ -0,0 +1,32 @@
+type);
+ $connection->setAddress($this->address);
+ return $connection;
+ }
+}
diff --git a/src/Actions/SocketReader.php b/src/Actions/SocketReader.php
new file mode 100644
index 0000000..3ac5e53
--- /dev/null
+++ b/src/Actions/SocketReader.php
@@ -0,0 +1,49 @@
+message = $message;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ /**
+ * Read content from connected socket
+ * @return \Qonsillium\Actions\SocketReader
+ */
+ public function make()
+ {
+ $this->setMessage(fread($this->getSocket(), $this->length));
+ return $this;
+ }
+}
diff --git a/src/Actions/SocketWriter.php b/src/Actions/SocketWriter.php
new file mode 100644
index 0000000..44df756
--- /dev/null
+++ b/src/Actions/SocketWriter.php
@@ -0,0 +1,37 @@
+message = $message;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ /**
+ * Write messages to connected socket
+ * @return int
+ */
+ public function make()
+ {
+ return fwrite($this->getSocket(), $this->getMessage(), strlen($this->getMessage()));
+ }
+}
diff --git a/src/Bootstrapper.php b/src/Bootstrapper.php
new file mode 100644
index 0000000..208f951
--- /dev/null
+++ b/src/Bootstrapper.php
@@ -0,0 +1,103 @@
+container = new ServiceContainer();
+ $this->provider = new SocketServiceProvider($configFile);
+ $this->provider->register($this->container);
+ }
+
+ /**
+ * @return \Qonsillium\Credential\SocketCredentials
+ */
+ protected function getSocketCredentials(): SocketCredentials
+ {
+ return $this->container['credentials.socket']();
+ }
+
+ /**
+ * @return \Qonsillium\Parsers\ConfigParsersFactory
+ */
+ protected function getConfigParsersFactory(): ConfigParsersFactory
+ {
+ return $this->container['config.parser']();
+ }
+
+ /**
+ * @return \Qonsillium\Types\TypeConfiguration
+ */
+ protected function getSocketTypeConfigurator(): TypeConfiguration
+ {
+ return $this->container['config.socket_type']();
+ }
+
+ /**
+ * @return \Qonsillium\ActionFactory
+ */
+ protected function getSocketActionsFactory(): ActionFactory
+ {
+ return $this->container['socket.actions.factory']();
+ }
+
+ /**
+ * @return \Qonsillium\Types\SocketTypeFactory
+ */
+ protected function getSocketTypesFactory(): SocketTypeFactory
+ {
+ return $this->container['socket.types.factory']();
+ }
+
+ /**
+ * @return \Qonsillium\SocketFacade
+ */
+ protected function getSocketFacade(): SocketFacade
+ {
+ return $this->provider['socket.facade'];
+ }
+
+ /**
+ * @return \Qonsillium\ClientSocket
+ */
+ public function getClientSocketConnector(): ClientSocket
+ {
+ return $this->container['socket.connection.client']();
+ }
+
+ /**
+ * @return \Qonsillium\ServerSocket
+ */
+ public function getServerSocketConnector(): ServerSocket
+ {
+ return $this->container['socket.connection.server']();
+ }
+}
diff --git a/src/Client.php b/src/Client.php
deleted file mode 100644
index 8fce42b..0000000
--- a/src/Client.php
+++ /dev/null
@@ -1,71 +0,0 @@
-createdSocket = $this->connectToSocket();
-
- if (!$this->createdSocket) {
- return new SocketError('Can\'t accepted connected socket');
- }
-
- return $this->createdSocket;
- }
-
- /**
- * Read message from accepted server socket
- * @return \Qonsillium\SocketError|\Qonsillium\SocketMessage
- */
- public function read()
- {
- $socketResponse = new SocketMessage(
- $this->readFromSocket($this->createdSocket)
- );
-
- if (!$socketResponse->getSocketResponse()) {
- return new SocketError('Can\'t read message from client socket');
- }
-
- return $socketResponse;
- }
-
- /**
- * Write message to server accepted socket
- * @param string $message
- * @return int|\Qonsillium\SocketError
- */
- public function write(string $message)
- {
- $writtenMessage = $this->writeToSocket($this->createdSocket, $message);
-
- if (!$writtenMessage) {
- return new SocketError('Can\'t write to accepted client socket');
- }
-
- return $writtenMessage;
- }
-
- /**
- * Call Client destructor method when socket
- * connection was broken
- * @return void
- */
- public function __destruct()
- {
- return $this->closeSocketConnection($this->createdSocket);
- }
-}
diff --git a/src/ClientSocket.php b/src/ClientSocket.php
new file mode 100644
index 0000000..53fdd73
--- /dev/null
+++ b/src/ClientSocket.php
@@ -0,0 +1,23 @@
+facade->sendFromClient($message);
+
+ if (!$sendedMessage) {
+ return false;
+ }
+
+ return $sendedMessage;
+ }
+}
diff --git a/src/Credential/ICredential.php b/src/Credential/ICredential.php
old mode 100755
new mode 100644
diff --git a/src/Credential/SocketCredentials.php b/src/Credential/SocketCredentials.php
old mode 100755
new mode 100644
index ad489a8..7332993
--- a/src/Credential/SocketCredentials.php
+++ b/src/Credential/SocketCredentials.php
@@ -4,19 +4,6 @@
class SocketCredentials implements ICredential
{
- /**
- * Host name where will
- * be connected
- * @var string
- */
- private string $host;
-
- /**
- * Port for host
- * @var string
- */
- private string $port;
-
/**
* Set credentials for socket connection
* @param string $name
@@ -37,4 +24,18 @@ public function getCredential(string $name)
{
return $this->$name;
}
+
+ /**
+ * Validate existence of credential
+ * @param string $name
+ * @return bool
+ */
+ public function validateExistence(string $name)
+ {
+ if (!property_exists($this, $name)) {
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/src/DI/IServiceProvider.php b/src/DI/IServiceProvider.php
new file mode 100644
index 0000000..c4e6e2f
--- /dev/null
+++ b/src/DI/IServiceProvider.php
@@ -0,0 +1,13 @@
+services[$offset] = $value;
+ }
+
+ /**
+ * @param string $offset
+ * @return mixed
+ */
+ public function offsetGet($offset)
+ {
+ return $this->services[$offset];
+ }
+
+ /**
+ * @param string $offset
+ * @return bool
+ */
+ public function offsetExists($offset)
+ {
+ return isset($this->services[$offset]);
+ }
+
+ /**
+ * @param string $offset
+ * @return void
+ */
+ public function offsetUnset($offset)
+ {
+ unset($this->services[$offset]);
+ }
+
+ /**
+ * @param \Qonsillium\DI\IServiceProvider $provider
+ * @return void
+ */
+ public function register(IServiceProvider $provider)
+ {
+ return $provider->register($this);
+ }
+}
diff --git a/src/Exceptions/ConfigFileDoesntExists.php b/src/Exceptions/ConfigFileDoesntExists.php
new file mode 100644
index 0000000..fb90560
--- /dev/null
+++ b/src/Exceptions/ConfigFileDoesntExists.php
@@ -0,0 +1,13 @@
+configFileExtension = pathinfo($this->configFile)['extension'];
+ $this->nullObj = new NullConfigFile($this->configFile);
+ }
+
+ /**
+ * Factory method which return config file
+ * handler by its extension. Can be ONLY
+ * yaml(yml) or json
+ * @return \Qonsillium\Parsers\ConfigParser
+ */
+ public function getParser(): ConfigParser
+ {
+ if ($this->configFileExtension === 'yaml' || $this->configFileExtension === 'yml') {
+ return new YAMLConfigParser($this->configFile);
+ } elseif ($this->configFileExtension === 'json') {
+ return new JSONConfigParser($this->configFile);
+ } else {
+ return $this->nullObj;
+ }
+ }
+}
diff --git a/src/Parsers/JSONConfigParser.php b/src/Parsers/JSONConfigParser.php
new file mode 100644
index 0000000..6096f25
--- /dev/null
+++ b/src/Parsers/JSONConfigParser.php
@@ -0,0 +1,16 @@
+file), true);
+ }
+}
diff --git a/src/Parsers/NullConfigFile.php b/src/Parsers/NullConfigFile.php
new file mode 100644
index 0000000..7b72dd8
--- /dev/null
+++ b/src/Parsers/NullConfigFile.php
@@ -0,0 +1,15 @@
+file);
+ }
+}
diff --git a/src/QonsilliumSocket.php b/src/QonsilliumSocket.php
new file mode 100644
index 0000000..10aff1c
--- /dev/null
+++ b/src/QonsilliumSocket.php
@@ -0,0 +1,85 @@
+bootstrapper = new Bootstrapper($configFile);
+ }
+
+ /**
+ * Return ClientSocket handler
+ * @return \Qonsillium\ClientSocket
+ */
+ protected function getClientSocket(): ClientSocket
+ {
+ return $this->bootstrapper->getClientSocketConnector();
+ }
+
+ /**
+ * Return ServerSocket handler
+ * @return \Qonsillium\ServerSocket
+ */
+ protected function getServerSocket(): ServerSocket
+ {
+ return $this->bootstrapper->getServerSocketConnector();
+ }
+
+ /**
+ * Run client socket and handle user
+ * setted callback function.
+ * @param \Closure $handler
+ *
+ * Example:
+ * $socket = QonsilliumSocket('config.yml');
+ * $socket->runClient(function(ClientSocket $client) {
+ * $client->send('Hello from client');
+ * })
+ *
+ * @return void
+ */
+ public function runClient(Closure $handler)
+ {
+ return $handler($this->getClientSocket());
+ }
+
+ /**
+ * Run server socket and handle user
+ * setted callback function.
+ * @param \Closure $handler
+ *
+ * Example:
+ * $socket = QonsilliumSocket('config.yml');
+ * $socket->runClient(function(ServerSocket $server) {
+ * $server->send('Hello from server');
+ * })
+ *
+ * @return void
+ */
+ public function runServer(Closure $handler)
+ {
+ return $handler($this->getServerSocket());
+ }
+}
diff --git a/src/Server.php b/src/Server.php
deleted file mode 100644
index 549addb..0000000
--- a/src/Server.php
+++ /dev/null
@@ -1,71 +0,0 @@
-createdSocket = $this->acceptConnectionOnSocket();
-
- if (!$this->createdSocket) {
- return new SocketError('Can\'t accepted connected socket');
- }
-
- return $this->createdSocket;
- }
-
- /**
- * Read message from accepted client socket
- * @return \Qonsillium\SocketError|\Qonsillium\SocketMessage
- */
- public function read()
- {
- $socketResponse = new SocketMessage(
- $this->readFromSocket($this->createdSocket)
- );
-
- if (!$socketResponse->getSocketResponse()) {
- return new SocketError('Can\'t read message from client socket');
- }
-
- return $socketResponse;
- }
-
- /**
- * Write message to client accepted socket
- * @param string $message
- * @return int|\Qonsillium\SocketError
- */
- public function write(string $message)
- {
- $writtenMessage = $this->writeToSocket($this->createdSocket, $message);
-
- if (!$writtenMessage) {
- return new SocketError('Can\'t write to accepted client socket');
- }
-
- return $writtenMessage;
- }
-
- /**
- * Call Server destructor method when socket
- * connection was broken
- * @return void
- */
- public function __destruct()
- {
- return $this->closeSocketConnection($this->createdSocket);
- }
-}
diff --git a/src/ServerSocket.php b/src/ServerSocket.php
new file mode 100644
index 0000000..2814ed0
--- /dev/null
+++ b/src/ServerSocket.php
@@ -0,0 +1,23 @@
+facade->sendFromServer($message);
+
+ if (!$sendedMessage) {
+ return false;
+ }
+
+ return $sendedMessage;
+ }
+}
diff --git a/src/ServiceContainer.php b/src/ServiceContainer.php
deleted file mode 100644
index 2eb4e41..0000000
--- a/src/ServiceContainer.php
+++ /dev/null
@@ -1,123 +0,0 @@
-helper = new ServicesHelper();
- }
-
- /**
- * Validate service name existence in container
- * @param string $serviceName
- * @return string
- * @throws \Qonsillium\Exceptions\ServiceNotFound
- */
- private function validateServiceExistence(string $serviceName)
- {
- return $this->helper->validateService($serviceName);
- }
-
- /**
- * Validate availablility of Server socket layer
- * and return instance of this class
- * @return \Qonsillium\Server
- */
- public function serverSocketHandler(): Server
- {
- $service = $this->validateServiceExistence('server_socket');
-
- if (!$service) {
- return false;
- }
-
- return new $service();
- }
-
- /**
- * Validate availablility of Client socket layer
- * and return instance of this class
- * @return \Qonsillium\Client
- */
- public function clientSocketHandler(): Client
- {
- $service = $this->validateServiceExistence('client_socket');
-
- if (!$service) {
- return false;
- }
-
- return new $service();
- }
-
- /**
- * Validate availablility of Socket layer
- * and return instance of this class
- * @return \Qonsillium\Socket
- */
- public function socketLayerHandler(): Socket
- {
- $service = $this->validateServiceExistence('socket_layer');
-
- if (!$service) {
- return false;
- }
-
- return new $service();
- }
-
- /**
- * Validate availablility of SocketEndpoint layer
- * and return instance of this class
- * @return \Qonsillium\SocketEndpoint
- */
- public function socketsManagerHandler(): SocketEndpoint
- {
- $service = $this->validateServiceExistence('socket_endpoint');
-
- if (!$service) {
- return false;
- }
-
- return new $service();
- }
-
- /**
- * Validate availablility of SocketCredentials layer
- * and return instance of this class
- * @return \Qonsillium\SocketCredentials
- */
- public function socketCredentialsHandler(): SocketCredentials
- {
- $service = $this->validateServiceExistence('socket_credential');
-
- if (!$service) {
- return false;
- }
-
- return new $service();
- }
-
- public function bootstrap()
- {
- //
- }
-}
diff --git a/src/ServicesHelper.php b/src/ServicesHelper.php
deleted file mode 100644
index 40d0536..0000000
--- a/src/ServicesHelper.php
+++ /dev/null
@@ -1,81 +0,0 @@
- Client::class,
- 'server_socket' => Server::class,
- 'socket_layer' => Socket::class,
- 'socket_endpoint' => SocketEndpoint::class,
- 'socket_credentials' => SocketCredentials::class
- ];
-
- /**
- * Register new service in service container. Must set
- * new service using little descriptive name, but if
- * you SET service name which already exists this will
- * delete previous service, and class name which respond for
- * this service
- * @param string $descriptiveName
- * @param string $className
- * @return void
- */
- public function addToList(string $descriptiveName, string $className)
- {
- $this->container[$descriptiveName] = $className;
- }
-
- /**
- * Return service from services list by unique
- * key
- * @param string $serviceName
- * @return mixed
- */
- public function getFromList(string $serviceName)
- {
- return $this->container[$serviceName];
- }
-
- /**
- * Validate service existence and return namespace
- * of this service in string representation or throws
- * exception
- * @param string $serviceName
- * @return string
- * @throws \Qonsillium\Exceptions\ServiceNotFound
- */
- public function validateService(string $serviceName)
- {
- $service = "\\{$this->getFromList($serviceName)}";
-
- if (!class_exists($service)) {
- throw new ServiceNotFound("Service with {$serviceName} was not found");
- }
-
- return $service;
- }
-
- /**
- * Remove service from services list by unique key
- * @param string $serviceName
- * @return void
- */
- public function removeFromList(string $serviceName)
- {
- unset($this->container[$serviceName]);
- }
-}
diff --git a/src/Socket.php b/src/Socket.php
deleted file mode 100755
index 4026462..0000000
--- a/src/Socket.php
+++ /dev/null
@@ -1,168 +0,0 @@
-host = $host;
- $this->port = $port;
- $this->socket = $this->create();
- }
-
- /**
- * Creates and returns a socket resource, also
- * referred to as an endpoint of communication
- * @return resource
- */
- public function create()
- {
- return socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
- }
-
- /**
- * Binds a name to a socket
- * @return bool
- */
- public function bind()
- {
- return socket_bind($this->socket, $this->host, $this->port);
- }
-
- /**
- * Listens for a connection on a socket
- * @return bool
- */
- public function listen()
- {
- return socket_listen($this->socket, 1);
- }
-
- /**
- * Accept a connection on a socket
- * @return resource
- */
- public function accept()
- {
- return socket_accept($this->socket);
- }
-
- /**
- * Bind, listen and return accepted socket
- * connection
- * @return resource
- */
- public function acceptSocketConnection()
- {
- if (!$this->bind()) {
- return false;
- }
-
- if (!$this->listen()) {
- return false;
- }
-
- $acceptedSocket = $this->accept();
-
- if (!$acceptedSocket) {
- return false;
- }
-
- return $acceptedSocket;
- }
-
- /**
- * Return resource of type Socket
- * which was created right now. Can get
- * access by connect method
- * @return resource
- */
- public function getConnectedSocket()
- {
- return $this->socket;
- }
-
- /**
- * Initiates a connection on a socket
- * @return \Qonsillium\Socket
- */
- public function connect()
- {
- socket_connect(
- $this->socket, $this->host, $this->port
- );
-
- return $this->socket;
- }
-
- /**
- * Write to a socket specified messages
- * @param string $message
- * @return int
- */
- public function write($socket, string $message)
- {
- return socket_write(
- $socket, $message, strlen($message)
- );
- }
-
- /**
- * Reads a maximum of length bytes from a socket
- * @param resource $socket
- * @return string
- */
- public function read($socket)
- {
- while(socket_recv($socket, $buffer, 2048, 0)) {
- $this->content .= $buffer;
- }
-
- return $this->content;
- }
-
- /**
- * Close specified socket connection
- * @param resource $socket
- * @return void
- */
- public function close($socket)
- {
- return socket_close($socket);
- }
-}
diff --git a/src/SocketEndpoint.php b/src/SocketEndpoint.php
deleted file mode 100755
index 7e00777..0000000
--- a/src/SocketEndpoint.php
+++ /dev/null
@@ -1,95 +0,0 @@
-credential = $credential;
- }
-
- /**
- * Return instance of SocketCredentials
- * @return SocketCredentials
- */
- public function getCredentials()
- {
- return $this->credential;
- }
-
- /**
- * Socket factory method which manipulate
- * PHP socket API
- * @return \Qonsillium\Socket
- */
- protected function getSocket()
- {
- return new Socket(
- $this->getCredentials()->getCredential('host'),
- $this->getCredentials()->getCredential('port')
- );
- }
-
- /**
- * Bind, listen and accept connection on socket.
- * Usually use when wanted to create server socket
- * @return resource|bool
- */
- protected function acceptConnectionOnSocket()
- {
- return $this->getSocket()->acceptSocketConnection();
- }
-
- /**
- * Connect to created to socket. Usually use
- * when wanted to create client socket
- * @return resource|bool
- */
- protected function connectToSocket()
- {
- return $this->getSocket()->connect();
- }
-
- /**
- * Write content from current listening socket
- * @param resource $socket
- * @param string $message
- * @return int
- */
- protected function writeToSocket($socket, string $message)
- {
- return $this->getSocket()->write($socket, $message);
- }
-
- /**
- * Read content from current listening socket
- * @param resource $socket
- * @return string
- */
- protected function readFromSocket($socket)
- {
- return $this->getSocket()->read($socket);
- }
-
- /**
- * Close socket connection which was created
- * acceptSocketConnection() or connectToSocket()
- * @param resource $socket
- * @return void
- */
- protected function closeSocketConnection($socket)
- {
- return $this->getSocket()->close($socket);
- }
-}
diff --git a/src/SocketError.php b/src/SocketError.php
deleted file mode 100644
index 1ed0e61..0000000
--- a/src/SocketError.php
+++ /dev/null
@@ -1,31 +0,0 @@
-errorMessage = $error;
- }
-
- /**
- * Return setted socket error
- * @return string
- */
- public function getSocketError()
- {
- return $this->errorMessage;
- }
-}
diff --git a/src/SocketFacade.php b/src/SocketFacade.php
new file mode 100644
index 0000000..98014db
--- /dev/null
+++ b/src/SocketFacade.php
@@ -0,0 +1,173 @@
+factory->getConnector($connectionType);
+ return $connector()->create();
+ }
+
+ /**
+ * Accept socket connections
+ * @param \Socket $socket
+ * @return bool
+ */
+ protected function acceptSocket($socket)
+ {
+ $acceptor = $this->factory->getAcceptor();
+ $acceptor->setSocket($socket);
+ $acceptAction = $acceptor();
+
+ if (!$acceptAction) {
+ return false;
+ }
+
+ return $acceptAction;
+ }
+
+ /**
+ * Read messages from client or server sockets
+ * @param \Socket $socket
+ * @return bool|\Qonsillium\SocketReader
+ */
+ protected function readSocket($socket)
+ {
+ $reader = $this->factory->getReader();
+ $reader->setSocket($socket);
+ $readAction = $reader();
+
+ if (!$readAction) {
+ return false;
+ }
+
+ return $readAction;
+ }
+
+ /**
+ * Write messages on client or server sockets
+ * @param \Socket $socket
+ * @param string $message
+ * @return bool|int
+ */
+ protected function writeSocket($socket, string $message)
+ {
+ $writer = $this->factory->getWriter();
+ $writer->setSocket($socket);
+ $writer->setMessage($message);
+ $writeAction = $writer();
+
+ if (!$writeAction) {
+ return false;
+ }
+
+ return $writeAction;
+ }
+
+ /**
+ * Close accepted or created socket connections
+ * @throws \Qonsillium\Exceptions\FailedCloseSocket
+ * @return void
+ */
+ public function closeSocket($socket)
+ {
+ $closer = $this->factory->getCloser();
+ $closer->setSocket($socket);
+ return $closer();
+ }
+
+ /**
+ * This method can be used only with ServerSocket.
+ * Here we create, bind, listen, accept, read and
+ * write socket
+ * @param string $message
+ * @throws \Qonsillium\Exceptions\FailedCconnectSocket
+ * @throws \Qonsillium\Exceptions\FailedWriteSocket
+ * @return string
+ */
+ public function sendFromServer(string $message)
+ {
+ $server = $this->connectSocket('server');
+
+ if (!$server) {
+ throw new FailedConnectSocket('Failed to connect server socket');
+ }
+
+ while ($client = $this->acceptSocket($server)) {
+ $written = $this->writeSocket($client, $message);
+
+ if (!$written) {
+ throw new FailedWriteSocket('Failed to write to client socket');
+ }
+
+ $this->content .= $this->readSocket($client)->getMessage();
+ $this->closeSocket($client);
+ }
+
+ $this->closeSocket($server);
+
+ return $this->content;
+ }
+
+ /**
+ * This method can be used only with ClientSocket.
+ * Here we create, read and write socket
+ * @param string $message
+ * @throws \Qonsillium\Exceptions\FailedConnectSocket
+ * @throws \Qonsillium\Exceptions\FailedWriteSocket
+ * @throws \Qonsillium\Exceptions\FailedReadSocket
+ * @return string
+ */
+ public function sendFromClient(string $message)
+ {
+ $client = $this->connectSocket('client');
+
+ if (!$client) {
+ throw new FailedConnectSocket('Failed to connect client socket');
+ }
+
+ $written = $this->writeSocket($client, $message);
+
+ if (!$written) {
+ throw new FailedWriteSocket('Failed to write to server socket');
+ }
+
+ while(!feof($client)) {
+ $this->content .= $this->readSocket($client)->getMessage();
+ }
+
+ $this->closeSocket($client);
+
+ return $this->content;
+ }
+}
diff --git a/src/SocketMessage.php b/src/SocketMessage.php
deleted file mode 100755
index 9af76f7..0000000
--- a/src/SocketMessage.php
+++ /dev/null
@@ -1,31 +0,0 @@
-message = $message;
- }
-
- /**
- * Get current readed socket response
- * @return string
- */
- public function getSocketResponse()
- {
- return $this->message;
- }
-}
diff --git a/src/SocketServiceProvider.php b/src/SocketServiceProvider.php
new file mode 100644
index 0000000..13f4d48
--- /dev/null
+++ b/src/SocketServiceProvider.php
@@ -0,0 +1,93 @@
+configFile = $configFile;
+ }
+
+ /**
+ * Register socket services
+ * @param \Qonsillium\DI\ServiceContainer
+ */
+ public function register(ServiceContainer $container)
+ {
+ $container['config.file'] = $this->configFile;
+
+ $container['config.parser'] = function() use ($container) {
+ return new ConfigParsersFactory($container['config.file']);
+ };
+
+ $container['config.socket_type'] = function() use ($container) {
+ return new TypeConfiguration($container['config.parser']()->getParser()->parse());
+ };
+
+ $container['credentials.socket'] = function() use ($container) {
+ $credential = new SocketCredentials();
+ $parsedConfig = $container['config.parser']()->getParser()->parse()['settings'];
+
+ // Set socket host credentials. We have only two types
+ // It's unix and tcp, another will be ignored
+ if ($parsedConfig['socket_type'] === 'unix') {
+ $credential->setCredential(
+ 'host',
+ "{$parsedConfig['socket_type']}://{$parsedConfig['address']}"
+ );
+ } elseif($parsedConfig['socket_type'] === 'tcp') {
+ $credential->setCredential(
+ 'host',
+ "{$parsedConfig['socket_type']}://{$parsedConfig['address']}:{$parsedConfig['port']}"
+ );
+ }
+
+ $credential->setCredential(
+ 'content_length',
+ $parsedConfig['content_length']
+ );
+
+ return $credential;
+ };
+
+ $container['socket.actions.factory'] = function() use ($container) {
+ return new ActionFactory($container['credentials.socket']());
+ };
+
+ $container['socket.types.factory'] = function() use ($container) {
+ return new SocketTypeFactory($container['config.socket_type']());
+ };
+
+ $container['socket.facade'] = function() use ($container) {
+ return new SocketFacade($container['socket.actions.factory']());
+ };
+
+ $container['socket.connection.client'] = function() use ($container) {
+ return new ClientSocket($container['socket.facade']());
+ };
+
+ $container['socket.connection.server'] = function() use ($container) {
+ return new ServerSocket($container['socket.facade']());
+ };
+ }
+}
diff --git a/src/Types/NullSocketType.php b/src/Types/NullSocketType.php
new file mode 100644
index 0000000..9f585a4
--- /dev/null
+++ b/src/Types/NullSocketType.php
@@ -0,0 +1,15 @@
+configuration->validateSettingsExistence($setting)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Return setting which was setted in
+ * configuration file and validate existence
+ * @return bool|string
+ */
+ public function get(string $setting)
+ {
+ if (!$this->validate($setting)) {
+ return false;
+ }
+
+ return $this->configuration->getConfigurationSetting($setting);
+ }
+
+ /**
+ * Configure TCP or Unix socket
+ * @return void
+ */
+ abstract public function configure();
+}
diff --git a/src/Types/SocketTypeFactory.php b/src/Types/SocketTypeFactory.php
new file mode 100644
index 0000000..d33db8f
--- /dev/null
+++ b/src/Types/SocketTypeFactory.php
@@ -0,0 +1,42 @@
+nullObj = new NullSocketType($this->configuration);
+ }
+
+ /**
+ * Factory method which return socket by
+ * type
+ * @param string $type
+ * @return \Qonsillium\Types\SocketType
+ */
+ public function getSocket(string $type): SocketType
+ {
+ if ($type === 'tcp') {
+ return new TCPSocketType($this->configuration);
+ } elseif ($type === 'unix') {
+ return new UnixSocketType($this->configuration);
+ } else {
+ return $this->nullObj;
+ }
+ }
+}
diff --git a/src/Types/TCPSocketType.php b/src/Types/TCPSocketType.php
new file mode 100644
index 0000000..0349e02
--- /dev/null
+++ b/src/Types/TCPSocketType.php
@@ -0,0 +1,15 @@
+configuration->configure();
+ }
+}
diff --git a/src/Types/TypeConfiguration.php b/src/Types/TypeConfiguration.php
new file mode 100644
index 0000000..484a396
--- /dev/null
+++ b/src/Types/TypeConfiguration.php
@@ -0,0 +1,58 @@
+settings as $key => $value) {
+ $this->configured[$key] = $value;
+ }
+ }
+
+ /**
+ * Validate settings existence in list
+ * @param string $setting
+ * @return bool
+ */
+ public function validateSettingsExistence(string $setting)
+ {
+ if (!isset($this->configured[$setting])) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Return configured setting by passsed name
+ * @return string
+ */
+ public function getConfigurationSetting(string $setting)
+ {
+ return $this->configured[$setting];
+ }
+}
diff --git a/src/Types/UnixSocketType.php b/src/Types/UnixSocketType.php
new file mode 100644
index 0000000..eb6f99a
--- /dev/null
+++ b/src/Types/UnixSocketType.php
@@ -0,0 +1,15 @@
+configuration->configure();
+ }
+}
diff --git a/tests/unit/ActionFactoryTest.php b/tests/unit/ActionFactoryTest.php
new file mode 100644
index 0000000..39a79da
--- /dev/null
+++ b/tests/unit/ActionFactoryTest.php
@@ -0,0 +1,91 @@
+credentials = new SocketCredentials;
+ $this->credentials->setCredential('host', 'tcp://127.0.0.1:8000');
+ $this->credentials->setCredential('content_length', 2048);
+
+ $this->factory = new ActionFactory($this->credentials);
+ }
+
+ public function testGetAddressReturnsSameStringAndIsString()
+ {
+ $this->assertIsString(
+ $this->factory->getAddress(),
+ 'ActionFactory::getAddress is null. Expected string'
+ );
+
+ $this->assertSame(
+ 'tcp://127.0.0.1:8000',
+ $this->factory->getAddress(),
+ 'ActionFactory::getAddress expected string with "tcp://127.0.0.1:8000", but getting null'
+ );
+ }
+
+ public function testGetConnectorReturnsSocketConnectorInstance()
+ {
+ $this->assertInstanceOf(
+ SocketConnector::class,
+ $this->factory->getConnector('server'),
+ 'ActionFactory::getConnector expected type SocketConnector but getting null'
+ );
+ }
+
+ public function testGetAcceptorReturnsSocketAcceptorInstance()
+ {
+ $this->assertInstanceOf(
+ SocketAcceptor::class,
+ $this->factory->getAcceptor(),
+ 'ActionFactory::getAcceptor expected type SocketAcceptor but getting null'
+ );
+ }
+
+ public function testGetReaderReturnsSocketReaderInstance()
+ {
+ $this->assertInstanceOf(
+ SocketReader::class,
+ $this->factory->getReader(),
+ 'ActionFactory::getReader expected type SocketReader but getting null'
+ );
+ }
+
+ public function testGetReaderReturnsSocketWriterInstance()
+ {
+ $this->assertInstanceOf(
+ SocketWriter::class,
+ $this->factory->getWriter(),
+ 'ActionFactory::getWriter expected type SocketWriter but getting null'
+ );
+ }
+
+ public function testGetReaderReturnsSocketCloserInstance()
+ {
+ $this->assertInstanceOf(
+ SocketCloser::class,
+ $this->factory->getCloser(),
+ 'ActionFactory::getWriter expected type SocketCloser but getting null'
+ );
+ }
+
+ public function tearDown(): void
+ {
+ unset($this->credentials);
+ unset($this->factory);
+ }
+}
diff --git a/tests/unit/Actions/Connections/ConnectionFactoryTest.php b/tests/unit/Actions/Connections/ConnectionFactoryTest.php
new file mode 100644
index 0000000..cad6584
--- /dev/null
+++ b/tests/unit/Actions/Connections/ConnectionFactoryTest.php
@@ -0,0 +1,15 @@
+assertInstanceOf(Connection::class, $factory->getConnection('server'));
+ }
+}
diff --git a/tests/unit/Credential/SocketCredentialTest.php b/tests/unit/Credential/SocketCredentialTest.php
new file mode 100644
index 0000000..a389a3e
--- /dev/null
+++ b/tests/unit/Credential/SocketCredentialTest.php
@@ -0,0 +1,25 @@
+setCredential('host', 'tcp://127.0.0.1:8000');
+
+ $this->assertSame('tcp://127.0.0.1:8000', $credentials->getCredential('host'));
+ }
+
+ public function testPropertyExistenceValidatorReturnsBool()
+ {
+ $credentials = new SocketCredentials();
+ $credentials->setCredential('host', 'tcp://127.0.0.1:8000');
+ $this->assertTrue(
+ $credentials->validateExistence('host'),
+ "SocketCredentials::validateExistence. Expected property 'host', but doesn't exists"
+ );
+ }
+}
diff --git a/tests/unit/Parsers/ConfigParsersFactoryTest.php b/tests/unit/Parsers/ConfigParsersFactoryTest.php
new file mode 100644
index 0000000..9988322
--- /dev/null
+++ b/tests/unit/Parsers/ConfigParsersFactoryTest.php
@@ -0,0 +1,22 @@
+assertInstanceOf(
+ ConfigParser::class,
+ $factory->getParser(),
+ 'ConfigParserFactory::getParser, Expected type ConfigParser, but getting null'
+ );
+ }
+}
diff --git a/tests/unit/Parsers/JSONConfigParserTest.php b/tests/unit/Parsers/JSONConfigParserTest.php
new file mode 100644
index 0000000..44e5423
--- /dev/null
+++ b/tests/unit/Parsers/JSONConfigParserTest.php
@@ -0,0 +1,16 @@
+assertIsArray(
+ $factory->getParser()->parse(),
+ "JSONConfigParser::parse. Expected type 'array', but getting null"
+ );
+ }
+}
diff --git a/tests/unit/Parsers/YAMLConfigParserTest.php b/tests/unit/Parsers/YAMLConfigParserTest.php
new file mode 100644
index 0000000..85015c8
--- /dev/null
+++ b/tests/unit/Parsers/YAMLConfigParserTest.php
@@ -0,0 +1,16 @@
+assertIsArray(
+ $factory->getParser()->parse(),
+ "YAMLConfigParser::parse. Expected 'array', but getting null"
+ );
+ }
+}
diff --git a/tests/unit/SocketCredentialsTest.php b/tests/unit/SocketCredentialsTest.php
deleted file mode 100755
index ec2c63d..0000000
--- a/tests/unit/SocketCredentialsTest.php
+++ /dev/null
@@ -1,24 +0,0 @@
-assertInstanceOf(
- \WebSocket\Credential\ICredential::class,
- $credential
- );
-
- $credential->setCredential('host', 'localhost');
-
- $this->assertSame(
- $credential->getCredential('host'),
- 'localhost'
- );
- }
-}
\ No newline at end of file
diff --git a/tests/unit/SocketServiceProviderTest.php b/tests/unit/SocketServiceProviderTest.php
new file mode 100644
index 0000000..c03a9ba
--- /dev/null
+++ b/tests/unit/SocketServiceProviderTest.php
@@ -0,0 +1,23 @@
+register($container);
+
+ $this->assertSame(
+ $configFilePath,
+ $container['config.file'],
+ "SocketServiceProvider::register expected {$configFilePath} file, but got wrong"
+ );
+ }
+}
diff --git a/tests/unit/SocketTest.php b/tests/unit/SocketTest.php
deleted file mode 100755
index 65a3b85..0000000
--- a/tests/unit/SocketTest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-setCredentials(new SocketCredentials());
-
- $this->assertInstanceOf(
- \WebSocket\Credential\SocketCredentials::class,
- $socket->getCredentials()
- );
- }
-}
diff --git a/tests/unit/Types/SocketTypeFactoryTest.php b/tests/unit/Types/SocketTypeFactoryTest.php
new file mode 100644
index 0000000..010ea9f
--- /dev/null
+++ b/tests/unit/Types/SocketTypeFactoryTest.php
@@ -0,0 +1,25 @@
+getParser()->parse()['settings']);
+ $socketTypeFactory = new SocketTypeFactory($configuration);
+
+ // SocketTypeFactory::getSocket will always return SocketType instance
+ // that's because we have a null object which contain realize interface of
+ // SocketType. Even if we will pass wrong file will be returned null object
+ $this->assertInstanceOf(
+ SocketType::class,
+ $socketTypeFactory->getSocket('tcp')
+ );
+ }
+}
diff --git a/tests/unit/Types/TypeConfigurationTest.php b/tests/unit/Types/TypeConfigurationTest.php
new file mode 100644
index 0000000..4a42172
--- /dev/null
+++ b/tests/unit/Types/TypeConfigurationTest.php
@@ -0,0 +1,33 @@
+getParser()->parse()['settings']);
+ $configuration->configure();
+
+ $this->assertTrue(
+ $configuration->validateSettingsExistence('address'),
+ "TypeConfiguration::validateSettingExistence. Setting 'host' doesn't exists in settings list"
+ );
+ }
+
+ public function testGetConfigurationSettingReturnsSameString()
+ {
+ $factorySettings = new ConfigParsersFactory(dirname(__DIR__, 1) . '/fixtures/config_tcp.yaml');
+ $configuration = new TypeConfiguration($factorySettings->getParser()->parse()['settings']);
+ $configuration->configure();
+
+ $this->assertSame(
+ '127.0.0.1',
+ $configuration->getConfigurationSetting('address'),
+ "TypeConfiguration::getConfigurationSetting. Expected '127.0.0.1', but got not the same string"
+ );
+ }
+}
diff --git a/tests/unit/fixtures/config_tcp.json b/tests/unit/fixtures/config_tcp.json
new file mode 100644
index 0000000..152c6ea
--- /dev/null
+++ b/tests/unit/fixtures/config_tcp.json
@@ -0,0 +1,8 @@
+{
+ "settings": {
+ "socket_type": "tcp",
+ "content_length": "2048",
+ "address": "127.0.0.1",
+ "port": "8001"
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/fixtures/config_tcp.yaml b/tests/unit/fixtures/config_tcp.yaml
new file mode 100644
index 0000000..5f103e6
--- /dev/null
+++ b/tests/unit/fixtures/config_tcp.yaml
@@ -0,0 +1,5 @@
+settings:
+ socket_type: tcp
+ read_length: 2048
+ address: 127.0.0.1
+ port: 8000
\ No newline at end of file
diff --git a/tests/unit/fixtures/config_unix.json b/tests/unit/fixtures/config_unix.json
new file mode 100644
index 0000000..a643793
--- /dev/null
+++ b/tests/unit/fixtures/config_unix.json
@@ -0,0 +1,7 @@
+{
+ "settings": {
+ "socket_type": "tcp",
+ "content_length": "2048",
+ "address": "socket.sock"
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/fixtures/config_unix.yaml b/tests/unit/fixtures/config_unix.yaml
new file mode 100644
index 0000000..e0b4dc4
--- /dev/null
+++ b/tests/unit/fixtures/config_unix.yaml
@@ -0,0 +1,4 @@
+settings:
+ socket_type: tcp
+ read_length: 2048
+ address: socket.sock
\ No newline at end of file