adjust preview cache
This commit is contained in:
@@ -5,6 +5,10 @@ class PreviewDocumentPageController < ActionController::API
|
|||||||
|
|
||||||
FORMAT = Templates::ProcessDocument::FORMAT
|
FORMAT = Templates::ProcessDocument::FORMAT
|
||||||
|
|
||||||
|
TMPFILE_PREFIX = 'attachment-'
|
||||||
|
TMPFILE_TTL = 5.minutes
|
||||||
|
TMPFILE_MAX_TOTAL_SIZE = Docuseal.multitenant? ? 400.megabytes : 1.gigabyte
|
||||||
|
|
||||||
def show
|
def show
|
||||||
result_data =
|
result_data =
|
||||||
ApplicationRecord.signed_id_verifier.verified(params[:signed_key], purpose: :attachment)
|
ApplicationRecord.signed_id_verifier.verified(params[:signed_key], purpose: :attachment)
|
||||||
@@ -30,34 +34,63 @@ class PreviewDocumentPageController < ActionController::API
|
|||||||
allow_other_host: true
|
allow_other_host: true
|
||||||
end
|
end
|
||||||
|
|
||||||
file_path =
|
|
||||||
if attachment.service.name == :disk
|
|
||||||
ActiveStorage::Blob.service.path_for(attachment.key)
|
|
||||||
else
|
|
||||||
find_or_create_document_tempfile_path(attachment)
|
|
||||||
end
|
|
||||||
|
|
||||||
preview_image =
|
preview_image =
|
||||||
Templates::ProcessDocument.generate_pdf_preview_from_file(attachment, file_path, params[:id].to_i)
|
open_attachment_io(attachment) do |io|
|
||||||
|
Templates::ProcessDocument.generate_pdf_preview_from_io(attachment, io, params[:id].to_i)
|
||||||
|
end
|
||||||
|
|
||||||
redirect_to preview_image.url(time: ActiveStorage::Attachment.service_url_time), allow_other_host: true
|
redirect_to preview_image.url(time: ActiveStorage::Attachment.service_url_time), allow_other_host: true
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_or_create_document_tempfile_path(attachment)
|
def open_attachment_io(attachment, &)
|
||||||
file_path = "#{Dir.tmpdir}/attachment-#{Digest::SHA1.hexdigest("#{attachment.id}-#{attachment.uuid}")}"
|
return File.open(ActiveStorage::Blob.service.path_for(attachment.key), 'rb', &) if attachment.service.name == :disk
|
||||||
|
|
||||||
File.open(file_path, File::RDWR | File::CREAT, 0o644) do |f|
|
file_name = "#{TMPFILE_PREFIX}#{Digest::SHA1.hexdigest("#{attachment.id}-#{attachment.uuid}")}"
|
||||||
f.flock(File::LOCK_EX)
|
|
||||||
|
file_path = File.join(Dir.tmpdir, file_name)
|
||||||
|
|
||||||
|
File.open(file_path, File::RDWR | File::CREAT, 0o644) do |file|
|
||||||
|
file.flock(File::LOCK_EX)
|
||||||
|
|
||||||
# rubocop:disable Style/ZeroLengthPredicate
|
# rubocop:disable Style/ZeroLengthPredicate
|
||||||
if f.size.zero?
|
if file.size.zero?
|
||||||
f.binmode
|
cleanup_stale_tempfiles
|
||||||
|
|
||||||
f.write(attachment.download)
|
file.binmode
|
||||||
|
|
||||||
|
file.write(attachment.download)
|
||||||
|
else
|
||||||
|
FileUtils.touch(file_path)
|
||||||
end
|
end
|
||||||
# rubocop:enable Style/ZeroLengthPredicate
|
# rubocop:enable Style/ZeroLengthPredicate
|
||||||
end
|
|
||||||
|
|
||||||
file_path
|
file.flock(File::LOCK_UN)
|
||||||
|
|
||||||
|
yield file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def cleanup_stale_tempfiles
|
||||||
|
entries =
|
||||||
|
Dir.glob(File.join(Dir.tmpdir, "#{TMPFILE_PREFIX}*")).filter_map do |path|
|
||||||
|
stat = File.stat(path)
|
||||||
|
|
||||||
|
[path, stat.mtime, stat.size]
|
||||||
|
rescue Errno::ENOENT
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
total_size = entries.sum(&:last)
|
||||||
|
stale_time = TMPFILE_TTL.ago
|
||||||
|
|
||||||
|
entries.sort_by(&:second).each do |path, mtime, size|
|
||||||
|
break if mtime > stale_time && total_size <= TMPFILE_MAX_TOTAL_SIZE
|
||||||
|
|
||||||
|
File.unlink(path)
|
||||||
|
|
||||||
|
total_size -= size
|
||||||
|
rescue Errno::ENOENT
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ class Pdfium
|
|||||||
|
|
||||||
attach_function :FPDF_LoadDocument, %i[string FPDF_STRING], :FPDF_DOCUMENT
|
attach_function :FPDF_LoadDocument, %i[string FPDF_STRING], :FPDF_DOCUMENT
|
||||||
attach_function :FPDF_LoadMemDocument, %i[pointer int FPDF_STRING], :FPDF_DOCUMENT
|
attach_function :FPDF_LoadMemDocument, %i[pointer int FPDF_STRING], :FPDF_DOCUMENT
|
||||||
|
attach_function :FPDF_LoadCustomDocument, %i[pointer FPDF_STRING], :FPDF_DOCUMENT
|
||||||
attach_function :FPDF_CloseDocument, [:FPDF_DOCUMENT], :void
|
attach_function :FPDF_CloseDocument, [:FPDF_DOCUMENT], :void
|
||||||
attach_function :FPDF_GetPageCount, [:FPDF_DOCUMENT], :int
|
attach_function :FPDF_GetPageCount, [:FPDF_DOCUMENT], :int
|
||||||
attach_function :FPDF_GetLastError, [], :ulong
|
attach_function :FPDF_GetLastError, [], :ulong
|
||||||
@@ -463,6 +464,43 @@ class Pdfium
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.open_io(io, password = nil)
|
||||||
|
io.binmode
|
||||||
|
|
||||||
|
get_block = FFI::Function.new(:int, %i[pointer ulong pointer ulong]) do |_param, position, out, size|
|
||||||
|
io.seek(position)
|
||||||
|
|
||||||
|
bytes = io.read(size).to_s
|
||||||
|
|
||||||
|
out.put_bytes(0, bytes)
|
||||||
|
|
||||||
|
bytes.bytesize == size ? 1 : 0
|
||||||
|
end
|
||||||
|
|
||||||
|
file_access = Pdfium::FPDF_FILEACCESS.new
|
||||||
|
file_access[:m_FileLen] = io.size
|
||||||
|
file_access[:m_GetBlock] = get_block
|
||||||
|
file_access[:m_Param] = FFI::Pointer::NULL
|
||||||
|
|
||||||
|
doc_ptr = Pdfium.FPDF_LoadCustomDocument(file_access, password)
|
||||||
|
|
||||||
|
if doc_ptr.null?
|
||||||
|
Pdfium.check_last_error('Failed to load document from IO')
|
||||||
|
|
||||||
|
raise PdfiumError, 'Failed to load document from IO, pointer is NULL.'
|
||||||
|
end
|
||||||
|
|
||||||
|
doc = new(doc_ptr, [file_access, get_block, io])
|
||||||
|
|
||||||
|
return doc unless block_given?
|
||||||
|
|
||||||
|
begin
|
||||||
|
yield doc
|
||||||
|
ensure
|
||||||
|
doc.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def closed?
|
def closed?
|
||||||
@closed
|
@closed
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -192,8 +192,8 @@ module Templates
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_pdf_preview_from_file(attachment, file_path, page_number)
|
def generate_pdf_preview_from_io(attachment, io, page_number)
|
||||||
doc = Pdfium::Document.open_file(file_path)
|
doc = Pdfium::Document.open_io(io)
|
||||||
|
|
||||||
doc_page = doc.get_page(page_number)
|
doc_page = doc.get_page(page_number)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user