Created
September 23, 2011 14:05
-
-
Save tana/1237420 to your computer and use it in GitHub Desktop.
mikutter icon memory cache
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # -*- coding: utf-8 -*- | |
| require File.expand_path('utils') | |
| miquire :core, 'environment' | |
| miquire :mui, 'skin' | |
| require 'gtk2' | |
| require 'net/http' | |
| require 'uri' | |
| require 'digest/md5' | |
| require 'thread' | |
| require 'observer' | |
| # メモリキャッシュ対応用メモ | |
| # cache:filename の場合はメモリキャッシュ | |
| # メモリキャッシュ Hash + 容量制限 | |
| class MemoryCache | |
| @@hash = {} | |
| @@keys = [] | |
| @@size = 0 | |
| def MemoryCache.get(filename) | |
| @@hash[filename] | |
| end | |
| def MemoryCache.set(filename, value) | |
| size = value.length | |
| @@keys << [filename, value.length] | |
| @@size = @@size + size | |
| if (@@size > 1000000) # 1000000はサイズ制限 | |
| @@size = @@size - @@keys[0][1] | |
| @@hash.delete(@@keys.shift[0]) | |
| #puts "memory cache deleted (@@hash.length=#{@@hash.length}, @@size=#{@@size})" | |
| end | |
| @@hash[filename] = value | |
| end | |
| def MemoryCache.exist?(filename) | |
| return @@hash.key?(filename) | |
| end | |
| end | |
| class File | |
| @@old_exist = File.method(:exist?) | |
| def File.exist?(filename) | |
| if (filename.index("cache:") == 0) | |
| MemoryCache.exist?(filename) | |
| else | |
| return @@old_exist.call(filename) | |
| end | |
| end | |
| @@old_expand = File.method(:expand_path) | |
| def File.expand_path(filename) | |
| if (filename.index("cache:") == 0) | |
| filename | |
| else | |
| @@old_expand.call(filename) | |
| end | |
| end | |
| end | |
| module FileTest | |
| @@old_exist = FileTest.method(:exist?) | |
| def FileTest.exist?(filename) | |
| if (filename.index("cache:") == 0) | |
| MemoryCache.exist?(filename) | |
| else | |
| return @@old_exist.call(filename) | |
| end | |
| end | |
| end | |
| def create_pixbuf(filename, width, height) | |
| if (filename.index("cache:") == 0) | |
| # メモリキャッシュから読み込み | |
| loader = Gdk::PixbufLoader.new | |
| loader.set_size(width, height) | |
| loader.write MemoryCache.get(filename) | |
| loader.close | |
| pixbuf = loader.pixbuf | |
| return pixbuf | |
| else | |
| return Gdk::Pixbuf.new(filename, width, height) | |
| end | |
| end | |
| module Gtk | |
| class WebIcon < Image | |
| include Observable | |
| attr_reader :loading_thread | |
| #ICONDIR = "#{Environment::CONFROOT}icons#{File::SEPARATOR}" | |
| ICONDIR = "/media/MYLINUXLIVE/mikutter/iconcache/" | |
| @@image_download_lock = Mutex.new | |
| @@m_iconlock = Mutex.new | |
| @@l_iconring = Hash.new{ Mutex.new } | |
| @@pixbuf = @@oldpixbuf = Hash.new{ Hash.new{ Hash.new } } | |
| @@pixbufcache_lastcleartime = Time.now | |
| def initialize(img, width=48, height=48) | |
| @loading_thread = nil | |
| if(img.index('http://') == 0) | |
| filename = WebIcon.get_filename(img) | |
| if not(File.exist?(filename)) then | |
| @loading_thread = WebIcon.iconring(img, [width, height]){ |pic| | |
| if destroyed? | |
| notice "object destroyed" | |
| else | |
| self.pixbuf = pic | |
| self.changed | |
| self.notify_observers end } | |
| filename = File.expand_path(MUI::Skin.get("loading.png")) | |
| end | |
| img = filename | |
| end | |
| super(WebIcon.genpixbuf(img, width, height)) | |
| end | |
| def self.remove_cache(*args) | |
| end | |
| def self.get_icon_pixbuf(img, width=48, height=width, &onload) | |
| type_strict img => String | |
| if(img.index('http://') == 0) | |
| filename = WebIcon.get_filename(img) | |
| if not(File.exist?(filename)) then | |
| iconring(img, [width, height], &onload) | |
| filename = File.expand_path(MUI::Skin.get("loading.png")) end | |
| img = filename end | |
| WebIcon.genpixbuf(img, width, height) end | |
| # URL _img_ の画像を読み込む。読み込みが終わったら、ブロックにGdk::Pixbufを取って呼び出す | |
| # Gdk::Pixbufは _dim_ で指定された寸法(px)に収まるようにリサイズされて渡される | |
| # ロードをしているThreadを返す | |
| def self.iconring(img, dim=[48,48], &onload) | |
| Thread.new{ | |
| WebIcon.background_icon_loader(img, dim, &onload) } end | |
| def self.get_filename(url) | |
| ext = (File.extname(url).split("?", 2)[0] or File.extname(url)) | |
| File.expand_path(self.icondir + Digest::MD5.hexdigest(url) + ext) | |
| end | |
| def self.pixbuf_cache_get(filename, width, height) | |
| if @@pixbuf[filename][width][height] | |
| @@pixbuf[filename][width][height] | |
| elsif @@oldpixbuf[filename][width][height] | |
| @@pixbuf[filename][width][height] = @@oldpixbuf[filename][width][height] end end | |
| def self.pixbuf_cache_set(filename, pixbuf) | |
| if @@pixbufcache_lastcleartime < Time.now | |
| notice 'pixbuf cache refreshed' | |
| @@pixbufcache_lastcleartime = Time.now + 60 * 30 | |
| @@oldpixbuf = @@pixbuf | |
| @@pixbuf = Hash.new{ Hash.new{ Hash.new } } end | |
| @@pixbuf[filename][pixbuf.width][pixbuf.height] = pixbuf end | |
| def self.genpixbuf(filename, width=48, height=48) | |
| result = nil | |
| if FileTest.exist?(File.expand_path(filename)) | |
| begin | |
| @@m_iconlock.synchronize{ | |
| result = pixbuf_cache_get(filename, width, height) | |
| if not(result.is_a?(Gdk::Pixbuf)) | |
| result = pixbuf_cache_set(filename, | |
| #Gdk::Pixbuf.new(File.expand_path(filename), width, height) | |
| create_pixbuf(File.expand_path(filename), width, height) | |
| ) | |
| end | |
| } | |
| rescue Gdk::PixbufError | |
| #puts "PIXBUFERROR!!!!!!!" | |
| result = Gdk::Pixbuf.new(File.expand_path(MUI::Skin.get('notfound.png')), width, height) end end | |
| result end | |
| def self.background_icon_loader(img, dim=[48,48], &onload) | |
| filename = WebIcon.local_path(img) | |
| Delayer.new(Delayer::LATER){ | |
| Lock.synchronize{ | |
| onload.call(self.genpixbuf(filename, *dim)) } } end | |
| # アイコンキャッシュのファイル名をフルパスで返す | |
| def self.local_path(url) | |
| @@l_iconring[url].synchronize{ | |
| filename = WebIcon.get_filename(url) | |
| if not(FileTest.exist?(filename)) then | |
| begin | |
| res = Net::HTTP.get_response(URI.parse(url)) | |
| if(res.is_a?(Net::HTTPResponse)) and (res.code == '200') then | |
| # ここでファイルに保存している | |
| # ここをメモリ上に入れる処理に書き換える | |
| #open(filename, 'wb'){ |f| | |
| # f.write res.body | |
| #} | |
| MemoryCache.set("cache:" + filename, res.body) | |
| filename = "cache:" + filename | |
| else | |
| #puts "NOTEXIST!!!!!!!" | |
| filename = MUI::Skin.get("notfound.png") | |
| end | |
| rescue Timeout::Error, StandardError => e | |
| #puts "TIMEOUT!!!!!" | |
| #puts "----------------" | |
| #puts e.message | |
| #puts e.backtrace | |
| #exit | |
| filename = MUI::Skin.get("notfound.png") | |
| end | |
| end | |
| filename | |
| } | |
| end | |
| def self.icondir | |
| if not(FileTest.exist?(File.expand_path(ICONDIR))) | |
| FileUtils.mkdir_p File.expand_path(ICONDIR) | |
| end | |
| ICONDIR | |
| end | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment