0

My first wsgi middleware

import logging
log = logging.getLogger(__name__)
class foomid(object):
    def __init__(self, app, app_conf):
        self.app = app

    def __call__(self, environ, start_response):
        a = [str(e) for e in environ]
        a.sort()
        log.info("\n".join(a))
        response = self.app(environ, start_response)
        return response

I just want to see how to make middleware and I want to observe environ.

0

What I did for pylons app deployment.

I try to install my application created on Pylons on the Debian server that has already Apache2 + mod_wsgi + virtualenv + userdir.

What I did:

  1. creating prod.ini by copying development.ini.
  2. Change sqlalchemy.url
  3. set debug = false
  4. write a script in ~/public_html/wsgi-script as follow:
    import os
    import site
    os.environ['PYTHON_EGG_CACHE'] = "/home/myhome/egg"
    site.addsitedir("/home/myhome/wsgiapp/basa2")
    site.addsitedir("/home/myhome/pyenv/PYLONS-1/lib/python2.5/site-packages")
    
    from paste.deploy import loadapp
    APP_CONFIG = "/home/myhome/wsgiapp/basa2/prod.ini"
    application = loadapp("config:" + APP_CONFIG)
    
    
  5. I also modify this file: /home/vee/pydev/PYLONS-1/lib/python2.5/site-packages/Pylons-0.9.7rc3-py2.5.egg/pylons/wsgiapp.py by checking before the command:
    del  environ['pylons.pylons']

    following this changeset. (I use Pylons 0.9.7rc3)

The procedures above are just conclusion. I did a lot of trial and error. I also restart Apache web server (I must not have to do). By the ways, it works now.

0

xmlrpc ด้วย python บน apache

xmlrpc ด้วย python บน apache ผ่าน mod_wsgi. ใช้ xmlrpc บน python เขียนง่ายมากเลย ทั้ง client และ server ดูตัวอย่างจาก http://docs.python.org/library/simplexmlrpcserver.html ได้

แต่ว่า simple server นี้เป็น standalone server แล้วผมก็เจอปัญหาอีกว่า พอเรียกใช้จากเครื่องอื่น ที่ไม่ใช่เครื่องเดียวกันแล้วมั้นช้าๆ ชอบกล เลยเปลี่ยนไปใช้ wsgi-xmlrpc แทน มีคนเขียนไว้ให้แล้วด้วยดีจัง ^_^.

ทีแรกผมก็ลงโปรแกรมจาก easy_install เลย ใช้ easy_install wsgi_xmlrpc อะไรทำนองนี้ก็ลงได้ แต่เล่นไปเล่นมาเจอปัญหาภาษาไทย ก็เลยเอา source code จาก svn trunk ที่ google code มาใช้แทน ถึงตอนนี้ก็ยังใช้ได้ดีอยู่. (วิธีใช้ mod_wsgi กับ userdir เข้าไปดูที่ http://blog.vee-u.com/2008/06/18/mod_wsgi_userdir_ubuntu/ ได้
และ http://blog.vee-u.com/tag/wsgi/ ได้)

เพื่อที่ผมจะได้เอาไว้ดูเองในภายหลังด้วยจึงต้อง post ตัวอย่างสักหน่อย สมมุติ เขียน client แบบนี้

# -*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

from xmlrpclib import ServerProxy
server = ServerProxy("http://localhost/test_service.wsgi", encoding="UTF-8")
print server.test_func("ดีจ๊ะ")

พอโปรแกรมทำงานแล้วได้ผลแบบนี้

ดีจ๊ะ ^_^

เวลาเขียน server ก็เขียนประมาณนี้ใน test_service.wsgi

import site
import os

os.environ['PYTHON_EGG_CACHE'] = "/somewhere/egg"
site.addsitedir("/home/vee/pyenv/WSGI-1/lib/python2.5/site-packages")

from wsgiref import simple_server
import wsgi_xmlrpc

def test_func(txt):
   return txt + " ^_^"

application = wsgi_xmlrpc.WSGIXMLRPCApplication(methods=[test_func])

^_^

4

dict api over http

ผมอยากให้ basa-asa (ซึ่งเป็นโปรแกรมช่วยแปลภาษา เช่น ช่วยเปิด dictionary ให้ ไม่ใช่โปรแกรมแปลภาษาอัตโนมัติแบบ Google translation) เปิด dictionary ผ่าน dict protocol ได้ เพราะว่าจะได้สะดวกทั้ง dictionary ที่ download มาได้และ dictionary ของชาวบ้านที่เขาไม่ให้ download (ไม่รู้ว่าจริงๆ แล้วมีหรือเปล่า dictionary ที่ใช้ผ่าน dict protocol ได้แต่ไม่ให้ download).  แต่ว่า dict protocol นี้อาจจะเขียน javascript ไปเปิดตรงๆ ลำบากสักหน่อย มากไปกว่านั้น protocol ต่างๆ ที่ไม่ใช่ http ก็มักจะโดนปิดกั้นอย่างน่าเศร้าใจ. ด้วยเหตุผลดังกล่าวผมก็เลยทำ dicthttp ขึ้นมาเป็นตัวหุ้ม (wrapper) dict server ไว้อีกที แล้วก็แปลง ผลที่ได้เป็นแบบ json ส่งผ่าน web (http) ไป.

เวลาใช้ dict protocol เราอาจจะค้นหาคำโดยใช้ url แบบ dict://hostname/d:word:database อะไรทำนองนี้ เวลาทำ wrapper ผมก็ทำให้ใช้ประมาณนั้นคือ http://hostname/d:word:database ได้เหมือนกัน แล้วผลก็ return มาเป็น json. โดยเป็น list ของ {ชื่อ database, คำที่ใช้ค้นหา, definition}.

แบบนี้เป็นต้น

$ curl http://localhost:8000/d:computer:gcide
[{“word”: “Computer”, “def”: “Computer \\Com*put\”er\\ (k[o^]m*p[=u]t\”[~e]r), n.\n1. One who computes.\n\n2. (Computers) an electronic device for performing\ncalculations automatically. It consists of a clock to\nprovide voltage pulses to synchronize the operations of\nthe devices within the computer, a central processing\nunit, where the arithmetical and logical operations are\nperformed on data, a random-access memory, where the\nprograms and data are stored for rapid access, devices to\ninput data and output results, and various other\nperipheral devices of widely varied function, as well as\ncircuitry to support the main operations.\n\nNote: This modern sense of computer comprises the\nstored-program computers, in which multiple steps in a\ncalculation may be stored within the computer itself as\n{instructions} in a {program}, and are then executed by\nthe computer without further intervention of the\noperator. Different types of computer are variously\ncalled {analog computer}, {number cruncher,\nnumber-cruncher}, {digital computer}, and {pari-mutuel\nmachine, totalizer, totaliser, totalizator,\ntotalisator}.\n\nSyn: data processor, electronic computer, information\nprocessing system.\n[WordNet 1.5 +PJC]\n\n3. (Computers) same as {digital computer}.\n[PJC]“, “database”: “gcide”}, {“word”: “computer”, “def”: “electronic device \\electronic device\\ n.\na device depending on the principles of electronics and using\nthe manipulation of electron flow for its operation.\n[PJC]\n\nNote: Numerous electronic devices are in daily use, among\nthem the {television}, {radio}, {computer}, {robot},\n{transmitter}, {receiver}, {VCR}, {CD player}, etc.\n[PJC]“, “database”: “gcide”}]

ขยุกขยุยไปบ้าง … แต่มันก็เป็นแบบนี้ล่ะ

นอกจากคำสั่ง define ใน dict protocol แล้วก็ใช้ match ได้ด้วย แบบ http://hostname/m:คำ:database:strategy ได้ด้วย. แต่เหมือน n ยังใส่ไม่ได้ หาไม่เจอว่าจะใส่ตรงไหนของ dictclient (python).

โปรแกรม dicthttp อยู่ที่ http://code.google.com/p/basaasa/source/browse/#svn/trunk/dicthttp ใช้ wsgi พื้นๆ

1

Django + userdir + mod_wsgi

แน่นอนเป็นภาคต่อมาจาก Turbogears + userdir + mod_wsgi. Django ก็ใช้ท่าคล้ายๆ Turbogears เปลี่ยน prefix นิดๆ หน่อยก็ใช้ได้แล้ว

หลังจากศึกษาวิธีใช้จาก http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango ผมสร้าง django.wsgi ไว้ใน /home/veer/public_html/wsgi-scrips อีกเช่นเคย

import os, sys
sys.path.append('/home/veer/Develop/django/mysite') # site ของผมเก็บไว้ที่นี้
sys.path.append('/home/veer/Develop/django')
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()

ที่ลำบากนิดหน่อยคือพวก media ทั้งหลาย ผมก็ copy มาไว้ใน home เลย (ขนาดประมาณ 300KiB กว่าๆ)

cp -r /usr/share/python-support/python-django/django/contrib/admin/media/ /home/veer/public_html/django_admin_media

แล้วก็ไปแก้ settings.py ใน /home/veer/Develop/django/mysite นิดหน่อย แก้ ADMIN_MEDIA_PREFIX จากเท่ากับ ” เป็น ADMIN_MEDIA_PREFIX = ‘/~veer/django_admin_media/’

เท่านี้ก็ไปเปิดเว็บดูก็ใช้ได้ (ถ้าผมไม่ได้ลืมเขียนอะไรไปนะ)

พรุ่งนี้น่าจะได้ลอง Pylons กับ WSGIDaemonProcess username user=username อะไรทำนองนี้.

2

mod_wsgi + userdir + Turbogears

อาจจะดูคลั่งๆ หน่อยแต่ mod_wsgi + userdir + Turbogears ก็ใช้ได้แล้ว. ด้วยพื้นฐานจากการใช้ mod_wsgi+userdir , การใช้ mod_wsgi กับ Turbogears และ การใช้ mod_wsgi กับ Turbogears แบบ non-root-mount. ก็แทบจะไม่ต้องทำอะไรแล้ว :-P.

แค่ copy ไฟล์ tg.wsgi ที่เคยอยู่ใน /home/veer/tg/tgapp/apache ไปไว้ใน /home/veer/public_html/wsgi-scripts/ แล้วก็แก้ prod.cfg ใน /home/veer/tg/tgapp นิดหน่อยที่ server.webpath ให้เปลี่ยนเป็น server.webpath=”/~veer/wsgi-scripts/tg.wsgi” เท่านี้ก็ใช้ซะงั้น.

สำหรับ Turbogears แล้วสำคัญมาที่ต้องใช้ tg.url เวลาเขียน URL ไม่ใส่ URL เอาเองตรงๆ (แบบที่ผมเคยทำ) … ไม่งั้นเวลามา deploy แบบนี้ก็แก้กันอ้วก :-P.

0

ทำให้ Turbogears + mod_wsgi ใช้งานกับ non-root mounted app

วิธีทำจริงๆ ก็อ่านจาก http://www.lucasmanual.com/mywiki/TurboGears#head-57ee578707aa057229eb1171a8e4aeb553bd6d3a มาเกือบหมด. แต่ว่าเขียนเสียหน่อยเพื่อความต่อเนื่องจากที่เขียนไว้เดิม. เริ่มจากแก้ /home/veer/tg/tgapp/apache/tg.wsgi:

import sys
sys.path.append('/home/veer/tg/tgapp')
sys.stdout = sys.stderr

import os
os.environ['PYTHON_EGG_CACHE'] = '/home/veer/tg/python-eggs'

import atexit
import cherrypy
import cherrypy._cpwsgi
import turbogears

# ข้างล่างเปลี่ยนไปใช้ fullpath แทนที่จะเขียน prod.cfg หรือ dev.cfg เฉยๆ
turbogears.update_config(configfile="/home/veer/tg/tgapp/prod.cfg", modulename="tgapp.config")
turbogears.config.update({'global': {'server.environment': 'production'}})
turbogears.config.update({'global': {'autoreload.on': False}})
turbogears.config.update({'global': {'server.log_to_screen': False}})

import tgapp.controllers

cherrypy.root = tgapp.controllers.Root()

if cherrypy.server.state == 0:
    atexit.register(cherrypy.server.stop)
    cherrypy.server.start(init_only=True, server_class=None)

application = cherrypy._cpwsgi.wsgiApp

จริงๆ แล้วก็แก้บรรทัดเดียว :-P … แต่ตอนลองทำงงเหมือนกัน

แล้วก็ไปสร้าง server.log ใน /home/veer/tg/tgapp/server.log อันนี้มีก็ทำแบบชั่วคราวๆ :-P (อีกแล้ว)

(อยู่ใน /home/veer/tg/tgapp)
touch server.log
chmod 777 server.log

ตามด้วยแก้ /home/veer/tg/tgapp/prod.cfg ทีแรกมันไม่มีให้แก้ก็เลยต้อง copy sample-prod.cfg มา

เพิ่ม server.webpath=”/first” เข้าไป (จริงมี # server.webpath=”” อยู่แล้ว ก็แค่เอา shape ออกแล้วใส่ /first ลงไป) แก้ path ของ server.log แบบนี้ args=”(‘/home/veer/tg/tgapp/server.log’,)” จากที่เดิมเขียนไว้ว่า args=”(‘server.log’,)”

ตามด้วยแก้ /etc/apache2/mod-enabled/mod-wsgi.conf เดิมเขียนไว้ว่า
WSGIScriptAlias / /home/veer/tg/tgapp/apache/tg.wsgi
ก็แก้เป็น
WSGIScriptAlias /first /home/veer/tg/tgapp/apache/tg.wsgi
เพื่อเปลี่ยนที่ mount

แล้วก็ restart apache ( /etc/init.d/apache restart ) จากนั้นพอเข้าไปดูใน localhost/first ก็ได้ผลตามต้องการ

… ต่อไปก็เป็น userdir T_T (เหมือนหา doc ไม่ค่อยเจอด้วย :-P)