|
16 | 16 |
|
17 | 17 | require 'stringio' |
18 | 18 | require 'zlib' |
| 19 | +require 'zstd-ruby' |
19 | 20 |
|
20 | 21 | module Fluent |
21 | 22 | module Plugin |
22 | 23 | module Compressable |
23 | | - def compress(data, **kwargs) |
| 24 | + def compress(data, type: :gzip, **kwargs) |
24 | 25 | output_io = kwargs[:output_io] |
| 26 | + writer = nil |
25 | 27 | io = output_io || StringIO.new |
26 | | - Zlib::GzipWriter.wrap(io) do |gz| |
27 | | - gz.write data |
| 28 | + if type == :gzip |
| 29 | + writer = Zlib::GzipWriter.new(io) |
| 30 | + elsif type == :zstd |
| 31 | + writer = Zstd::StreamWriter.new(io) |
| 32 | + else |
| 33 | + raise ArgumentError, "Unknown compression type: #{type}" |
28 | 34 | end |
29 | | - |
| 35 | + writer.write(data) |
| 36 | + writer.finish |
30 | 37 | output_io || io.string |
31 | 38 | end |
32 | 39 |
|
33 | 40 | # compressed_data is String like `compress(data1) + compress(data2) + ... + compress(dataN)` |
34 | 41 | # https://www.ruby-forum.com/topic/971591#979503 |
35 | | - def decompress(compressed_data = nil, output_io: nil, input_io: nil) |
| 42 | + def decompress(compressed_data = nil, output_io: nil, input_io: nil, type: :gzip) |
36 | 43 | case |
37 | 44 | when input_io && output_io |
38 | | - io_decompress(input_io, output_io) |
| 45 | + io_decompress(input_io, output_io, type) |
39 | 46 | when input_io |
40 | 47 | output_io = StringIO.new |
41 | | - io = io_decompress(input_io, output_io) |
| 48 | + io = io_decompress(input_io, output_io, type) |
42 | 49 | io.string |
43 | 50 | when compressed_data.nil? || compressed_data.empty? |
44 | 51 | # check compressed_data(String) is 0 length |
45 | 52 | compressed_data |
46 | 53 | when output_io |
47 | 54 | # execute after checking compressed_data is empty or not |
48 | 55 | io = StringIO.new(compressed_data) |
49 | | - io_decompress(io, output_io) |
| 56 | + io_decompress(io, output_io, type) |
50 | 57 | else |
51 | | - string_decompress(compressed_data) |
| 58 | + string_decompress(compressed_data, type) |
52 | 59 | end |
53 | 60 | end |
54 | 61 |
|
55 | 62 | private |
56 | 63 |
|
57 | | - def string_decompress(compressed_data) |
| 64 | + def string_decompress(compressed_data, type = :gzip) |
58 | 65 | io = StringIO.new(compressed_data) |
59 | 66 |
|
60 | 67 | out = '' |
61 | 68 | loop do |
62 | | - gz = Zlib::GzipReader.new(io) |
63 | | - out << gz.read |
64 | | - unused = gz.unused |
65 | | - gz.finish |
| 69 | + if type == :gzip |
| 70 | + reader = Zlib::GzipReader.new(io) |
| 71 | + out << reader.read |
| 72 | + unused = reader.unused |
| 73 | + reader.finish |
66 | 74 |
|
67 | | - unless unused.nil? |
68 | | - adjust = unused.length |
69 | | - io.pos -= adjust |
| 75 | + unless unused.nil? |
| 76 | + adjust = unused.length |
| 77 | + io.pos -= adjust |
| 78 | + end |
| 79 | + elsif type == :zstd |
| 80 | + reader = Zstd::StreamReader.new(io) |
| 81 | + # Zstd::StreamReader needs to specify the size of the buffer |
| 82 | + out << reader.read(1024) |
| 83 | + # Zstd::StreamReader doesn't provide unused data, so we have to manually adjust the position |
| 84 | + else |
| 85 | + raise ArgumentError, "Unknown compression type: #{type}" |
70 | 86 | end |
71 | 87 | break if io.eof? |
72 | 88 | end |
73 | 89 |
|
74 | 90 | out |
75 | 91 | end |
76 | 92 |
|
77 | | - def io_decompress(input, output) |
| 93 | + def io_decompress(input, output, type = :gzip) |
78 | 94 | loop do |
79 | | - gz = Zlib::GzipReader.new(input) |
80 | | - v = gz.read |
81 | | - output.write(v) |
82 | | - unused = gz.unused |
83 | | - gz.finish |
84 | | - |
85 | | - unless unused.nil? |
86 | | - adjust = unused.length |
87 | | - input.pos -= adjust |
| 95 | + reader = nil |
| 96 | + if type == :gzip |
| 97 | + reader = Zlib::GzipReader.new(input) |
| 98 | + v = reader.read |
| 99 | + output.write(v) |
| 100 | + unused = reader.unused |
| 101 | + reader.finish |
| 102 | + unless unused.nil? |
| 103 | + adjust = unused.length |
| 104 | + input.pos -= adjust |
| 105 | + end |
| 106 | + elsif type == :zstd |
| 107 | + reader = Zstd::StreamReader.new(input) |
| 108 | + # Zstd::StreamReader needs to specify the size of the buffer |
| 109 | + v = reader.read(1024) |
| 110 | + output.write(v) |
| 111 | + # Zstd::StreamReader doesn't provide unused data, so we have to manually adjust the position |
| 112 | + else |
| 113 | + raise ArgumentError, "Unknown compression type: #{type}" |
88 | 114 | end |
89 | 115 | break if input.eof? |
90 | 116 | end |
|
0 commit comments