
    i                     Z    d dl Z d dlZd dlZd dlZd dlmZmZmZmZ d dl	  G d d      Z
y)    N)IterableIteratorOptionalUnion)*c                       e Zd ZdZdZdZddedee   fdZdefd	Z	defd
Z
d ZdefdZed        Zedededefd       Zdedee   fdZdeeeej0                  f      fdZy)BackupTarManageru  
    Менеджер для генерации tar архивов на лету чанками.

    В tar-архиве каждый файл хранится в виде последовательности блоков по 512 байт:
    header - 512 bytes
    file data - N bytes
    padding - до 512 bytes

    Заканчивается архив двумя блоками по 512 байт заполненных нулями
    i   i   Nnamebase_dirc                 N    || _         |st        j                  | _        d | _        y N)r
   configBACKUP_BASE_DIRr   index_content)selfr
   r   s      ./modules/backup/manager.py__init__zBackupTarManager.__init__   s!    	"22DM7;    returnc                 "    d| j                    dS )Nz/opt/eva-app/backup/z_index_tar.jsonr
   r   s    r   _get_index_filenamez$BackupTarManager._get_index_filename!   s    %dii[@@r   c                      | j                    dS )Nz	_full.tarr   r   s    r   get_tar_filenamez!BackupTarManager.get_tar_filename$   s    ))I&&r   c                     | j                   sJ| j                         }t        |      5 }t        j                  |      | _         d d d        | j                   S | j                   S # 1 sw Y   | j                   S xY wr   )r   r   openjsonload)r   index_filenameindex_wrappers      r   _get_index_contentz#BackupTarManager._get_index_content'   sk    !!!557Nn% >%)YY}%="> !!!t!!!> !!!s   A##A7c                 (    | j                         d   S )N
total_size)r"   r   s    r   get_total_size_from_indexz*BackupTarManager.get_total_size_from_index/   s    &&(66r   c                 T    | j                   || j                   z  z
  | j                   z  S )u  
        Рассчет количества байтов заполнения, необходимых после файла в Tar архиве

        Пример:
        size = 1000 bytes

        TAR слой:
            [512 bytes header]
            [1000 bytes file data]
            [24 bytes padding]

        24 padding требуется:
            1000 % 512 = 488
            512 - 488 = 24
        )BLOCK)clssizes     r   _paddingzBackupTarManager._padding2   s%    " 		D399,,		99r   pathr)   c                     t        j                  |       }||_        d|_        d|_        |j                  t         j                        S )uA   
        Формирование tar заголовка
        i  r   )format)tarfileTarInfor)   modemtimetobufUSTAR_FORMAT)r+   r)   tis      r   _build_headerzBackupTarManager._build_headerE   s>     __T"xxw33x44r   start_offsetc              #   *  K   | j                         d   }d}d| j                  z  }|D ]x  }|d   }|d   }|d   }|d   }	| j                  |      }
|	|z   }||
z   }||k\  r|};| j                  ||      }||	k  rt	        d||z
        }||d  t
        j                  j                  | j                  |      }t        j                  d	|       t	        d||	z
        }||z
  }	 t        |d
      5 }|j                  |       |dkD  r@|j                  t        | j                  |            }|sn|t        |      z  }| |dkD  r@ddd       |dkD  r(t        | j                  |      }|d|  ||z  }|dkD  r(|
rt	        d||z
        }||
k  r
d|
|z
  z   |}d}{ ||| j"                  dz  z   k  r't	        d||z
        }d| j"                  dz  |z
  z   yy# 1 sw Y   xY w# t         $ r t        j                  d|       Y w xY ww)uz   
        Стриминг файлов в качестве tar архива с учётом Range-запроса.
        filesr       r+   r)   header_offsetdata_offsetNzStart to stream file=%srbz+File not found, filling with zeros, file=%s   )r"   
CHUNK_SIZEr*   r5   maxosr+   joinr   loggingdebugr   seekreadminlenFileNotFoundErrorr'   )r   r6   r8   current_offset
zero_chunkentryr+   r)   r:   r;   paddata_endfile_endheaderstart_in_header	file_pathrD   	remainingfchunk
chunk_size	pad_startstart_in_finals                          r   stream_tar_from_rangez&BackupTarManager.stream_tar_from_rangeQ   s\    
 '')'2T__,
 4	E=D=D!/2M.K--%C"T)H#~H x'!)''d3Fk)"%a)E"F_-.. T]]D9IMM3Y?q,45DtI
X)T* $aFF4L#a- !s4??I'F G$!!SZ/	# $a-$ a- )<
 *--Z'	 a- <(#:;	s?3?33%NLi4	n .4::>99 L>$ABN4::>N:;; :9$ $ % XKYWXsJ   C#H&G.2AG"	G.,H>A$H"G+	'G..HHHH
root_pathsc                 R    dg dt         dt         f fd}|D ]&  }t        j                  j                  |      }t        j                  j	                  |      r5t        j                  j                  | j                        } |||       wt        j                  j                  |      r{t        j                  |      D ]a  \  }}}|D ]V  }t        j                  j                  ||      }	t        j                  j                  |	 j                        } ||	|       X c t        j                  d|       )  j                  dz  z   }
|
d} j                         }t        |d	      5 }t        j                   ||d
       ddd       y# 1 sw Y   yxY w)uA  
        Генерирует индекс tar для всех файлов и директорий, указанных в root_paths,
        включая поддиректории, и сохраняет в JSON.

        Пути внутри архива строятся относительно base_dir.
        r   	full_pathrel_pathc                     t         j                  j                  |       }
j                  ||      }t	        |      }	}	|z   }j                  ||||d       
j                  |      }	||z   |z   z  	y )N)r+   r)   r:   r;   )r@   r+   getsizer5   rG   appendr*   )r[   r\   r)   rO   
header_lenr:   r;   rL   indexoffsetr   s           r   _create_index_from_pathzOBackupTarManager.generate_tar_index_from_paths.<locals>._create_index_from_path   s    77??9-D''$7FVJ"M :-KLL$ %2#.	 --%Cj4'#--Fr   )startz!tar_index: path %s does not existr=   )r$   r8   w   )indentN)strr@   r+   abspathisfilerelpathr   isdirwalkrA   rB   warningr'   r   r   r   dump)r   rY   rc   r+   r\   root_	filenamesrS   r[   r$   resultoutput_pathra   rb   s   `            @@r   generate_tar_index_from_pathsz.BackupTarManager.generate_tar_index_from_paths   si    	.s 	.c 	.(  	KD77??4(Dww~~d#77??4t}}?E'h7t$*,''$- E&D!Y& E$&GGLLq$9	#%77??9DMM?#R/	8DEE  CTJ	K djj1n,
 %
 ..0+s# 	+qIIfa*	+ 	+ 	+s   ;FF&r   )__name__
__module____qualname____doc__r'   r>   rh   r   r   r   r   r"   intr%   classmethodr*   staticmethodbytesr5   r   rX   r   r   r@   PathLikeru    r   r   r	   r	   
   s    	 EJ<S <HSM <AS A'# '"73 7 : :$ 	5C 	5s 	5u 	5 	5B<# B<(5/ B<H:+U3#345:+r   r	   )r   rB   r@   r.   typingr   r   r   r   cmf.includer	   r   r   r   <module>r      s&      	  6 6 E+ E+r   