Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cups #92

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

Cups #92

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
6 changes: 1 addition & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,8 @@
"php-http/message-factory": "^1.1",
"psr/http-message": "1.*",
"psr/http-client": "^1.0",
"smalot/cups-ipp": "^0.5.0",
"spatie/laravel-ray": "^1.0|^1.29"
},
"suggest": {
"smalot/cups-ipp": "Required when using the CUPS driver"
},
"autoload": {
"psr-4": {
"Rawilk\\Printing\\": "src"
Expand Down Expand Up @@ -79,4 +75,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
}
}
1 change: 1 addition & 0 deletions config/printing.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
'username' => env('CUPS_SERVER_USERNAME'),
'password' => env('CUPS_SERVER_PASSWORD'),
'port' => env('CUPS_SERVER_PORT', 631),
'secure' => env('CUPS_SERVER_SECURE', false),
],

/*
Expand Down
90 changes: 90 additions & 0 deletions src/Api/Cups/AttributeGroup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups;

use Rawilk\Printing\Api\Cups\Exceptions\TypeNotSpecified;

abstract class AttributeGroup
{
/**
* Every attribute group has a specific delimiter tag
*
* @see https://www.rfc-editor.org/rfc/rfc2910#section-3.5
*/
protected int $tag;

/**
* @var array<string, \Rawilk\Printing\Api\Cups\Type|array<int, \Rawilk\Printing\Api\Cups\Type>>
*/
protected array $attributes = [];

public function __set($name, $value)
{
$this->attributes[$name] = $value;
}

public function __construct(array $attributes = [])
{
$this->attributes = $attributes;
}

/**
* @var array<string, \Rawilk\Printing\Api\Cups\Type|array<int, \Rawilk\Printing\Api\Cups\Type>>
*/
public function getAttributes()
{
return $this->attributes;
}

public function encode(): string
{
$binary = pack('c', $this->tag);
foreach ($this->attributes as $name => $value) {
if (gettype($value) === 'array') {
$binary .= $this->handleArrayEncode($name, $value);
continue;
}
if (!$value instanceof Type) {
throw new TypeNotSpecified('Attribute value has to be of type ' . Type::class);
}

$nameLen = strlen($name);
$binary .= pack('c', $value->getTag());

$binary .= pack('n', $nameLen); // Attribute key length
$binary .= pack('a' . $nameLen, $name); // Attribute key

$binary .= $value->encode(); // Attribute value (with length)
}
return $binary;
}

/**
* If attribute is an array, the attribute name after the first element is empty
* @param string $name
* @param array<int, \Rawilk\Printing\Api\Cups\Type> $values
*/
private function handleArrayEncode(string $name, array $values): string
{
$str = '';
if ($values[0] instanceof \Rawilk\Printing\Api\Cups\Types\RangeOfInteger) {
\Rawilk\Printing\Api\Cups\Types\RangeOfInteger::checkOverlaps($values);
}
for ($i = 0; $i < sizeof($values); $i++) {
$_name = $name;
if ($i !== 0) {
$_name = '';
}
$nameLen = strlen($_name);

$str .= pack('c', $values[$i]->getTag()); // Value tag
$str .= pack('n', $nameLen); // Attribute key length
$str .= pack('a' . $nameLen, $_name); // Attribute key

$str .= $values[$i]->encode();
}
return $str;
}
}
30 changes: 30 additions & 0 deletions src/Api/Cups/AttributeGroupTag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups;

use Rawilk\Printing\Api\Cups\Attributes\JobGroup;
use Rawilk\Printing\Api\Cups\Attributes\OperationGroup;
use Rawilk\Printing\Api\Cups\Attributes\PrinterGroup;
use Rawilk\Printing\Api\Cups\Attributes\UnsupportedGroup;

enum AttributeGroupTag: int
{
case RESERVED = 0x00;
case OPERATION_ATTRIBUTES = 0x01;
case JOB_ATTRIBUTES = 0x02;
case END_OF_ATTRIBUTES = 0x03;
case PRINTER_ATTRIBUTES = 0x04;
case UNSUPPORTED_ATTRIBUTES = 0x05;

public static function getGroupClassByTag(int $tag): string
{
return match ($tag) {
AttributeGroupTag::JOB_ATTRIBUTES->value => JobGroup::class,
AttributeGroupTag::OPERATION_ATTRIBUTES->value => OperationGroup::class,
AttributeGroupTag::PRINTER_ATTRIBUTES->value => PrinterGroup::class,
AttributeGroupTag::UNSUPPORTED_ATTRIBUTES->value => UnsupportedGroup::class,
};
}
}
13 changes: 13 additions & 0 deletions src/Api/Cups/Attributes/JobGroup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups\Attributes;

use Rawilk\Printing\Api\Cups\AttributeGroup;
use Rawilk\Printing\Api\Cups\AttributeGroupTag;

class JobGroup extends AttributeGroup
{
protected int $tag = AttributeGroupTag::JOB_ATTRIBUTES->value;
}
13 changes: 13 additions & 0 deletions src/Api/Cups/Attributes/OperationGroup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups\Attributes;

use Rawilk\Printing\Api\Cups\AttributeGroup;
use Rawilk\Printing\Api\Cups\AttributeGroupTag;

class OperationGroup extends AttributeGroup
{
protected int $tag = AttributeGroupTag::OPERATION_ATTRIBUTES->value;
}
13 changes: 13 additions & 0 deletions src/Api/Cups/Attributes/PrinterGroup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups\Attributes;

use Rawilk\Printing\Api\Cups\AttributeGroup;
use Rawilk\Printing\Api\Cups\AttributeGroupTag;

class PrinterGroup extends AttributeGroup
{
protected int $tag = AttributeGroupTag::PRINTER_ATTRIBUTES->value;
}
13 changes: 13 additions & 0 deletions src/Api/Cups/Attributes/UnsupportedGroup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups\Attributes;

use Rawilk\Printing\Api\Cups\AttributeGroup;
use Rawilk\Printing\Api\Cups\AttributeGroupTag;

class UnsupportedGroup extends AttributeGroup
{
protected int $tag = AttributeGroupTag::UNSUPPORTED_ATTRIBUTES->value;
}
49 changes: 49 additions & 0 deletions src/Api/Cups/Cups.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups;

use Illuminate\Support\Facades\Http;

class Cups
{
public function __construct(
private string $ip,
private ?string $username,
private ?string $password,
private int $port = 631,
private bool $secure = false
) {
}

/**
* @throws Illuminate\Http\Client\ConnectionException
* @throws Illuminate\Http\Client\RequestException
* @throws \Rawilk\Printing\Api\Cups\Exceptions\ClientException
* @throws \Rawilk\Printing\Api\Cups\Exceptions\ServerException
*/
public function makeRequest(Request $request): Response
{
$http = Http::withBody($request->encode());

if ($this->username || $this->password) {
$http->withBasicAuth($this->username, $this->password);
}

$http = $http->withHeaders(
[
"Content-Type" => "application/ipp"
]
)->post($this->getScheme() . '://' . $this->ip . ':' . $this->port . '/admin')
->throwIfClientError();
$response = new Response($http->body());

return $response;
}

private function getScheme()
{
return $this->secure ? 'https' : 'http';
}
}
15 changes: 15 additions & 0 deletions src/Api/Cups/Exceptions/ClientError.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups\Exceptions;

use Exception;

class ClientError extends Exception
{
public static function invalid(string $message): self
{
return new static($message);
}
}
15 changes: 15 additions & 0 deletions src/Api/Cups/Exceptions/RangeOverlap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups\Exceptions;

use Exception;

class RangeOverlap extends Exception
{
public static function invalid(string $message): self
{
return new static($message);
}
}
15 changes: 15 additions & 0 deletions src/Api/Cups/Exceptions/ServerError.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups\Exceptions;

use Exception;

class ServerError extends Exception
{
public static function invalid(string $message): self
{
return new static($message);
}
}
15 changes: 15 additions & 0 deletions src/Api/Cups/Exceptions/TypeNotSpecified.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups\Exceptions;

use Exception;

class TypeNotSpecified extends Exception
{
public static function invalid(string $message): self
{
return new static($message);
}
}
15 changes: 15 additions & 0 deletions src/Api/Cups/Exceptions/UnknownEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups\Exceptions;

use Exception;

class UnknownEnum extends Exception
{
public static function invalid(string $message): self
{
return new static($message);
}
}
15 changes: 15 additions & 0 deletions src/Api/Cups/Exceptions/UnknownType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Rawilk\Printing\Api\Cups\Exceptions;

use Exception;

class UnknownType extends Exception
{
public static function invalid(string $message): self
{
return new static($message);
}
}
Loading