From 9e3bbcd38f109759882c07c2edce83cae8ff8064 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Thu, 5 Jan 2023 19:51:29 +0100 Subject: [PATCH 1/2] first rewrite part --- FHEM/98_backupToStorage.pm | 6 +- controls_backupToStorage.txt | 4 +- lib/FHEM/Services/backupToStorage.pm | 512 +++++++++++++-------------- 3 files changed, 252 insertions(+), 270 deletions(-) diff --git a/FHEM/98_backupToStorage.pm b/FHEM/98_backupToStorage.pm index 7e549c5..28e6788 100644 --- a/FHEM/98_backupToStorage.pm +++ b/FHEM/98_backupToStorage.pm @@ -2,7 +2,7 @@ # # Developed with Kate # -# (c) 2020-2021 Copyright: Marko Oldenburg (fhemdevelopment@cooltux.net) +# (c) 2020-2021 Copyright: Marko Oldenburg (fhemdevelopment@cooltux.net) # All rights reserved # # Special thanks goes to: @@ -181,9 +181,9 @@ sub backupToStorage_Initialize { ], "release_status": "devepolment", "license": "GPL_2", - "version": "v1.3.1", + "version": "v1.4.0", "author": [ - "Marko Oldenburg " + "Marko Oldenburg " ], "x_fhem_maintainer": [ "CoolTux" diff --git a/controls_backupToStorage.txt b/controls_backupToStorage.txt index 2ea40b8..54c8724 100644 --- a/controls_backupToStorage.txt +++ b/controls_backupToStorage.txt @@ -1,2 +1,2 @@ -UPD 2021-11-09_13:08:21 6508 FHEM/98_backupToStorage.pm -UPD 2021-11-09_13:55:09 24286 lib/FHEM/Services/backupToStorage.pm +UPD 2022-03-10_06:48:27 6511 FHEM/98_backupToStorage.pm +UPD 2022-03-10_08:41:03 23352 lib/FHEM/Services/backupToStorage.pm diff --git a/lib/FHEM/Services/backupToStorage.pm b/lib/FHEM/Services/backupToStorage.pm index 8b8c746..b8eca3e 100644 --- a/lib/FHEM/Services/backupToStorage.pm +++ b/lib/FHEM/Services/backupToStorage.pm @@ -1,8 +1,8 @@ ############################################################################### # -# Developed with Kate +# Developed with VSCodium and richterger perl plugin # -# (c) 2020-2021 Copyright: Marko Oldenburg (fhemdevelopment@cooltux.net) +# (c) 2020-2022 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) # All rights reserved # # Special thanks goes to: @@ -37,7 +37,15 @@ use utf8; use GPUtils qw(GP_Import); -use Data::Dumper; #only for Debugging +BEGIN { + + # Import from main context + GP_Import( + qw( init_done + defs + ) + ); +} # try to use JSON::MaybeXS wrapper # for chance of better performance + open code @@ -45,15 +53,11 @@ eval { require JSON::MaybeXS; import JSON::MaybeXS qw( decode_json encode_json ); 1; -}; - -if ($@) { - $@ = undef; +} or do { # try to use JSON wrapper # for chance of better performance eval { - # JSON preference order local $ENV{PERL_JSON_BACKEND} = 'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP' @@ -62,10 +66,7 @@ if ($@) { require JSON; import JSON qw( decode_json encode_json ); 1; - }; - - if ($@) { - $@ = undef; + } or do { # In rare cases, Cpanel::JSON::XS may # be installed but JSON|JSON::MaybeXS not ... @@ -73,10 +74,7 @@ if ($@) { require Cpanel::JSON::XS; import Cpanel::JSON::XS qw(decode_json encode_json); 1; - }; - - if ($@) { - $@ = undef; + } or do { # In rare cases, JSON::XS may # be installed but JSON not ... @@ -84,10 +82,7 @@ if ($@) { require JSON::XS; import JSON::XS qw(decode_json encode_json); 1; - }; - - if ($@) { - $@ = undef; + } or do { # Fallback to built-in JSON which SHOULD # be available since 5.014 ... @@ -95,73 +90,41 @@ if ($@) { require JSON::PP; import JSON::PP qw(decode_json encode_json); 1; - }; - - if ($@) { - $@ = undef; + } or do { # Fallback to JSON::backportPP in really rare cases require JSON::backportPP; import JSON::backportPP qw(decode_json encode_json); 1; - } - } - } - } -} - -## Import der FHEM Funktionen -#-- Run before package compilation -BEGIN { - - # Import from main context - GP_Import( - qw( - readingsSingleUpdate - readingsBulkUpdate - readingsBeginUpdate - readingsEndUpdate - ReadingsVal - ReadingsAge - gettimeofday - InternalTimer - defs - modules - IsDisabled - setKeyValue - getKeyValue - getUniqueId - Log3 - CommandAttr - attr - AttrVal - deviceEvents - init_done - devspec2array - DoTrigger - HttpUtils_NonblockingGet) - ); -} + }; + }; + }; + }; +}; sub Define { + use version 0.60; + my $hash = shift // return; my $aArg = shift // return; return $@ unless ( FHEM::Meta::SetInternals($hash) ); - use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); + + $version = FHEM::Meta::Get( $hash, 'version' ); + our $VERSION = $version; return q{only one backupToStorage instance allowed} - if ( devspec2array('TYPE=backupToStorage') > 1 ) + if ( ::devspec2array('TYPE=backupToStorage') > 1 ) ; # es wird geprüft ob bereits eine Instanz unseres Modules existiert,wenn ja wird abgebrochen return q{too few parameters: define backupToStorage} if ( scalar( @{$aArg} ) != 2 ); my $name = shift @$aArg; - $hash->{VERSION} = version->parse($VERSION)->normal; - $hash->{NOTIFYDEV} = 'global,' . $name; - $hash->{STORAGETYPE} = AttrVal( $name, 'bTS_Type', 'Nextcloud' ); + $hash->{VERSION} = version->parse($VERSION)->normal; + $hash->{NOTIFYDEV} = 'global,' . $name; + $hash->{STORAGETYPE} = ::AttrVal( $name, 'bTS_Type', 'Nextcloud' ); - Log3( $name, 3, qq{backupToStorage ($name) - defined} ); + ::Log3( $name, 3, qq{backupToStorage ($name) - defined} ); return; } @@ -170,7 +133,7 @@ sub Undef { my $hash = shift; my $name = shift; - Log3( $name, 3, q{qbackupToStorage ($name) - delete device $name} ); + ::Log3( $name, 3, q{qbackupToStorage ($name) - delete device $name} ); return; } @@ -180,7 +143,7 @@ sub Delete { my $name = shift; HttpUtils_Close( $hash->{helper}->{HttpUtilsParam} ) - if ( defined($hash->{helper}->{HttpUtilsParam}) ); + if ( defined( $hash->{helper}->{HttpUtilsParam} ) ); DeletePassword($hash); return; @@ -190,7 +153,7 @@ sub Shutdown { my $hash = shift; HttpUtils_Close( $hash->{helper}->{HttpUtilsParam} ) - if ( defined($hash->{helper}->{HttpUtilsParam}) ); + if ( defined( $hash->{helper}->{HttpUtilsParam} ) ); return; } @@ -202,35 +165,31 @@ sub Notify { my $name = $hash->{NAME}; my $devname = $dev->{NAME}; my $devtype = $dev->{TYPE}; - my $events = deviceEvents( $dev, 1 ); - + my $events = ::deviceEvents( $dev, 1 ); + _CheckIsDisabledAfterSetAttr($hash) - if ( ( - ( - grep m{^DELETEATTR.$name.(disable|disabledForIntervals)$}xms, - @{$events} - or grep m{^ATTR.$name.(disable|disabledForIntervals).\S+$}xms, - @{$events} - ) - && $devname eq 'global' - && $init_done + if ( + ( + ( + grep { /^DELETEATTR.$name.(disable|disabledForIntervals)$/x } + @{$events} + or grep { /^ATTR.$name.(disable|disabledForIntervals).\S+$/x } + @{$events} ) - || $devname eq $name - ); + && $devname eq 'global' + && $init_done + ) + || $devname eq $name + ); - return if ( !$events - || IsDisabled($name) ); + return if ( !$events + || ::IsDisabled($name) ); - - Log3( $name, 4, - qq{backupToStorage ($name) - - Devname: $devname - Name: $name - Notify: } . Dumper $events - ); # mit Dumper + ::Log3( $name, 4, + qq{backupToStorage ($name) - Devname: $devname Name: $name Notify: } ); PushToStorage($hash) - if ( ( grep m{^backup.done(.+)?$}xms, @{$events} ) + if ( ( grep { /^backup.done(.+)?$/x } @{$events} ) && $devname eq 'global' && $init_done ); @@ -239,16 +198,16 @@ sub Notify { ( ( ( - grep m{^DELETEATTR.$name.(bTS_Host|bTS_User)$}xms, + grep { /^DELETEATTR.$name.(bTS_Host|bTS_User)$/x } @{$events} - or grep m{^ATTR.$name.(bTS_Host|bTS_User).\S+$}xms, + or grep { /^ATTR.$name.(bTS_Host|bTS_User).\S+$/x } @{$events} ) && $devname eq 'global' ) || ( ( - $devname eq $name && grep m{^password.(add|remove)$}xms, + $devname eq $name && grep { /^password.(add|remove)$/x } @{$events} ) ) @@ -260,8 +219,8 @@ sub Notify { $hash, 'state', ( ( - AttrVal( $name, 'bTS_Host', 'none' ) eq 'none' - || AttrVal( $name, 'bTS_User', 'none' ) eq 'none' + ::AttrVal( $name, 'bTS_Host', 'none' ) eq 'none' + || ::AttrVal( $name, 'bTS_User', 'none' ) eq 'none' || !defined( ReadPassword( $hash, $name ) ) ) ? 'please set storage account credentials first' @@ -271,16 +230,13 @@ sub Notify { ) if ( ( - ( grep m{^DEFINED.$name$}xms, @{$events} ) + ( grep { /^DEFINED.$name$/x } @{$events} ) && $devname eq 'global' && $init_done ) - || ( - grep m{^INITIALIZED$}xms, - @{$events} or grep m{^REREADCFG$}xms, - @{$events} or grep m{^MODIFIED.$name$}xms, - @{$events} - ) + || ( grep { /^INITIALIZED$/x } @{$events} + or grep { /^REREADCFG$/x } @{$events} + or grep { /^MODIFIED.$name$/x } @{$events} ) && $devname eq 'global' ); @@ -297,7 +253,7 @@ sub Set { if ( lc $cmd eq 'addpassword' ) { return q{please set Attribut bTS_User first} - if ( AttrVal( $name, 'bTS_User', 'none' ) eq 'none' ); + if ( ::AttrVal( $name, 'bTS_User', 'none' ) eq 'none' ); return qq{usage: "$cmd" } if ( scalar( @{$aArg} ) != 1 ); @@ -312,22 +268,22 @@ sub Set { elsif ( lc $cmd eq 'active' ) { return qq{usage: $cmd} if ( scalar( @{$aArg} ) != 0 ); - + readingsSingleUpdate( $hash, 'state', 'ready', 1 ); } elsif ( lc $cmd eq 'inactive' ) { return qq{usage: $cmd} if ( scalar( @{$aArg} ) != 0 ); - + readingsSingleUpdate( $hash, 'state', $cmd, 1 ); } else { - my $list = 'active:noArg inactive:noArg'; - $list .= ( - defined( ReadPassword( $hash, $name ) ) - ? ' deletepassword:noArg' - : ' addpassword' - ); + my $list = 'active:noArg inactive:noArg'; + $list .= ( + defined( ReadPassword( $hash, $name ) ) + ? ' deletepassword:noArg' + : ' addpassword' + ); return qq{Unknown argument "$cmd", choose one of $list}; } @@ -336,52 +292,68 @@ sub Set { } sub Attr { - my $cmd = shift; - my $name = shift; + my $cmd = shift; + my $name = shift; - my $hash = $defs{$name}; - my $attrName = shift; - my $attrVal = shift; + my $hash = $defs{$name}; + my $attrName = shift; + my $attrVal = shift; + if ( $attrName eq 'disable' + || $attrName eq 'disabledForIntervals' ) + { - if ( $attrName eq 'disable' - || $attrName eq 'disabledForIntervals' ) { - if ( $cmd eq 'set' ) { if ( $attrName eq 'disabledForIntervals' ) { return - 'check disabledForIntervals Syntax HH:MM-HH:MM or HH:MM-HH:MM HH:MM-HH:MM ...' - if ( $attrVal !~ /^((\d{2}:\d{2})-(\d{2}:\d{2})\s?)+$/ ); - Log3( $name, 3, qq{backupToStorage ($name) - disabledForIntervals} ); +'check disabledForIntervals Syntax HH:MM-HH:MM or HH:MM-HH:MM HH:MM-HH:MM ...' + if ( $attrVal !~ /^((\d{2}:\d{2})-(\d{2}:\d{2})\s?)+$/x ); + ::Log3( $name, 3, + qq{backupToStorage ($name) - disabledForIntervals} ); } elsif ( $attrName eq 'disable' ) { - Log3( $name, 3, qq{backupToStorage ($name) - disabled} ); + ::Log3( $name, 3, qq{backupToStorage ($name) - disabled} ); } } - InternalTimer( gettimeofday() + 1, - 'FHEM::Services::backupToStorage::_CheckIsDisabledAfterSetAttr', $hash, 0 ); + ::InternalTimer( + ::gettimeofday() + 1, + 'FHEM::Services::backupToStorage::_CheckIsDisabledAfterSetAttr', + $hash, 0 + ); } elsif ( $attrName eq 'bTS_Type' ) { - InternalTimer( gettimeofday() + 1, - sub { $hash->{STORAGETYPE} = AttrVal($name,'bTS_Type','Nextcloud'); }, $hash, 0 ); + ::InternalTimer( + ::gettimeofday() + 1, + sub { + $hash->{STORAGETYPE} = + ::AttrVal( $name, 'bTS_Type', 'Nextcloud' ); + }, + $hash, + 0 + ); } return; } sub _CheckIsDisabledAfterSetAttr { - my $hash = shift; + my $hash = shift; - my $name = $hash->{NAME}; - my $state = ( IsDisabled($name) - ? 'inactive' - : 'ready' ); - - Log3( $name, 3, qq{backupToStorage ($name) - _CheckIsDisabledAfterSetAttr} ); + my $name = $hash->{NAME}; + my $state = ( + ::IsDisabled($name) + ? 'inactive' + : 'ready' + ); - readingsSingleUpdate($hash, 'state', $state, 1) - if ( ReadingsVal($name, 'state', 'ready' ) ne $state ); + ::Log3( $name, 3, + qq{backupToStorage ($name) - _CheckIsDisabledAfterSetAttr} ); + + readingsSingleUpdate( $hash, 'state', $state, 1 ) + if ( ::ReadingsVal( $name, 'state', 'ready' ) ne $state ); + + return; } sub Rename { @@ -391,7 +363,7 @@ sub Rename { my $hash = $defs{$new}; StorePassword( $hash, $new, ReadPassword( $hash, $old ) ); - setKeyValue( $hash->{TYPE} . "_" . $old . "_passwd", undef ); + ::setKeyValue( $hash->{TYPE} . "_" . $old . "_passwd", undef ); return; } @@ -401,66 +373,67 @@ sub PushToStorage { my $name = $hash->{NAME}; - Log3( $name, 4, qq{backupToStorage ($name) - push to storage function} ); - - return Log3( $name, 4, qq{backupToStorage ($name) - fhemBackupFile Reading to old} ) - if ( ReadingsAge($name,'fhemBackupFile',1) > 3600 ); - - Log3( $name, 4, qq{backupToStorage ($name) - after readings age return} ); + ::Log3( $name, 4, qq{backupToStorage ($name) - push to storage function} ); + return ::Log3( $name, 4, + qq{backupToStorage ($name) - fhemBackupFile Reading to old} ) + if ( ::ReadingsAge( $name, 'fhemBackupFile', 1 ) > 3600 ); + + ::Log3( $name, 4, qq{backupToStorage ($name) - after readings age return} ); if ( $hash->{STORAGETYPE} eq 'SynologyFileStation' ) { - - + } else { - require "SubProcess.pm"; + require SubProcess; my $subprocess = SubProcess->new( { onRun => \&FileUpload } ); - my $backupFile = ReadingsVal( $name, 'fhemBackupFile', 'none' ); + my $backupFile = ::ReadingsVal( $name, 'fhemBackupFile', 'none' ); my @fileNameAtStorage_array = split( '/', $backupFile ); - my $fileNameAtStorage = $fileNameAtStorage_array[$#fileNameAtStorage_array]; + my $fileNameAtStorage = + $fileNameAtStorage_array[$#fileNameAtStorage_array]; - $subprocess->{curl} = qx(which curl); - chomp($subprocess->{curl}); - $subprocess->{fhemhost} = qx(hostname -f); - chomp($subprocess->{fhemhost}); - $subprocess->{type} = $hash->{STORAGETYPE}; - $subprocess->{host} = AttrVal( $name, 'bTS_Host', '' ); - $subprocess->{user} = AttrVal( $name, 'bTS_User', '' ); - $subprocess->{pass} = ReadPassword( $hash, $name ); - $subprocess->{path} = AttrVal( $name, 'bTS_Path', '' ); - $subprocess->{backupfile} = $backupFile; - $subprocess->{fileNameAtStorage} = $fileNameAtStorage; - $subprocess->{proto} = AttrVal( $name, 'bTS_Proto', 'https' ); - $subprocess->{loglevel} = AttrVal( $name, 'verbose', 3 ); + $subprocess->{curl} = qx(which curl); + chomp( $subprocess->{curl} ); + $subprocess->{fhemhost} = qx(hostname -f); + chomp( $subprocess->{fhemhost} ); + $subprocess->{type} = $hash->{STORAGETYPE}; + $subprocess->{host} = ::AttrVal( $name, 'bTS_Host', '' ); + $subprocess->{user} = ::AttrVal( $name, 'bTS_User', '' ); + $subprocess->{pass} = ReadPassword( $hash, $name ); + $subprocess->{path} = ::AttrVal( $name, 'bTS_Path', '' ); + $subprocess->{backupfile} = $backupFile; + $subprocess->{fileNameAtStorage} = $fileNameAtStorage; + $subprocess->{proto} = ::AttrVal( $name, 'bTS_Proto', 'https' ); + $subprocess->{loglevel} = ::AttrVal( $name, 'verbose', 3 ); my $pid = $subprocess->run(); readingsSingleUpdate( $hash, 'state', ' file upload in progress', 1 ); if ( !defined($pid) ) { - Log3( $name, 1, - qq{backupToStorage ($name) - Cannot execute command asynchronously} ); + ::Log3( $name, 1, +qq{backupToStorage ($name) - Cannot execute command asynchronously} + ); CleanSubprocess($hash); readingsSingleUpdate( $hash, 'state', 'Cannot execute command asynchronously', 1 ); - return undef; + return; } - Log3( $name, 4, - qq{backupToStorage ($name) - execute command asynchronously (PID="$pid")} + ::Log3( $name, 4, +qq{backupToStorage ($name) - execute command asynchronously (PID="$pid")} ); $hash->{".fhem"}{subprocess} = $subprocess; - InternalTimer( gettimeofday() + 1, + ::InternalTimer( ::gettimeofday() + 1, "FHEM::Services::backupToStorage::PollChild", $hash ); } - Log3( $hash, 4, + ::Log3( $hash, 4, qq{backupToStorage ($name) - control passed back to main loop.} ); return; @@ -471,59 +444,61 @@ sub KeepLastN { my $name = $hash->{NAME}; - Log3( $name, 4, qq{backupToStorage ($name) - Keep Last N at Storage function} ); - + ::Log3( $name, 4, + qq{backupToStorage ($name) - Keep Last N at Storage function} ); if ( $hash->{STORAGETYPE} eq 'SynologyFileStation' ) { - - + } else { - require "SubProcess.pm"; + require SubProcess; my $subprocess = SubProcess->new( { onRun => \&CleanUp } ); - my $backupFile = ReadingsVal( $name, 'fhemBackupFile', 'none' ); + my $backupFile = ::ReadingsVal( $name, 'fhemBackupFile', 'none' ); my @fileNameAtStorage_array = split( '/', $backupFile ); - my $fileNameAtStorage = $fileNameAtStorage_array[$#fileNameAtStorage_array]; + my $fileNameAtStorage = + $fileNameAtStorage_array[$#fileNameAtStorage_array]; - $subprocess->{curl} = qx(which curl); - chomp($subprocess->{curl}); - $subprocess->{type} = $hash->{STORAGETYPE}; - $subprocess->{host} = AttrVal( $name, 'bTS_Host', '' ); - $subprocess->{user} = AttrVal( $name, 'bTS_User', '' ); - $subprocess->{pass} = ReadPassword( $hash, $name ); - $subprocess->{path} = AttrVal( $name, 'bTS_Path', '' ); - $subprocess->{fileNameAtStorage} = $fileNameAtStorage; - $subprocess->{proto} = AttrVal( $name, 'bTS_Proto', 'https' ); - $subprocess->{loglevel} = AttrVal( $name, 'verbose', 3 ); - $subprocess->{keeplastn} = AttrVal( $name, 'bTS_KeepLastBackups', 5 ); + $subprocess->{curl} = qx(which curl); + chomp( $subprocess->{curl} ); + $subprocess->{type} = $hash->{STORAGETYPE}; + $subprocess->{host} = ::AttrVal( $name, 'bTS_Host', '' ); + $subprocess->{user} = ::AttrVal( $name, 'bTS_User', '' ); + $subprocess->{pass} = ReadPassword( $hash, $name ); + $subprocess->{path} = ::AttrVal( $name, 'bTS_Path', '' ); + $subprocess->{fileNameAtStorage} = $fileNameAtStorage; + $subprocess->{proto} = ::AttrVal( $name, 'bTS_Proto', 'https' ); + $subprocess->{loglevel} = ::AttrVal( $name, 'verbose', 3 ); + $subprocess->{keeplastn} = ::AttrVal( $name, 'bTS_KeepLastBackups', 5 ); my $pid = $subprocess->run(); - readingsSingleUpdate( $hash, 'state', ' clean up pass last N in progress', 1 ); + readingsSingleUpdate( $hash, 'state', + ' clean up pass last N in progress', 1 ); if ( !defined($pid) ) { - Log3( $name, 1, - qq{backupToStorage ($name) - Cannot execute command asynchronously} ); + ::Log3( $name, 1, +qq{backupToStorage ($name) - Cannot execute command asynchronously} + ); CleanSubprocess($hash); readingsSingleUpdate( $hash, 'state', 'Cannot execute command asynchronously', 1 ); - return undef; + return; } - Log3( $name, 4, - qq{backupToStorage ($name) - execute command asynchronously (PID="$pid")} + ::Log3( $name, 4, +qq{backupToStorage ($name) - execute command asynchronously (PID="$pid")} ); $hash->{".fhem"}{subprocess} = $subprocess; - InternalTimer( gettimeofday() + 1, + ::InternalTimer( ::gettimeofday() + 1, "FHEM::Services::backupToStorage::PollChild", $hash ); } - Log3( $hash, 4, + ::Log3( $hash, 4, qq{backupToStorage ($name) - control passed back to main loop.} ); return; @@ -539,26 +514,29 @@ sub PollChild { my $json = $subprocess->readFromChild(); if ( !defined($json) ) { - Log3( $name, 5, - qq{backupToStorage ($name) - still waiting ($subprocess->{lasterror}).} + ::Log3( $name, 5, +qq{backupToStorage ($name) - still waiting ($subprocess->{lasterror}).} ); - InternalTimer( gettimeofday() + 1, + ::InternalTimer( ::gettimeofday() + 1, "FHEM::Services::backupToStorage::PollChild", $hash ); return; } else { - Log3( $name, 4, - qq{backupToStorage ($name) - got result from asynchronous parsing: $json} ); + ::Log3( $name, 4, +qq{backupToStorage ($name) - got result from asynchronous parsing: $json} + ); $subprocess->wait(); - Log3( $name, 4, + ::Log3( $name, 4, qq{backupToStorage ($name) - asynchronous finished.} ); CleanSubprocess($hash); WriteReadings( $hash, $json ); } } + + return; } ###################################### @@ -569,23 +547,23 @@ sub FileUpload { my $response = {}; if ( $subprocess->{type} eq 'Nextcloud' ) { - my ($returnString,$returnCode) = ExecuteNCupload($subprocess); - + my ( $returnString, $returnCode ) = ExecuteNCupload($subprocess); + print 'backupToStorage File Upload - FileUpload Nextcloud, returnCode: ' - . $returnCode - . ' , returnString: ' - . $returnString . "\n" + . $returnCode + . ' , returnString: ' + . $returnString . "\n" if ( $subprocess->{loglevel} > 4 ); - - - if ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/m - and $returnString =~ /\s\s(.*)<\/o:hint>/m ) { + + if ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/xm + and $returnString =~ /\s\s(.*)<\/o:hint>/xm ) + { $response->{ncUpload} = $1; } - elsif ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/m ) { + elsif ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/xm ) { $response->{ncUpload} = 'upload successfully'; } - elsif ( $returnString =~ /(curl:\s.*)/ ){ + elsif ( $returnString =~ /(curl:\s.*)/x ) { $response->{ncUpload} = $1; } else { @@ -596,7 +574,7 @@ sub FileUpload { my $json = eval { encode_json($response) }; if ($@) { print 'backupToStorage File Upload backupToStorage - JSON error: $@' - . "\n"; + . "\n"; $json = '{"jsonerror":"$@"}'; } @@ -618,7 +596,8 @@ sub ExecuteNCupload { $command .= $subprocess->{user}; $command .= $subprocess->{path}; $command .= '/'; - $command .= $subprocess->{fhemhost} . '-' . $subprocess->{fileNameAtStorage}; + $command .= + $subprocess->{fhemhost} . '-' . $subprocess->{fileNameAtStorage}; $command .= '"'; return ExecuteCommand($command); @@ -629,23 +608,23 @@ sub CleanUp { my $response = {}; if ( $subprocess->{type} eq 'Nextcloud' ) { - my ($returnString,$returnCode) = ExecuteCleanUp($subprocess); - + my ( $returnString, $returnCode ) = ExecuteCleanUp($subprocess); + print 'backupToStorage File Upload - FileUpload Nextcloud, returnCode: ' - . $returnCode - . ' , returnString: ' - . $returnString . "\n" + . $returnCode + . ' , returnString: ' + . $returnString . "\n" if ( $subprocess->{loglevel} > 4 ); - - - if ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/m - and $returnString =~ /\s\s(.*)<\/o:hint>/m ) { + + if ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/xm + and $returnString =~ /\s\s(.*)<\/o:hint>/xm ) + { $response->{ncUpload} = $1; } - elsif ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/m ) { + elsif ( $returnString =~ /100\s\s?[0-9].*\s100\s\s?[0-9].*/xm ) { $response->{ncUpload} = 'upload successfully'; } - elsif ( $returnString =~ /(curl:\s.*)/ ){ + elsif ( $returnString =~ /(curl:\s.*)/x ) { $response->{ncUpload} = $1; } else { @@ -656,7 +635,7 @@ sub CleanUp { my $json = eval { encode_json($response) }; if ($@) { print 'backupToStorage File Upload backupToStorage - JSON error: $@' - . "\n"; + . "\n"; $json = '{"jsonerror":"$@"}'; } @@ -676,7 +655,8 @@ sub ExecuteNCfetchFileList { $command .= '/remote.php/dav/files/'; $command .= $subprocess->{user}; $command .= $subprocess->{path}; - $command .= '" --data \'\''; + $command .= +'" --data \'\''; return ExecuteCommand($command); } @@ -700,7 +680,8 @@ sub ExecuteNCremoveFile { } sub ExecuteCommand { - my $command = join q{ }, @_; + my @options = @_; + my $command = join q{ }, @options; return ( $_ = qx{$command 2>&1}, $? >> 8 ); } @@ -714,7 +695,9 @@ sub CleanSubprocess { my $name = $hash->{NAME}; delete( $hash->{".fhem"}{subprocess} ); - Log3( $name, 4, qq{backupToStorage ($name) - clean Subprocess} ); + ::Log3( $name, 4, qq{backupToStorage ($name) - clean Subprocess} ); + + return; } sub StorePassword { @@ -723,10 +706,10 @@ sub StorePassword { my $password = shift; my $index = $hash->{TYPE} . "_" . $name . "_passwd"; - my $key = getUniqueId() . $index; + my $key = ::getUniqueId() . $index; my $enc_pwd = ""; - if ( eval "use Digest::MD5;1" ) { + if ( eval { use Digest::MD5; 1 } ) { $key = Digest::MD5::md5_hex( unpack "H*", $key ); $key .= Digest::MD5::md5_hex($key); @@ -739,8 +722,8 @@ sub StorePassword { $key = $encode . $key; } - my $err = setKeyValue( $index, $enc_pwd ); - DoTrigger( $name, 'password add' ); + my $err = ::setKeyValue( $index, $enc_pwd ); + ::DoTrigger( $name, 'password add' ); return qq{error while saving the password - $err} if ( defined($err) ); @@ -753,30 +736,31 @@ sub ReadPassword { my $name = shift; my $index = $hash->{TYPE} . "_" . $name . "_passwd"; - my $key = getUniqueId() . $index; + my $key = ::getUniqueId() . $index; my ( $password, $err ); - Log3( $name, 4, qq{backupToStorage ($name) - Read password from file} ); + ::Log3( $name, 4, qq{backupToStorage ($name) - Read password from file} ); - ( $err, $password ) = getKeyValue($index); + ( $err, $password ) = ::getKeyValue($index); if ( defined($err) ) { - Log3( $name, 3, - qq{backupToStorage ($name) - unable to read password from file: $err} + ::Log3( $name, 3, +qq{backupToStorage ($name) - unable to read password from file: $err} ); - return undef; + return; } if ( defined($password) ) { - if ( eval "use Digest::MD5;1" ) { + if ( eval { use Digest::MD5; 1 } ) { $key = Digest::MD5::md5_hex( unpack "H*", $key ); $key .= Digest::MD5::md5_hex($key); } my $dec_pwd = ''; - for my $char ( map { pack( 'C', hex($_) ) } ( $password =~ /(..)/g ) ) { + for my $char ( map { pack( 'C', hex($_) ) } ( $password =~ /(..)/xg ) ) + { my $decode = chop($key); $dec_pwd .= chr( ord($char) ^ ord($decode) ); @@ -786,8 +770,8 @@ sub ReadPassword { return $dec_pwd; } else { - Log3( $name, 3, qq{backupToStorage ($name) - No password in file} ); - return undef; + ::Log3( $name, 3, qq{backupToStorage ($name) - No password in file} ); + return; } return; @@ -798,8 +782,8 @@ sub DeletePassword { my $name = $hash->{NAME}; - setKeyValue( $hash->{TYPE} . "_" . $name . "_passwd", undef ); - DoTrigger( $name, 'password remove' ); + ::setKeyValue( $hash->{TYPE} . "_" . $name . "_passwd", undef ); + ::DoTrigger( $name, 'password remove' ); return; } @@ -809,21 +793,17 @@ sub CheckAttributsForCredentials { my $name = $hash->{NAME}; - my $ncUser = AttrVal( $name, 'bTS_User', 'none' ); + my $ncUser = ::AttrVal( $name, 'bTS_User', 'none' ); my $ncPass = ReadPassword( $hash, $name ); - my $ncHost = AttrVal( $name, 'bTS_Host', 'none' ); + my $ncHost = ::AttrVal( $name, 'bTS_Host', 'none' ); my $status = 'ready'; - $status = ( $status eq 'ready' - && $ncUser eq 'none' - ? 'no user credential attribut' - : $status eq 'ready' - && $ncHost eq 'none' - ? 'no host credential attribut' - : $status eq 'ready' - && !defined($ncPass) - ? 'no password set' - : $status + $status = ( + $status eq 'ready' && $ncUser eq 'none' ? 'no user credential attribut' + : $status eq 'ready' + && $ncHost eq 'none' ? 'no host credential attribut' + : $status eq 'ready' && !defined($ncPass) ? 'no password set' + : $status ); return readingsSingleUpdate( $hash, 'state', $status, 1 ); @@ -837,14 +817,16 @@ sub WriteReadings { my $decode_json = eval { decode_json($json) }; if ($@) { - Log3( $name, 2, qq{backupToStorage ($name) - JSON error: $@} ); + ::Log3( $name, 2, qq{backupToStorage ($name) - JSON error: $@} ); return; } - readingsBeginUpdate($hash); - readingsBulkUpdate( $hash, 'state', 'ready' ); - readingsBulkUpdate( $hash, 'uploadState', $decode_json->{ncUpload} ); - readingsEndUpdate( $hash, 1 ); + ::readingsBeginUpdate($hash); + ::readingsBulkUpdate( $hash, 'state', 'ready' ); + ::readingsBulkUpdate( $hash, 'uploadState', $decode_json->{ncUpload} ); + ::readingsEndUpdate( $hash, 1 ); + + return; } 1; -- 2.45.2 From bb46ccab455f91d01abe0bf8818c7628f68f491c Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Thu, 5 Jan 2023 20:43:49 +0100 Subject: [PATCH 2/2] rewrite commandref rewrite commandref with id tag [Ticket: X] --- FHEM/98_backupToStorage.pm | 140 +++++++++++++++++++++++------------ controls_backupToStorage.txt | 4 +- 2 files changed, 93 insertions(+), 51 deletions(-) diff --git a/FHEM/98_backupToStorage.pm b/FHEM/98_backupToStorage.pm index 28e6788..7833b4f 100644 --- a/FHEM/98_backupToStorage.pm +++ b/FHEM/98_backupToStorage.pm @@ -1,8 +1,8 @@ ############################################################################### # -# Developed with Kate +# Developed with VSCodium and richterger perl plugin # -# (c) 2020-2021 Copyright: Marko Oldenburg (fhemdevelopment@cooltux.net) +# (c) 2020-2023 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) # All rights reserved # # Special thanks goes to: @@ -29,28 +29,33 @@ # ############################################################################### -package main; +package FHEM::backupToStorage; use strict; use warnings; use utf8; use FHEM::Meta; -use FHEM::Services::backupToStorage; +require FHEM::Services::backupToStorage; -sub backupToStorage_Initialize { +#-- Run before package compilation +BEGIN { + sub ::backupToStorage_Initialize { goto &Initialize } +} + +sub Initialize { my $hash = shift; ## Da ich mit package arbeite müssen in die Initialize für die jeweiligen hash Fn Funktionen der Funktionsname # und davor mit :: getrennt der eigentliche package Name des Modules - $hash->{SetFn} = \&FHEM::Services::backupToStorage::Set; - $hash->{DefFn} = \&FHEM::Services::backupToStorage::Define; - $hash->{NotifyFn} = \&FHEM::Services::backupToStorage::Notify; - $hash->{UndefFn} = \&FHEM::Services::backupToStorage::Undef; - $hash->{AttrFn} = \&FHEM::Services::backupToStorage::Attr; - $hash->{RenameFn} = \&FHEM::Services::backupToStorage::Rename; - $hash->{DeleteFn} = \&FHEM::Services::backupToStorage::Delete; - $hash->{ShutdownFn} = \&FHEM::Services::backupToStorage::Shutdown; + $hash->{SetFn} = \&FHEM::Services::backupToStorage::Set; + $hash->{DefFn} = \&FHEM::Services::backupToStorage::Define; + $hash->{NotifyFn} = \&FHEM::Services::backupToStorage::Notify; + $hash->{UndefFn} = \&FHEM::Services::backupToStorage::Undef; + $hash->{AttrFn} = \&FHEM::Services::backupToStorage::Attr; + $hash->{RenameFn} = \&FHEM::Services::backupToStorage::Rename; + $hash->{DeleteFn} = \&FHEM::Services::backupToStorage::Delete; + $hash->{ShutdownFn} = \&FHEM::Services::backupToStorage::Shutdown; $hash->{NotifyOrderPrefix} = '51-'; # Order Nummer für NotifyFn $hash->{AttrList} = 'bTS_Host ' @@ -76,13 +81,14 @@ sub backupToStorage_Initialize { =begin html - +

backupToStorage

    The module offers the possibility to automatically load the created backup files from the backup module onto a storage.

    - Define + +

    Define

      define <name> backupToStorage
      @@ -92,28 +98,46 @@ sub backupToStorage_Initialize {

- - Attributs + +

Attributs

    -
  • bTS_Host - Server name where the storage is located
  • -
  • bTS_User - remote user for login
  • -
  • bTS_Path - remote path where the upload file should go. e.g. Nextcloud </FHEM-Backup>
  • -
  • bTS_Type - Storage Type, default is Nextcloud
  • + +
  • bTS_Host + Server name where the storage is located +
  • + +
  • bTS_User + remote user for login +
  • + +
  • bTS_Path + remote path where the upload file should go. e.g. Nextcloud </FHEM-Backup> +
  • + +
  • bTS_Type + Storage Type, default is Nextcloud +

- - Set + +

Set

    -
  • addpassword - puts the storage password in the keyfile / !!! don't use = !!!
  • -
  • deletepassword - removes the storage password from the keyfile
  • + +
  • addpassword + puts the storage password in the keyfile / !!! don't use = !!! +
  • + +
  • deletepassword + removes the storage password from the keyfile +

- + Readings
    -
  • state - shows the current status of the module
  • -
  • fhemBackupFile - the path of the last backup file is automatically set by the backup module
  • -
  • uploadState - Status of the last upload.
  • +
  • state - shows the current status of the module
  • +
  • fhemBackupFile - the path of the last backup file is automatically set by the backup module
  • +
  • uploadState - Status of the last upload.
@@ -121,13 +145,14 @@ sub backupToStorage_Initialize { =begin html_DE - +

backupToStorage

    Das Modul bietet die Möglichkeit die erstellten Backupdateien vom Modul backup automatisiert auf ein Storage zu laden.

    - Define + +

    Define

      define <name> backupToStorage
      @@ -137,29 +162,46 @@ sub backupToStorage_Initialize {

- - Attribute + +

Attribute

    -
  • bTS_Host - Servername wo sich das Storage drauf befindet
  • -
  • bTS_User - remote User für den Login
  • -
  • bTS_Path - remote Path wohin das uploadfile soll. z.B. Nextcloud </FHEM-Backup>
  • -
  • bTS_Type - Storage Type, default ist Nextcloud
  • -
  • bTS_Type - Storage Type, default ist Nextcloud
  • + +
  • bTS_Host + Servername wo sich das Storage drauf befindet +
  • + +
  • bTS_User + remote User für den Login +
  • + +
  • bTS_Path + remote Path wohin das uploadfile soll. z.B. Nextcloud </FHEM-Backup> +
  • + +
  • bTS_Type + Storage Type, default ist Nextcloud +

- - Set + +

Set

    -
  • addpassword - setzt das Storage Passwort ins Keyfile / !!!Keine = verwenden!!!
  • -
  • deletepassword - entfernt das Storage Passwort aus dem Keyfile
  • + +
  • addpassword
    + setzt das Storage Passwort ins Keyfile / !!!Keine = verwenden!!! +
  • + +
  • deletepassword
    + entfernt das Storage Passwort aus dem Keyfile +

- - Readings + +

Readings

    -
  • state - zeigt den aktuellen Status des Modules an
  • -
  • fhemBackupFile - der Pfad des letzten Backupfiles, wird automatisch vom backup Modul gesetzt
  • -
  • uploadState - Status des letzten uploads.
  • +
  • state - zeigt den aktuellen Status des Modules an
  • +
  • fhemBackupFile - der Pfad des letzten Backupfiles, wird automatisch vom backup Modul gesetzt
  • +
  • uploadState - Status des letzten uploads.
@@ -181,7 +223,7 @@ sub backupToStorage_Initialize { ], "release_status": "devepolment", "license": "GPL_2", - "version": "v1.4.0", + "version": "v2.0.0", "author": [ "Marko Oldenburg " ], @@ -189,7 +231,7 @@ sub backupToStorage_Initialize { "CoolTux" ], "x_fhem_maintainer_github": [ - "LeonGaultier" + "CoolTuxNet" ], "prereqs": { "runtime": { diff --git a/controls_backupToStorage.txt b/controls_backupToStorage.txt index 54c8724..86c859f 100644 --- a/controls_backupToStorage.txt +++ b/controls_backupToStorage.txt @@ -1,2 +1,2 @@ -UPD 2022-03-10_06:48:27 6511 FHEM/98_backupToStorage.pm -UPD 2022-03-10_08:41:03 23352 lib/FHEM/Services/backupToStorage.pm +UPD 2023-01-05_20:43:08 7708 FHEM/98_backupToStorage.pm +UPD 2023-01-05_20:06:46 23352 lib/FHEM/Services/backupToStorage.pm -- 2.45.2