<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>days of linnchord &#187; 软件开发</title>
	<atom:link href="http://linnchord.net/archives/category/develop/feed" rel="self" type="application/rss+xml" />
	<link>http://linnchord.net</link>
	<description>南台静坐 : : :</description>
	<lastBuildDate>Thu, 03 Nov 2011 02:22:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>PIL MemoryError with uWSGI</title>
		<link>http://linnchord.net/archives/843.html</link>
		<comments>http://linnchord.net/archives/843.html#comments</comments>
		<pubDate>Thu, 03 Nov 2011 02:20:33 +0000</pubDate>
		<dc:creator>linnchord</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[PIL]]></category>
		<category><![CDATA[uwsgi]]></category>

		<guid isPermaLink="false">http://linnchord.net/?p=843</guid>
		<description><![CDATA[用PIL库处理图片，作缩略图的时候需要先裁减为正方形，再比例缩小，当裁减时不定报错。 img = img.transform((r,r), Image.EXTENT, area) #ERROR File "/usr/local/lib/python2.7/dist-packages/PIL/ImageFile.py", line 231, in load_prepare self.im = Image.core.new(self.mode, self.size) MemoryError google PIL+MemoryError，主要提到2个可能错误。一个是PIL库本身ctype代码问题，一个是传递裁减范围为负值导致内存问题。仔细检查了一下，都没有异常。后来考虑到上面的代码为创建新图像时内存错误，直接调整了uwsgi参数。 -M -p 2 --no-orphans --logdate --chmod-socket=666 --uid admin --gid admin --limit-as 384 --harakiri 60 --max-requests 2000 [--limit-as]参数从256调整到384，系统恢复正常。 反思查找原因，发现图片文件虽然不大仅3M+，但是该图片像素巨大为4096*5210，将该图片转换为BMP，有60M+。估计库在处理图片裁减时会将jpg文件重新读取为完整位图，再考虑到操作位图消耗和程序本身需要的内存空间，原设定256M限制肯定不足了，需要设定更大。 目前程序运行在一个虚拟机上，内存2G……看来需要尽快切换主机了……]]></description>
			<content:encoded><![CDATA[<p>用PIL库处理图片，作缩略图的时候需要先裁减为正方形，再比例缩小，当裁减时不定报错。</p>
<pre class="brush:python">
img = img.transform((r,r), Image.EXTENT, area)

#ERROR
File "/usr/local/lib/python2.7/dist-packages/PIL/ImageFile.py", line 231, in load_prepare
    self.im = Image.core.new(self.mode, self.size)
MemoryError
</pre>
<p><a target="_blank" href="http://www.google.com.hk/search?q=PIL%2BMemoryError">google PIL+MemoryError</a>，主要提到2个可能错误。一个是PIL库本身ctype代码问题，一个是传递裁减范围为负值导致内存问题。仔细检查了一下，都没有异常。后来考虑到上面的代码为创建新图像时内存错误，直接调整了uwsgi参数。</p>
<pre class="brush:shell">-M -p 2 --no-orphans --logdate --chmod-socket=666 --uid admin --gid admin --limit-as 384 --harakiri 60 --max-requests 2000</pre>
<p>[--limit-as]参数从256调整到384，系统恢复正常。</p>
<p>反思查找原因，发现图片文件虽然不大仅3M+，但是该图片像素巨大为4096*5210，将该图片转换为BMP，有60M+。估计库在处理图片裁减时会将jpg文件重新读取为完整位图，再考虑到操作位图消耗和程序本身需要的内存空间，原设定256M限制肯定不足了，需要设定更大。</p>
<p>目前程序运行在一个虚拟机上，内存2G……看来需要尽快切换主机了……</p>
]]></content:encoded>
			<wfw:commentRss>http://linnchord.net/archives/843.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>install gevent on macosx lion with macport lib</title>
		<link>http://linnchord.net/archives/834.html</link>
		<comments>http://linnchord.net/archives/834.html#comments</comments>
		<pubDate>Thu, 27 Oct 2011 07:56:48 +0000</pubDate>
		<dc:creator>linnchord</dc:creator>
				<category><![CDATA[mac]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://linnchord.net/?p=834</guid>
		<description><![CDATA[我的os大部分包使用macport管理，直接pip安装存在问题 sudo pip install gevent 出错提示 command ‘gcc-4.2′ failed with exit status 1 下载源代码包安装 wget http://pypi.python.org/packages/source/g/gevent/gevent-0.13.6.tar.gz tar -zxvf gevent-0.13.6.tar.gz cd gevent-0.13.6 sudo python setup.py install -I /opt/local/include -L /opt/local/lib #指定默认的macport路径]]></description>
			<content:encoded><![CDATA[<p>我的os大部分包使用macport管理，直接pip安装存在问题</p>
<pre class="brush:shell">sudo pip install gevent</pre>
<p>出错提示</p>
<pre class="brush:shell">command ‘gcc-4.2′ failed with exit status 1 </pre>
<p>下载源代码包安装</p>
<pre class="brush:shell">
wget http://pypi.python.org/packages/source/g/gevent/gevent-0.13.6.tar.gz
tar -zxvf gevent-0.13.6.tar.gz
cd gevent-0.13.6
sudo python setup.py install -I /opt/local/include -L /opt/local/lib #指定默认的macport路径
</pre>
]]></content:encoded>
			<wfw:commentRss>http://linnchord.net/archives/834.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flask下的session认证和cache header设置</title>
		<link>http://linnchord.net/archives/826.html</link>
		<comments>http://linnchord.net/archives/826.html#comments</comments>
		<pubDate>Sat, 17 Sep 2011 01:34:11 +0000</pubDate>
		<dc:creator>linnchord</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[Flask]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://linnchord.me/?p=826</guid>
		<description><![CDATA[Flask是个非常优秀的python microframework，基于Werkzeug、Jinja 2，使用非常方便，性能也非常不错，最近公司创业新项目一直在用。 这里和大家分享2个简单的decorator，分别用于session认证和响应头cache设置 # -*- coding: utf-8 -*- """ lib/decorator.py ~~~~~~~~~~~~~~ some decorator defined :author: linnchord@gmail.com :date:2011-8-4 """ from functools import wraps from flask import session, redirect, url_for, flash, request, make_response from models.user import User from util import helper def login_required(f): @wraps(f) def do(*args, **kwargs): if 'userId' not in session: #cookie自动登录机制 token=request.cookies.get('auto_login') if token: [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://flask.pocoo.org/">Flask</a>是个非常优秀的python microframework，基于Werkzeug、Jinja 2，使用非常方便，性能也非常不错，最近公司创业新项目一直在用。</p>
<p>这里和大家分享2个简单的decorator，分别用于session认证和响应头cache设置</p>
<pre class="brush:python">
# -*- coding: utf-8 -*-
"""
    lib/decorator.py
    ~~~~~~~~~~~~~~

    some decorator defined 

    :author: linnchord@gmail.com
    :date:2011-8-4

"""
from functools import wraps
from flask import session, redirect, url_for, flash, request, make_response
from models.user import User
from util import helper

def login_required(f):

    @wraps(f)
    def do(*args, **kwargs):
        if 'userId' not in session:
            #cookie自动登录机制
            token=request.cookies.get('auto_login')
            if token:
                userId, token = token.split('_')
                user = User.get_user_by_id(userId)
                from matrix import app
                if user and helper.md5(str(user.id) + user.password + app.config['SECURIY_KEY'])==token:
                    session['userId']=user.id
                    session['phone']=user.phone
                    session['nickName']=user.nickName
                else:
                    return redirect('/logout')
            else:
                return redirect('/')

        return f(*args, **kwargs)

    return do

def no_cache_header(f):

    @wraps(f)
    def do(*args, **kwargs):
        response = make_response(f(*args, **kwargs))
        response.headers['pragma'] = 'no-cache'
        response.headers['Cache-Control'] = 'no-cache, must-revalidate'
        return response
    return do
</pre>
<p>使用很简单方便</p>
<pre class="brush:python">
@app.route('/user/follow/<int:userId>', methods=['GET'])
@login_required
@no_cache_header
def follow_user(userId,appId):
    pass
</pre>
<p>需要注意的是@no_cache_header修饰应该放在最后，否则逻辑无法正确完成。这个修饰经常用于ajax响应，因为……坑爹的IE总是要缓存第一次请求结果。</p>
<p>这个session auto login机制有个问题，他的auto login cookie始终是不变的，长期使用会有一定安全隐患。更安全的方法是用户每次登录生成一个security key来进行hash，不过这样对于经常换浏览器甚至操作系统的人会造成一定障碍。例如我……经常使用chrome/firefox/ie，还在mac/win下切来切去，某个小说网站每次切了就得重新登录，让我很蛋疼……</p>
]]></content:encoded>
			<wfw:commentRss>http://linnchord.net/archives/826.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PIL 1.1.7 install on ubuntu</title>
		<link>http://linnchord.net/archives/815.html</link>
		<comments>http://linnchord.net/archives/815.html#comments</comments>
		<pubDate>Mon, 29 Aug 2011 14:51:49 +0000</pubDate>
		<dc:creator>linnchord</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[PIL]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://linnchord.me/?p=815</guid>
		<description><![CDATA[PIL虽然可以通过pip安装，但是不好用，各种调用需要的依赖都没有，需要手动安装。 过程如下 #清除系统上现有库 python版本自行替换 sudo rm -rf /usr/lib/python2.7/site-packages/PIL sudo rm /usr/lib/python2.7/site-packages/PIL.pth #安装依赖包 sudo apt-get install libjpeg8 libjpeg8-dev libfreetype6 libfreetype6-dev liblcms1-dev #下载 wget http://effbot.org/downloads/Imaging-1.1.7.tar.gz tar -zxvf Imaging-1.1.7.tar.gz cd Imaging-1.1.7/ python setup.py build_ext -i sudo python setup.py install #安装后如果发现安装的包没有正确支持可进行如下操作 sudo ln -s /usr/lib/x86_64-linux-gnu/libfreetype.so /usr/lib/ sudo ln -s /usr/lib/x86_64-linux-gnu/libz.so /usr/lib/ sudo ln -s /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/]]></description>
			<content:encoded><![CDATA[<p>PIL虽然可以通过pip安装，但是不好用，各种调用需要的依赖都没有，需要手动安装。</p>
<p>过程如下</p>
<pre class="brush:shell">
#清除系统上现有库 python版本自行替换
sudo rm -rf /usr/lib/python2.7/site-packages/PIL
sudo rm /usr/lib/python2.7/site-packages/PIL.pth

#安装依赖包
sudo apt-get install libjpeg8 libjpeg8-dev libfreetype6 libfreetype6-dev liblcms1-dev

#下载
wget http://effbot.org/downloads/Imaging-1.1.7.tar.gz
tar -zxvf Imaging-1.1.7.tar.gz
cd Imaging-1.1.7/
python setup.py build_ext -i
sudo python setup.py install

#安装后如果发现安装的包没有正确支持可进行如下操作
sudo ln -s /usr/lib/x86_64-linux-gnu/libfreetype.so /usr/lib/
sudo ln -s /usr/lib/x86_64-linux-gnu/libz.so /usr/lib/
sudo ln -s /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/
</pre>
]]></content:encoded>
			<wfw:commentRss>http://linnchord.net/archives/815.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flask SessionStore by redis with msgpack serialized</title>
		<link>http://linnchord.net/archives/797.html</link>
		<comments>http://linnchord.net/archives/797.html#comments</comments>
		<pubDate>Thu, 18 Aug 2011 16:45:03 +0000</pubDate>
		<dc:creator>linnchord</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[Flask]]></category>
		<category><![CDATA[msgpack]]></category>
		<category><![CDATA[redis]]></category>

		<guid isPermaLink="false">http://linnchord.me/?p=797</guid>
		<description><![CDATA[参考老外代码写了个用于Flask框架的基于redis的session实现，采用msgpack进行序列化。 # -*- coding:utf-8 -*- """ lib/RedisSessionStore.py ~~~~~~~~~~~~~~ Flask, session store in redis ref by https://gist.github.com/994937 :author: linnchord@gmail.com :date:2011-08-04 """ import redis from flask import Flask, request, session, json from werkzeug.contrib.sessions import Session, SessionStore import msgpack class RedisSessionStore(SessionStore): def __init__(self, key_prefix=None, host='127.0.0.1', port=6379, dbindex=1, expire=1800): SessionStore.__init__(self) self.redis = redis.Redis(host,port,dbindex) self.key_prefix = key_prefix self.expire = expire [...]]]></description>
			<content:encoded><![CDATA[<p>参考老外代码写了个用于Flask框架的基于redis的session实现，采用msgpack进行序列化。</p>
<pre class="brush:python">
# -*- coding:utf-8 -*-
"""

lib/RedisSessionStore.py
~~~~~~~~~~~~~~

Flask, session store in redis

ref by https://gist.github.com/994937

:author: linnchord@gmail.com
:date:2011-08-04

"""
import redis
from flask import Flask, request, session, json
from werkzeug.contrib.sessions import Session, SessionStore
import msgpack

class RedisSessionStore(SessionStore):

    def __init__(self, key_prefix=None, host='127.0.0.1', port=6379, dbindex=1, expire=1800):
        SessionStore.__init__(self)

        self.redis = redis.Redis(host,port,dbindex)
        self.key_prefix = key_prefix
        self.expire = expire

    def save(self,session):
        key = self._get_session_key(session.sid)
        data = msgpack.Packer().pack(dict(session))
        #print "set session {0}:{1}".format(key, data)
        self.redis.setex(key, data, self.expire)

    def delete(self, session):
        key = self._get_session_key(session.sid)
        self.redis.delete(key)

    def get(self, sid):
        key = self._get_session_key(sid)
        data = self.redis.get(key)
        if data is not None:
            self.redis.setex(key, data, self.expire)
            un = msgpack.Unpacker()
            un.feed(data)
            data = un.unpack()
        else:
            data = {}

        return self.session_class(data, sid, False)

    def _get_session_key(self,sid):
        key = self.key_prefix + sid
        if isinstance(key, unicode):
          key = key.encode('utf-8')
        return key

    @staticmethod
    def init_app(app):
        app.session_store = RedisSessionStore(
            app.config['SESSION_KEY_PREFIX'],
            app.config['SESSION_REDIS_HOST'],
            app.config['SESSION_REDIS_PORT'],
            app.config['SESSION_REDIS_DB'],
            app.config['SESSION_LIFETIME']
        )
        app.session_key = app.config['SESSION_KEY']

class SessionMixin(object):

  __slots__ = ('session_key', 'session_store')

  def open_session(self, request):
    sid = request.cookies.get(self.session_key, None)
    if sid is None:
        return self.session_store.new()
    else:
        return self.session_store.get(sid)

  def save_session(self, session, response):
    if session.should_save:
        self.session_store.save(session)
        response.set_cookie(self.session_key, session.sid)
    return response

class MyFlask(SessionMixin, Flask): pass

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

HOW TO USE

app = MyFlask(__name__)
RedisSessionStore.init_app(app)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

APP CONFIG:

SESSION_REDIS_HOST = '127.0.0.1'
SE
