Class: Webcache::DiskCache
- Inherits:
-
Object
- Object
- Webcache::DiskCache
- Defined in:
- lib/webget/webcache_disk.rb,
lib/webget/webcache_disk-rewrite.rb
Overview
todo/check - change to Disk - why? why not?
Instance Method Summary collapse
- #_body_path(url) ⇒ Object
- #_meta_path(url) ⇒ Object
- #_read_utf8(path) ⇒ Object
- #_write_utf8(path, text) ⇒ Object
- #cached?(url) ⇒ Boolean (also: #exist?)
-
#read(url) ⇒ Object
fix-fix-fix change to read_txt/read_text/read_html plus add read_blob/read_bin(ary) !!!.
- #read_csv(url) ⇒ Object
- #read_json(url) ⇒ Object
- #read_meta(url) ⇒ Object
-
#record(url, response, format:) ⇒ Object
add more save / put / etc.
-
#rewrite_path(host, req_path) ⇒ Object
todo/fix - make rewrite_path configurable "pipeline" lets you auto-add more rewriters and keep this code "generic" move rewriters "downstream" into "userland" ??.
-
#url_to_path(str) ⇒ Object
helpers.
Instance Method Details
#_body_path(url) ⇒ Object
8 |
# File 'lib/webget/webcache_disk.rb', line 8 def _body_path( url ) "#{Webcache.root}/#{url_to_path( url )}"; end |
#_meta_path(url) ⇒ Object
9 |
# File 'lib/webget/webcache_disk.rb', line 9 def ( url ) "#{Webcache.root}/#{url_to_path( url )}.meta.txt"; end |
#_read_utf8(path) ⇒ Object
194 195 196 197 198 199 200 201 |
# File 'lib/webget/webcache_disk.rb', line 194 def _read_utf8( path ) ## note - by default ruby on windows (automagically) ## translates \r\n newlines to \n (universal/unix-style) ## when read files!!!! ## note - only handles \r\n (not "legacy" mac classic-style \r) File.open( path, 'r:utf-8' ) {|f| f.read } end |
#_write_utf8(path, text) ⇒ Object
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/webget/webcache_disk.rb', line 203 def _write_utf8( path, text ) ## write out utf8 (always use "universal" newlines on any platform) ## todo / fix - add universial or such to open too ? ## ## fix: newlines - always use "unix" style" - why? why not? ## fix: use :newline => :universal option? translates to univeral "\n" ## ## ## The universal_newline: true flag forces Ruby to look through the string and ## convert both Windows-style (\r\n) and old Mac-style (\r) newlines ## into the standard Unix newline (\n) ## ## File.open("output.txt", "w", universal_newline: true) do |file| ## file.write(content) ## end ## ## mixed_string = "Line one\r\nLine two\rLine three\n" ## ## Converts all \r\n and \r into \n ## clean_string = mixed_string.encode(universal_newline: true) ## ## Why Use encode Instead of gsub? ## While many developers use regular expressions like .gsub(/\r\n?/, "\n"), ## using .encode is highly preferred because: ## Edge-case Safety: It is an internal, optimized C-level implementation ## that handles mixed and broken newline edges perfectly. ## Encoding Preservation: It seamlessly preserves the existing character encoding ## (e.g., UTF-8) of your string. ## ## was - text = text.gsub( "\r\n", "\n" ) ## ## note - by default ruby on windows (automagically) translates newlines to \r\n (crlf)!!! ## thus, always use/ add universal_newline flag!!! File.open( path, 'w:utf-8', universal_newline: true ) do |f| f.write( text ) end end |
#cached?(url) ⇒ Boolean Also known as: exist?
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/webget/webcache_disk.rb', line 12 def cached?( url ) body_path = _body_path( url ) exist = File.exist?( body_path ) =begin ## not really working - check back later ### The catch on Windows ## On Windows, File.realpath does NOT normalize casing to the on-disk canonical case. ## ## note - on windows - file.exist? is case-insensitive ## use the strict: true flag if you want to enforce case-sensitive exists checks on windows!!! ## On Windows, File.realpath returns the "true" path ## as stored on the disk with the correct casing. ## If the path you provide doesn't match the casing of the real path, ## you know the match was case-insensitive. if exist && strict exist = File.realpath(body_path) == File.expand_path(body_path) end =end exist end |
#read(url) ⇒ Object
fix-fix-fix change to read_txt/read_text/read_html plus add read_blob/read_bin(ary) !!!
42 43 44 |
# File 'lib/webget/webcache_disk.rb', line 42 def read( url ) _read_utf8(_body_path( url )) end |
#read_csv(url) ⇒ Object
54 55 56 57 58 |
# File 'lib/webget/webcache_disk.rb', line 54 def read_csv( url ) txt = _read_utf8(_body_path( url )) data = CsvHash.parse( txt ) data end |
#read_json(url) ⇒ Object
48 49 50 51 52 |
# File 'lib/webget/webcache_disk.rb', line 48 def read_json( url ) txt = _read_utf8(_body_path( url )) data = JSON.parse( txt ) data end |
#read_meta(url) ⇒ Object
61 62 63 64 65 |
# File 'lib/webget/webcache_disk.rb', line 61 def ( url ) txt = _read_utf8(( url )) data = Headers.parse( txt ) data end |
#record(url, response, format:) ⇒ Object
add more save / put / etc. aliases - why? why not? rename to record_html - why? why not?
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/webget/webcache_disk.rb', line 73 def record( url, response, format: ) ### ## note - encoding_user MUST be passed along with response (wrapper) obj ## e.g. response._encoding_user = encoding ?? ## see Webget.page|text|dataset|etc. ## todo/check - use rel_path or local_path or such?? save_path = url_to_path( url ) body_path = _body_path( url ) = ( url ) ## is _body_path + ".meta.txt" ## make sure path exits FileUtils.mkdir_p( File.dirname( body_path ) ) puts "[cache] saving #{body_path}..." ## todo/check: verify content-type - why? why not? ## note - for now respone.text always assume (converted) to utf8!!!!!!!!! if format == 'json' _write_utf8( body_path, JSON.pretty_generate( response.json )) x_encoding = nil ## for now do not track; always assume UTF-8 x_encoding_source = nil x_encoding_valid = nil x_ascii_only = nil x_8bit = nil x_utf8_replace = nil else ## html, txt or csv _write_utf8( body_path, response.text ) x_encoding = response._text_encoding x_encoding_source = response._text_encoding_source x_encoding_valid = response._text_encoding_valid # true|false or nil (undef) x_ascii_only = response._text_ascii_only x_8bit = response._text_8bit x_utf8_replace = response._text_utf8_replace end ### fix-fix-fix -- add support for binary/image formats ## e.g. bin|gif|jpg|etc - why? why not? #### ## get file size in bytes ## or use File.stat( body_path ).size (using File::Stat) ?? x_size = File.size( body_path ) ## todo/check: ## do headers also need to converted (like text) if encoding is NOT utf-8 ??? #### add our own custom headers first!! ## change x-save to x-filename or ?? ## change to x-7bit-only or x-ascii7bit or x-ascii7bit-only or ?? ## change x-size to x-bytesize or ?? ## change x-8bit to ??? ### start w/ comment line ### uncomment - http status - why? why not? buf = String.new buf << "# fetched on #{Time.now.utc}\n" buf << "# HTTP/#{response.version} #{response.status.code} #{response.status.}\n" buf << "\n" buf << "x-url: #{url}\n" buf << "x-encoding: #{x_encoding}\n" if x_encoding buf << "x-encoding-source: #{x_encoding_source}\n" if x_encoding_source buf << "x-encoding-valid: #{x_encoding_valid}\n" if x_encoding_valid buf << "x-ascii-only: #{x_ascii_only}\n" if x_ascii_only buf << "x-8bit: #{x_8bit}\n" if x_8bit buf << "x-utf8-replace: #{x_utf8_replace}\n" if x_utf8_replace buf << "x-save: #{save_path}\n" buf << "x-size: #{x_size}\n" buf << "x-format: #{format}\n" ## e.g. json|html|csv|etc. buf << "\n" # iterate all response headers response.headers.each do |key, value| buf << "#{key}: #{value}\n" end _write_utf8( , buf ) end |
#rewrite_path(host, req_path) ⇒ Object
todo/fix - make rewrite_path configurable "pipeline" lets you auto-add more rewriters and keep this code "generic" move rewriters "downstream" into "userland" ??
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/webget/webcache_disk-rewrite.rb', line 11 def rewrite_path( host, req_path ) ### special "prettify" rule for weltfussball ## /eng-league-one-2019-2020/ => /eng-league-one-2019-2020.html ### todo/fix - move rules downstream to user - why? why not? if host.include?( 'uefa.com' ) || host.include?( 'kicker.de' ) || host.include?( 'kicker.at' ) if req_path.end_with?( '/' ) req_path = "#{req_path[0..-2]}.html" else puts "ERROR: expected request_uri for >#{host}< ending with '/'; got: >#{req_path}<" exit 1 end elsif host.include?( 'weltfussball.de' ) || host.include?( 'worldfootball.net' ) if req_path.end_with?( '/' ) req_path = "#{req_path[0..-2]}.html" else puts "ERROR: expected request_uri for >#{host}< ending with '/'; got: >#{req_path}<" exit 1 end elsif host.include?( 'tipp3.at' ) req_path = req_path.sub( '.jsp', '' ) # shorten - cut off .jsp extension ## change ? to -I- ## change = to ~ ## Example: ## sportwetten/classicresults.jsp?oddsetProgramID=888 ## => ## sportwetten/classicresults-I-oddsetProgramID~888 req_path = req_path.gsub( '?', '-I-' ) .gsub( '=', '~') req_path = "#{req_path}.html" elsif host.include?( 'fbref.com' ) req_path = req_path.sub( 'en/', '' ) # shorten - cut off en/ req_path = "#{req_path}.html" # auto-add html extension elsif host.include?( 'football-data.co.uk' ) req_path = req_path.sub( 'mmz4281/', '' ) # shorten - cut off mmz4281/ req_path = req_path.sub( 'new/', '' ) # shorten - cut off new/ elsif host.include?( 'football-data.org' ) ## req_path = req_path.sub( 'v2/', '' ) # shorten - cut off v2/ ## flattern - make a file path - for auto-save ## change ? to -I- ## change / to ~~ ## change = to ~ req_path = req_path.gsub( '?', '-I-' ) .gsub( '/', '~~' ) .gsub( '=', '~') req_path = "#{req_path}.json" elsif host.include?( 'api-sports.io' ) req_path = req_path.gsub( '?', '-I-' ) .gsub( '&', '~~' ) ### check if & present? .gsub( '=', '~') req_path = "#{req_path}.json" elsif host.include?( 'api.cryptokitties.co' ) ## for now always auto-add .json extensions e.g. ## kitties/1 => kitties/1.json ## cattributes => cattributes.json req_path = "#{req_path}.json" else ## no special rule end req_path end |
#url_to_path(str) ⇒ Object
helpers
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/webget/webcache_disk.rb', line 172 def url_to_path( str ) ## map url to file path uri = URI( str ) ## URI() same as URI.parse() ## note: ignore scheme (e.g. http/https) ## and post (e.g. 80, 8080, etc.) for now ## always downcase for now (internet domain is case insensitive) host_dir = uri.host.downcase ## "/this/is/everything?query=params" ## cut-off leading slash and ## convert query ? = ## check if [1..] is sames as [1..-1] req_path = rewrite_path( host_dir, uri.request_uri[1..] ) page_path = "#{host_dir}/#{req_path}" page_path end |