Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
},
"autoload-dev": {
"psr-4": {
"Litebase\\Tests\\": "tests"
"Tests\\": "tests"
}
},
"config": {
Expand Down
2 changes: 2 additions & 0 deletions src/ApiClient.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Litebase;

use GuzzleHttp\Client;
Expand Down
4 changes: 3 additions & 1 deletion src/ChunkedSignatureSigner.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Litebase;

/**
Expand Down Expand Up @@ -44,7 +46,7 @@ public function signChunk(string $chunkData): string

// Create the string to sign for this chunk
// Format: previousSignature + chunkHash
$stringToSign = $this->previousSignature.$chunkHash;
$stringToSign = $this->previousSignature . $chunkHash;

// Create the signing key chain (same as in request signature validation)
$dateKey = hash_hmac('sha256', $this->date, $this->accessKeySecret ?? '');
Expand Down
2 changes: 2 additions & 0 deletions src/ColumnType.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Litebase;

enum ColumnType: int
Expand Down
2 changes: 2 additions & 0 deletions src/ColumnTypeString.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Litebase;

enum ColumnTypeString: string
Expand Down
77 changes: 67 additions & 10 deletions src/Configuration.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<?php

declare(strict_types=1);

namespace Litebase;

use Litebase\OpenAPI\Configuration as BaseConfiguration;

/**
* Extended configuration class with HMAC-SHA256 authentication support
* Extended configuration class with HMAC-SHA256 authentication support.
*/
class Configuration extends BaseConfiguration
{
Expand All @@ -19,56 +21,101 @@ class Configuration extends BaseConfiguration

protected ?string $port = null;

protected ?string $transport = null;

/**
* Create a new Configuration instance from an array of settings.
*
* @param array<string, string|null> $config
*/
public static function create(array $config = []): self
{
$configuration = new self();

$host = $config['host'] ?? '';
$port = $config['port'] ?? null;
$database = $config['database'] ?? null;
$configuration->transport = $config['transport'] ?? 'http';

$configuration
->setHost($host)
->setPort($port)
->setDatabase($database);

if (isset($config['access_key_id'], $config['access_key_secret'])) {
$configuration->setAccessKey($config['access_key_id'], $config['access_key_secret']);
}

if (isset($config['token'])) {
$configuration->setAccessToken($config['token']);
}

if (isset($config['username'], $config['password'])) {
$configuration->setUsername($config['username'])
->setPassword($config['password']);
}

return $configuration;
}

/**
* Get the access key ID
* Get the access key ID.
*/
public function getAccessKeyId(): string
{
return $this->accessKeyId ?? '';
}

/**
* Get the access key secret
* Get the access key secret.
*/
public function getAccessKeySecret(): string
{
return $this->accessKeySecret ?? '';
}

/**
* Get the database name
* Get the database name.
*/
public function getDatabase(): ?string
{
return $this->database;
}

/**
* Get the branch name
* Get the branch name.
*/
public function getBranch(): ?string
{
return $this->branch;
}

/**
* Check if access key authentication is configured
* Check if access key authentication is configured.
*/
public function hasAccessKey(): bool
{
return ! empty($this->accessKeyId) && ! empty($this->accessKeySecret);
}

/**
* Get the port
* Get the port.
*/
public function getPort(): ?string
{
return $this->port;
}

/**
* Set access key credentials for HMAC-SHA256 authentication
* Get the transport type.
*/
public function getTransport(): ?string
{
return $this->transport;
}

/**
* Set access key credentials for HMAC-SHA256 authentication.
*/
public function setAccessKey(?string $accessKeyId, ?string $accessKeySecret): self
{
Expand All @@ -79,7 +126,7 @@ public function setAccessKey(?string $accessKeyId, ?string $accessKeySecret): se
}

/**
* Set the database name (and optional branch) in the format "database/branch"
* Set the database name (and optional branch) in the format "database/branch".
*/
public function setDatabase(?string $database): self
{
Expand All @@ -91,12 +138,22 @@ public function setDatabase(?string $database): self
}

/**
* Set the port
* Set the port.
*/
public function setPort(?string $port): self
{
$this->port = $port;

return $this;
}

/**
* Set the transport type.
*/
public function setTransport(?string $transport): self
{
$this->transport = $transport;

return $this;
}
}
24 changes: 13 additions & 11 deletions src/Connection.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Litebase;

use Exception;
Expand Down Expand Up @@ -361,7 +363,7 @@ public function open(): void
stream_set_timeout($this->socket, 5);

$error = fwrite($this->socket, "POST {$this->path} HTTP/1.1\r\n");
$error = fwrite($this->socket, implode("\r\n", $this->headers)."\r\n");
$error = fwrite($this->socket, implode("\r\n", $this->headers) . "\r\n");
$error = fwrite($this->socket, "\r\n");

if ($error === false) {
Expand All @@ -371,7 +373,7 @@ public function open(): void
$this->open = true;

$this->messages = [
pack('C', QueryStreamMessageType::OPEN_CONNECTION->value.pack('V', 0)),
pack('C', QueryStreamMessageType::OPEN_CONNECTION->value . pack('V', 0)),
...$this->messages,
];

Expand All @@ -388,7 +390,7 @@ public function send(Query $query): QueryResult
// If chunked signer is available, create a signed frame per LQTP protocol
if ($this->chunkedSigner !== null) {
// Frame data: [QueryLength:4][QueryData]
$frameData = pack('V', strlen($queryRequest)).$queryRequest;
$frameData = pack('V', strlen($queryRequest)) . $queryRequest;

// Sign the frame data using chunked signature scheme (similar to AWS Sig4)
$chunkSignature = $this->chunkedSigner->signChunk($frameData);
Expand All @@ -399,13 +401,13 @@ public function send(Query $query): QueryResult
$totalLength = 4 + strlen($signatureBytes) + strlen($frameData);

$frame = pack('C', QueryStreamMessageType::FRAME->value) // Message type (0x04)
.pack('V', $totalLength) // Total length (signature metadata + frame data)
.pack('V', strlen($signatureBytes)) // Signature length
.$signatureBytes // Hex-encoded chunk signature
.$frameData; // Frame data
. pack('V', $totalLength) // Total length (signature metadata + frame data)
. pack('V', strlen($signatureBytes)) // Signature length
. $signatureBytes // Hex-encoded chunk signature
. $frameData; // Frame data
} else {
// Fallback to unsigned frame format (deprecated)
$frame = pack('C', QueryStreamMessageType::FRAME->value).pack('V', strlen($queryRequest)).$queryRequest;
$frame = pack('C', QueryStreamMessageType::FRAME->value) . pack('V', strlen($queryRequest)) . $queryRequest;
}

$this->messages[] = $frame;
Expand Down Expand Up @@ -435,7 +437,7 @@ public function send(Query $query): QueryResult

continue;
} catch (Exception $reconnectException) {
throw new Exception('[Litebase Client Error]: Failed to reconnect after connection loss: '.$reconnectException->getMessage());
throw new Exception('[Litebase Client Error]: Failed to reconnect after connection loss: ' . $reconnectException->getMessage());
}
}
}
Expand Down Expand Up @@ -522,7 +524,7 @@ public function send(Query $query): QueryResult
/** @var array<int, array<int, bool|float|int|string|null>> $rows */
$rows = isset($response['rows']) && is_array($response['rows']) ? $response['rows'] : [];

$transactionIDValue = $response['transactionID'] ?? '';
$transactionIDValue = $response['transactionId'] ?? '';
$transactionID = is_scalar($transactionIDValue) ? (string) $transactionIDValue : '';

$errorMessageValue = $response['errorMessage'] ?? null;
Expand Down Expand Up @@ -590,7 +592,7 @@ protected function writeMessage(string $message): void
$chunkSize = dechex(strlen($message));

$n = $this->socket ?
fwrite($this->socket, $chunkSize."\r\n".$message."\r\n") :
fwrite($this->socket, $chunkSize . "\r\n" . $message . "\r\n") :
false;

if ($n === false) {
Expand Down
8 changes: 4 additions & 4 deletions src/HasRequestHeaders.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Litebase;

trait HasRequestHeaders
Expand All @@ -11,10 +13,8 @@ trait HasRequestHeaders
protected function requestHeaders(string $host, ?string $port, int $contentLength, array $headers = []): array
{
// Include port if non standard port is used
if ($port !== null && ! in_array($port, [80, 443])) {
$host = sprintf('%s:%d', $host, $port);
} else {
$host = $host;
if ($port !== null && ! in_array($port, ['80', '443'], true)) {
$host = sprintf('%s:%s', $host, $port);
}

return [
Expand Down
2 changes: 2 additions & 0 deletions src/HttpStreamingTransport.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Litebase;

use Exception;
Expand Down
6 changes: 4 additions & 2 deletions src/HttpTransport.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Litebase;

use GuzzleHttp\Client;
Expand Down Expand Up @@ -50,13 +52,13 @@ public function send(Query $query): ?QueryResult

/** @var array<int, array<int, bool|float|int|string|null>> $rows */
$rows = array_values(array_map(
fn ($row) => is_array($row) ? array_values($row) : (array) $row,
fn($row) => is_array($row) ? array_values($row) : (array) $row,
$firstResult->getRows() ?? []
));

return new QueryResult(
changes: $firstResult->getChanges() ?? 0,
columns: array_values(array_map(fn ($col) => [
columns: array_values(array_map(fn($col) => [
'type' => ColumnType::from($col->getType() ?? 1),
'name' => $col->getName() ?? '',
], $firstResult->getColumns() ?? [])),
Expand Down
Loading