Adding missing database for cache, missing file format and some image
logic.
This commit is contained in:
parent
ac40d32ef6
commit
3285ac3987
112
lib/Exd/DB.pm
Normal file
112
lib/Exd/DB.pm
Normal file
@ -0,0 +1,112 @@
|
||||
package Exd::DB;
|
||||
|
||||
use v5.40.0;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use DBI;
|
||||
use Path::Tiny;
|
||||
|
||||
use Exd::DB::Migrations;
|
||||
|
||||
my $dbh;
|
||||
|
||||
sub connect {
|
||||
if ( defined $dbh ) {
|
||||
return $dbh;
|
||||
}
|
||||
my $class = shift;
|
||||
my $database = $class->database;
|
||||
$dbh = DBI->connect(
|
||||
"dbi:SQLite:dbname=$database",
|
||||
,
|
||||
undef, undef,
|
||||
{
|
||||
RaiseError => 1,
|
||||
},
|
||||
);
|
||||
$class->_migrate($dbh);
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
sub database($class) {
|
||||
my $home = $ENV{HOME};
|
||||
my $flatpak_config_dir = $ENV{XDG_CONFIG_HOME};
|
||||
my $db_path = '';
|
||||
{
|
||||
if ($flatpak_config_dir) {
|
||||
$db_path = $flatpak_config_dir . '/';
|
||||
next;
|
||||
}
|
||||
$db_path = $home . '/' if $home;
|
||||
}
|
||||
$db_path .= '.exd/db.sqlite';
|
||||
path($db_path)->parent->mkpath;
|
||||
return $db_path;
|
||||
|
||||
}
|
||||
|
||||
sub _migrate {
|
||||
my $class = shift;
|
||||
my $dbh = shift;
|
||||
local $dbh->{RaiseError} = 0;
|
||||
local $dbh->{PrintError} = 0;
|
||||
my @migrations = Exd::DB::Migrations::MIGRATIONS();
|
||||
if ( $class->get_current_migration($dbh) > @migrations ) {
|
||||
warn "Something happened there, wrong migration number.";
|
||||
}
|
||||
if ( $class->get_current_migration($dbh) >= @migrations ) {
|
||||
say STDERR "Migrations already applied.";
|
||||
return;
|
||||
}
|
||||
$class->_apply_migrations( $dbh, \@migrations );
|
||||
}
|
||||
|
||||
sub _apply_migrations {
|
||||
my $class = shift;
|
||||
my $dbh = shift;
|
||||
my $migrations = shift;
|
||||
for (
|
||||
my $i = $class->get_current_migration($dbh) ;
|
||||
$i < @$migrations ;
|
||||
$i++
|
||||
)
|
||||
{
|
||||
local $dbh->{RaiseError} = 1;
|
||||
my $current_migration = $migrations->[$i];
|
||||
my $migration_number = $i + 1;
|
||||
$class->_apply_migration( $dbh, $current_migration, $migration_number );
|
||||
}
|
||||
}
|
||||
|
||||
sub _apply_migration {
|
||||
my $class = shift;
|
||||
my $dbh = shift;
|
||||
my $current_migration = shift;
|
||||
my $migration_number = shift;
|
||||
{
|
||||
if (ref $current_migration eq 'CODE') {
|
||||
$current_migration->($dbh);
|
||||
next;
|
||||
}
|
||||
$dbh->do($current_migration);
|
||||
}
|
||||
$dbh->do( <<'EOF', undef, 'current_migration', $migration_number );
|
||||
INSERT INTO options
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (name) DO
|
||||
UPDATE SET value = $2;
|
||||
EOF
|
||||
}
|
||||
|
||||
sub get_current_migration {
|
||||
my $class = shift;
|
||||
my $dbh = shift;
|
||||
my $result = $dbh->selectrow_hashref( <<'EOF', undef, 'current_migration' );
|
||||
select value from options where name = ?;
|
||||
EOF
|
||||
return int( $result->{value} // 0 );
|
||||
}
|
||||
1;
|
24
lib/Exd/DB/Migrations.pm
Normal file
24
lib/Exd/DB/Migrations.pm
Normal file
@ -0,0 +1,24 @@
|
||||
package Exd::DB::Migrations;
|
||||
|
||||
use v5.40.0;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use feature 'signatures';
|
||||
|
||||
sub MIGRATIONS {
|
||||
return (
|
||||
'CREATE TABLE options (
|
||||
name TEXT PRIMARY KEY,
|
||||
value TEXT
|
||||
);',
|
||||
'CREATE TABLE cached_bluetooth_printers (
|
||||
address TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
port INTEGER NOT NULL
|
||||
);',
|
||||
);
|
||||
}
|
||||
1;
|
83
lib/Exd/FileFormat.pm
Normal file
83
lib/Exd/FileFormat.pm
Normal file
@ -0,0 +1,83 @@
|
||||
package Exd::FileFormat;
|
||||
|
||||
use v5.40.0;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use Moo;
|
||||
use Path::Tiny;
|
||||
use Archive::Zip;
|
||||
|
||||
use Digest::SHA qw/sha256_hex/;
|
||||
|
||||
has dir => ( is => 'rw' );
|
||||
|
||||
sub new_tmp($class) {
|
||||
my $tempdir = Path::Tiny->tempdir();
|
||||
return $class->new( dir => $tempdir );
|
||||
}
|
||||
|
||||
has _images_dir => ( is => 'lazy' );
|
||||
|
||||
sub _build__images_dir($self) {
|
||||
my $dir = $self->dir;
|
||||
my $images = $dir->child('images');
|
||||
$images->mkpath;
|
||||
return $images;
|
||||
}
|
||||
|
||||
sub add_png_image( $self, $file_contents ) {
|
||||
my $sha_image = sha256_hex($file_contents);
|
||||
$self->_images_dir->child("$sha_image.png")->spew_raw($file_contents);
|
||||
}
|
||||
|
||||
sub get_image( $self, $sha ) {
|
||||
return $self->_images_dir->child("$sha.png");
|
||||
}
|
||||
|
||||
sub get_script($self) {
|
||||
return $self->dir->child('script.pl')->slurp_raw;
|
||||
}
|
||||
|
||||
sub set_script( $self, $script_contents ) {
|
||||
return $self->dir->child('script.pl')->spew_raw($script_contents);
|
||||
}
|
||||
|
||||
sub to_zip($self) {
|
||||
my $zip = Archive::Zip->new;
|
||||
$self->dir->visit(
|
||||
sub( $path, $state ) {
|
||||
return if $path->is_dir;
|
||||
my $path_relative = $path->relative( $self->dir );
|
||||
$zip->addFile( $path, $path_relative );
|
||||
},
|
||||
{ recurse => 1 }
|
||||
);
|
||||
return $zip;
|
||||
}
|
||||
|
||||
sub from_zip_file( $class, $zip_file ) {
|
||||
my $tempdir = Path::Tiny->tempdir();
|
||||
my $zip = Archive::Zip->new($zip_file);
|
||||
$zip->extractTree( '.', $tempdir );
|
||||
return $class->new( dir => $tempdir );
|
||||
}
|
||||
|
||||
sub execute( $self, $printer ) {
|
||||
my $script = $self->get_script;
|
||||
my $sub =
|
||||
eval
|
||||
'use v5.40.0; use strict; use warnings; use utf8; no Carp::Always; use Cairo; use Pango;'
|
||||
. $script;
|
||||
if ($@) {
|
||||
die $@;
|
||||
}
|
||||
$sub->($self, $printer);
|
||||
}
|
||||
|
||||
sub save( $self, $output_file ) {
|
||||
$self->to_zip->writeToFileNamed($output_file);
|
||||
}
|
||||
1;
|
@ -21,6 +21,7 @@ use Capture::Tiny qw/capture/;
|
||||
use Exd::Printer;
|
||||
use Exd::DeviceToBluetooth;
|
||||
use Exd::DeviceToImage;
|
||||
use Exd::FileFormat;
|
||||
use Exd::Gui::PrinterConfigure;
|
||||
|
||||
use JSON;
|
||||
@ -45,7 +46,7 @@ Glib::Object::Introspection->setup(
|
||||
|
||||
has _app => ( is => 'rw', );
|
||||
|
||||
has window => ( is => 'rw', );
|
||||
has window => ( is => 'rw', );
|
||||
has _scroll_log_upper => ( is => 'rw', );
|
||||
|
||||
has _execute_log => ( is => 'rw', );
|
||||
@ -60,7 +61,28 @@ has _read_from_script => ( is => 'rw' );
|
||||
has _read_from_parent => ( is => 'rw' );
|
||||
has _write_to_parent => ( is => 'rw' );
|
||||
has _write_to_script => ( is => 'rw' );
|
||||
has device => (is => 'rw');
|
||||
has device => ( is => 'rw' );
|
||||
has _file_format => (
|
||||
is => 'rw',
|
||||
default => sub {
|
||||
my $tmp = Exd::FileFormat->new_tmp;
|
||||
say $tmp->dir;
|
||||
$tmp->set_script(<<'EOF');
|
||||
sub ($exd, $printer) {
|
||||
$printer->print_text(
|
||||
[
|
||||
'hola mundo'
|
||||
],
|
||||
30
|
||||
);
|
||||
$printer->print_n_lf(2);
|
||||
|
||||
$printer->print;
|
||||
}
|
||||
EOF
|
||||
return $tmp;
|
||||
}
|
||||
);
|
||||
|
||||
sub _tempdir_previews($self) {
|
||||
if ( !defined $self->_tempdir_previews_guts ) {
|
||||
@ -115,7 +137,7 @@ sub _run_script( $self, $device = undef, $verbose = 1 ) {
|
||||
my $fh = $self->_write_to_script;
|
||||
print $fh JSON::to_json(
|
||||
{
|
||||
script => $script,
|
||||
exd_dir => ''.$self->_file_format->dir,
|
||||
device => $device->serialize,
|
||||
verbose => $verbose,
|
||||
}
|
||||
@ -144,8 +166,8 @@ sub _daemon_script_runner($self) {
|
||||
my $fh = $self->_read_from_parent;
|
||||
my $line = <$fh>;
|
||||
my $data = JSON::from_json($line);
|
||||
my ( $script, $device, $verbose ) =
|
||||
$data->@{ 'script', 'device', 'verbose' };
|
||||
my ( $exd_dir, $device, $verbose ) =
|
||||
$data->@{ 'exd_dir', 'device', 'verbose' };
|
||||
$device = $self->device_hash_to_object($device);
|
||||
if ( $last_pid
|
||||
&& $last_device->isa('Exd::DeviceToImage')
|
||||
@ -157,7 +179,7 @@ sub _daemon_script_runner($self) {
|
||||
my $new_pid = fork;
|
||||
if ( !$new_pid ) {
|
||||
eval {
|
||||
$self->_on_run_script( $script, $device, $write_to_parent,
|
||||
$self->_on_run_script( path($exd_dir), $device, $write_to_parent,
|
||||
$verbose );
|
||||
};
|
||||
if ($@) {
|
||||
@ -193,20 +215,15 @@ sub device_hash_to_object( $self, $device_hash ) {
|
||||
return $sub->();
|
||||
}
|
||||
|
||||
sub _on_run_script( $self, $script, $device, $write_to_parent, $verbose = 1 ) {
|
||||
sub _on_run_script( $self, $exd_dir, $device, $write_to_parent, $verbose = 1 ) {
|
||||
my $printer = Exd::Printer->new( device => $device );
|
||||
local $| = 1;
|
||||
|
||||
my $exd = Exd::FileFormat->new(dir => $exd_dir);
|
||||
|
||||
my ( $stdout, $stderr, $exit ) = capture {
|
||||
eval {
|
||||
my $sub =
|
||||
eval
|
||||
'use v5.40.0; use strict; use warnings; use utf8; no Carp::Always; use Cairo; use Pango;'
|
||||
. $script;
|
||||
if ($@) {
|
||||
die $@;
|
||||
}
|
||||
$sub->($printer);
|
||||
$exd->execute($printer);
|
||||
};
|
||||
if ($@) {
|
||||
if ($verbose) {
|
||||
@ -227,8 +244,8 @@ sub _monitor_run($self) {
|
||||
for my $fh (@fhs) {
|
||||
$fh->blocking(0);
|
||||
my $text = '';
|
||||
while (my $line = <$fh>) {
|
||||
if (!defined $line) {
|
||||
while ( my $line = <$fh> ) {
|
||||
if ( !defined $line ) {
|
||||
next;
|
||||
}
|
||||
$text .= $line;
|
||||
@ -238,12 +255,12 @@ sub _monitor_run($self) {
|
||||
}
|
||||
}
|
||||
|
||||
sub add_to_log($self, $text) {
|
||||
my $execute_log = $self->_execute_log;
|
||||
my $buffer = $execute_log->get_buffer;
|
||||
my $end_iter = $buffer->get_end_iter;
|
||||
sub add_to_log( $self, $text ) {
|
||||
my $execute_log = $self->_execute_log;
|
||||
my $buffer = $execute_log->get_buffer;
|
||||
my $end_iter = $buffer->get_end_iter;
|
||||
|
||||
$buffer->insert( $end_iter, $text, -1 );
|
||||
$buffer->insert( $end_iter, $text, -1 );
|
||||
}
|
||||
|
||||
sub _build__select($self) {
|
||||
@ -262,8 +279,8 @@ sub _on_preview($self) {
|
||||
}
|
||||
}
|
||||
|
||||
sub _populate_editor($self, $box_editor_preview) {
|
||||
my $editor = Gtk4::Source::View->new;
|
||||
sub _populate_editor( $self, $box_editor_preview ) {
|
||||
my $editor = Gtk4::Source::View->new;
|
||||
$self->_editor($editor);
|
||||
$editor->set_hexpand(1);
|
||||
$editor->set_vexpand(1);
|
||||
@ -274,25 +291,19 @@ sub _populate_editor($self, $box_editor_preview) {
|
||||
$editor->set_smart_backspace(1);
|
||||
$editor->set_show_line_numbers(1);
|
||||
my $buffer = $editor->get_buffer();
|
||||
$buffer->set_text( <<'EOF', -1 );
|
||||
sub ($printer) {
|
||||
$printer->print_text(
|
||||
[
|
||||
'hola mundo'
|
||||
],
|
||||
30
|
||||
);
|
||||
$printer->print_n_lf(2);
|
||||
|
||||
$printer->print;
|
||||
}
|
||||
EOF
|
||||
$buffer->set_text( $self->_file_format->get_script, -1 );
|
||||
$buffer->set_language(
|
||||
Gtk4::Source::LanguageManager::get_default()->get_language('perl') );
|
||||
$buffer->set_highlight_syntax(1);
|
||||
$buffer->signal_connect(
|
||||
'changed',
|
||||
sub {
|
||||
my $buffer = $self->_editor->get_buffer;
|
||||
my $begin_iter = $buffer->get_iter_at_offset(0);
|
||||
my $end_iter = $buffer->get_end_iter;
|
||||
my $script = $buffer->get_text( $begin_iter, $end_iter, 0 );
|
||||
|
||||
$self->_file_format->set_script($script);
|
||||
$self->_generate_preview_file(0);
|
||||
}
|
||||
);
|
||||
@ -302,7 +313,7 @@ EOF
|
||||
$box_editor_preview->append($editor_scroll_window);
|
||||
}
|
||||
|
||||
sub _populate_editor_and_preview($self, $box_vertical) {
|
||||
sub _populate_editor_and_preview( $self, $box_vertical ) {
|
||||
my $box_editor_preview = Gtk4::Box->new( 'horizontal', 10 );
|
||||
$self->_populate_editor($box_editor_preview);
|
||||
$self->_populate_preview($box_editor_preview);
|
||||
@ -316,8 +327,8 @@ sub _populate_editor_and_preview($self, $box_vertical) {
|
||||
);
|
||||
}
|
||||
|
||||
sub _populate_preview($self, $box_editor_preview) {
|
||||
my $preview_picture = Gtk4::Picture->new;
|
||||
sub _populate_preview( $self, $box_editor_preview ) {
|
||||
my $preview_picture = Gtk4::Picture->new;
|
||||
$self->_preview_widget($preview_picture);
|
||||
my $preview_scroll_window = Gtk4::ScrolledWindow->new;
|
||||
$preview_scroll_window->set_child($preview_picture);
|
||||
@ -345,7 +356,7 @@ sub _activate($self) {
|
||||
$select_printer->signal_connect(
|
||||
'clicked',
|
||||
sub {
|
||||
Exd::Gui::PrinterConfigure->new(app => $self)->start;
|
||||
Exd::Gui::PrinterConfigure->new( app => $self )->start;
|
||||
}
|
||||
);
|
||||
$preview_button->signal_connect(
|
||||
@ -381,8 +392,8 @@ sub _activate($self) {
|
||||
$box_vertical->append($box_buttons);
|
||||
my $execute_log_window = Gtk4::ScrolledWindow->new;
|
||||
$execute_log_window->set_vexpand(0);
|
||||
$execute_log_window->set_property('height-request', 300);
|
||||
my $scroll = $execute_log_window->get_vadjustment;
|
||||
$execute_log_window->set_property( 'height-request', 300 );
|
||||
my $scroll = $execute_log_window->get_vadjustment;
|
||||
$self->_scroll_log_upper( $scroll->get_upper );
|
||||
$scroll->signal_connect(
|
||||
'changed',
|
||||
|
Loading…
Reference in New Issue
Block a user