วันอังคารที่ 31 มีนาคม พ.ศ. 2552

Ubuntu set static ip address

เนื่องจาก เวลาที่เราต้องการนำ web หรือ application ไปไว้ยัง server เพื่อเป็น service บางอย่างนั้นจำเป็นต้องให้ ip address ของเครื่อง server ที่เราต้องการนั้น ไม่ถูกเปลี่ยนแปลง เมื่อมีการ shutdown หรือเปลี่ยนแปลง ระบบเครือข่าย ในส่วนของ ubuntu ก็จะมีวิธีการประมาณนี้ครับ

เข้าไปแก้ไข file ที่ทำการ setup ip โดยจำเป็นต้องใช้สิทธิ root ครับ ตามด้านล่างนี้ ...

$ sudo vi /etc/network/interfaces

เมื่อเข้าไปครั้งแรกจะเห็นแค่ สองบรรทัด ...

auto lo
iface lo inet loopback

ก็ทำการเพิ่ม

auto eth1
iface eth1 inet static
address 192.168.123.248
gateway 192.168.123.254
netmask 255.255.255.0
network 192.168.123.0
broadcast 192.168.123.255

ในส่วนของ eth1 ในที่นี้จะเป็นเหมือนตัวแทน hardware wireless ในการเชื่อมต่อของเครื่อง
ในส่วนของ address นั้น จะเป็น ip address ที่เราต้องการ force ไว้
ส่วนที่เหลือ นั้นก็เป็นองค์ประกอบ network องค์กร ครับ ผมสมติให้เป็น 192.168.123.xxx ก็ไปไล่เปลี่ยนเอา

สุดท้ายก็ทำการ restart network ด้วย command ...

sudo /etc/init.d/networking restart

น่าจะมี log ขึ้นประมาณนี้

* Reconfiguring network interfaces... [ OK ]

ถ้าไม่ขึ้น error ก็ ...
เป็นอันเสร็จเรียบร้อย


sudo vi /etc/resolv.conf


edit if can't get internet


nameserver 192.168.123.254



end config...

วันพฤหัสบดีที่ 26 มีนาคม พ.ศ. 2552

python receive http post text stream by turbogears2

ในส่วน ของ web controller ของ turbogear นั้น โดยปกติก็จะรับ เป็น kw อยู่แล้ว คือรับ name:value ตาม format

    @expose('templatename')
    def servicename(self, **kw):
        print 'data key, value :', kw
        return dict(page='templatename')

ในกรณีที่เราต้องการ รับ text stream เช่น client อาจ post xml มาเพื่อ information บางอย่างก็จะต้อง ดึงจาก body แทน code ก็จะเพิ่มประมาณนี้ครับ

import pylons

    @expose('templatename')
    def servicename(self, **kw):
        body = pylons.request.body
        print 'data text stream : %s' % body
        return dict(page='templatename')

python http post text stream

ในกรณีที่เราต้องการ post text string หรือ data บางอย่าง เช่น xml information บางอย่าง
ในส่วนของ การ post ส่วนใหญ่จะเป็นในกรณี name:value โดยตัวอย่าง format จะเป็นประมาณ
http://localhost:8080web?name=uname&data=udata
name:value จะเป็น name:uname , data:udata

แต่กรณีที่เราต้องการ post text อย่างเดียว จะเป็นการ post body ตัวอย่างด้านล่าง

http://localhost:8080/web
body = '<xml><auth><user>userxy</user><pass>xxxyyy</pass></auth><data>test data stream.</data></xml>'

data ในส่วนของ body จะไม่ถูกต่อท้าย และจะไม่มี name:value

code ตัวอย่าง

import httplib

def post(url='', data=''):
    print ' url post : %s ' % url
    print ' data post : %s ' % data
    try:
        ufull = url.replace('http://', '')
        x = ufull.find('/')
        h = httplib.HTTP(ufull[:x])
        h.putrequest('POST', ufull[x:])
        h.putheader('content-type', 'text/xml')
        h.putheader('content-length', str(len(data)))
        h.endheaders()
        h.send(data)
        errcode, errmsg, headers = h.getreply()
        res = h.file.read()
    except Exception, ex:
        raise ex
    return res

if '__main__' == __name__:
    u = 'http://localhost:8080/web'
    d = '<xml><auth><user>userxy</user><pass>xxxyyy</pass></auth><data>test data stream.</data></xml>'
    res = post(url=u, data=d)
    print 'response post : %s' % res
---------------------------------

วันพุธที่ 25 มีนาคม พ.ศ. 2552

python one line code style

python เป็นภาษา script นั่นคือ ส่วนใหญ่จะมี syntex ที่ค่อยข้างอ่านง่าย และกระชับ และใช้งานได้ทันที
การเขียน คำสั่งเล็ก ๆ ในบรรทัดเกียวก็จึงเป็นเรื่องง่าย

ตัวอย่าง code 1
mstr = 'data1,data2  ,  data3,'
l = [m.strip() for m in mstr.split(',') if '' != m.strip()]
print l
output:

['data1', 'data2', 'data3']

# ตัวอย่างเป็นการแยก data ออกจากกันด้วยเครื่องหมาย ',' return เป็น list และตัดช่องว่างออก
# strip() คำสั่งตัด space
# split() คำสั่งแยก string เป็น array ด้วย argument
# [] เครื่องหมาย การประกาศตัวแปร ให้ทำการ return เป็น array

...

วันจันทร์ที่ 23 มีนาคม พ.ศ. 2552

activemq python listener(receive) with stomp.py

ในส่วนที่แล้วมีการพูดถึง send to queue(jms activemq) ไปแล้ว ในส่วนนี้เป็นการรับข้อมูลจาก queue โดยใช้ listener คือ เมื่อมี data เข้ามายัง queue process ก็จะเริ่มทำงาน
ลักษณะการ connect จะคล้ายกับ send แต่จะต่างกันตรงที่ทำการ add class ที่ทำการ listener เข้าไปครับ ตามนี้

file name : listener.py
import time
import sys
import stomp
import logging
from threading import Thread
    
class MyListener(object):
    def on_error(self, headers, message):
        print 'received an error %s' % message
    def on_message(self, headers, message):
        print 'data of headers : %s' % str(headers)
        conn.ack(headers)
        print 'received a message %s' % message
    
class ReceiveConnection():
    def create_connect(self):
        self.conn = stomp.Connection()
    def create_listener(self):
        self.conn.add_listener(MyListener())
        self.conn.start()
        self.conn.connect()
    def __init__(self):
        self.create_connect()
        self.create_listener()
    
conn = ReceiveConnection().conn
    
class Receiver(Thread):
    def __init__(self):
        print 'receive init...'
        Thread.__init__(self)
    def run(self):
        print 'receive run...'
        try:
            conn.subscribe(destination='/queue/qname', ack='client')
            while 1:
                input = raw_input('\nplease q(Enter) to exit:\n')
                if 'q' == input:
                    break
            conn.disconnect()
        except:
            raise Exception('connection to /queue/qname fail!')
    
if "__main__" == __name__:
    print 'start test...'
    r = Receiver()
    r.setName('t_aisws')
    r.start()
    r.join()
    print 'finish test...'

ในกรณีนี้ จะเป็นแบบ ack client คือ เคลีย data จาก queue หลังจาก message listener มีการทำงาน

อีกกรณีเป็นแบบ ack auto คือ เคลีย data จาก q เมื่อรับข้อความจาก queue มาทันที
ทำการแก้ code จากข้างบน โดย บล๊อก
    #conn.ack(headers)
และ เปลี่ยนจาก
    conn.subscribe(destination='/queue/qname', ack='client')
เป็น
    conn.subscribe(destination='/queue/qname', ack='auto')
สองจุดเพียงเท่านี้ ครับ
จบ ๆ ๆ

activemq python send with stomp.py

การทำงานที่มีความซับซ้อนขึ้น และ เป็นงานประเภท transaction มาก ส่วนใหญ่จะมีการใช้ queue มาทำการแบ่ง process ต่าง ๆ ออกจากกัน ในส่วนของผู้ที่เคยเขียน java มานั้น คงรู้จัก JMS ดีกันอย่างดี หรือพอสมควร
ทำไมไม่ใช้ queue ของ python ? เนื่องด้วย ผมก็มองว่า ภาษา python เป็น ภาษาที่ใช้ในการ Integrate เป็นส่วนใหญ่ เนื่องจากแก้ไขได้ง่าย รวดเร็ว ดู code สะอาดตา แค่นี้ก็พอแล้วสำหรับ python ส่วน java นั้น จะเป็นภาษาที่มีความแข็งแรง และ เสถียรภาพค่อนข้างสูง ถ้าไม่เขียน bug เยอนะครับ
stomp คือ อะไร ? ก็คือ protocal ที่ใช้ในการติดต่อ ประเภทหนึ่ง เป็น text stream
รายละเอียดหาได้จาก http://stomp.codehaus.org/

เกริ่นพอแระ เริ่มดีกว่า

ก่อนอื่นก็ ไป download stomp.py ได้จาก
http://stomp.codehaus.org/Python

เริ่มด้วย การ send message
file name : adaptor.py
import stomp

class adaptor(object):
    def __init__(self, host='localhost', port='61613',  dest='test'):
        print 'initial connection to queue host:', host, ', port:', port, ' for:',  dest
        self.dest = dest
        try:
            self.conn = stomp.Connection([(host, int(port))])
            self.conn.start()
            self.conn.connect()
        except Exception, e:
            raise Exception('fail connect to queue', e)

    def send(self,  msg=' '):
        print 'send to queuename:', self.dest #,' ,message:', ms' ,message:', msg
        while 1:
            try:
                self.conn.send(msg, destination=self.dest)
                break
            except Exception, e:
                if isinstance(e, NotConnectedException):
                self.conn = stomp.Connection([(host, int(port))])
                self.conn.start()
                self.conn.connect()
            else:
                raise Exception('fail send data to queue', e)

#defind pool queue name in qname
adappoolqname = adaptor(host='localhost', port='61613',  dest='/queue/qname')
-------------------------------------

ในกรณีนี้เป็นการเขียน แบบ pool คือ connection ค้างไว้ เพื่อลด header ที่เกิดขึ้นในการติดต่อแต่ละครั้ง และ bug ของ activemq เอง ที่มีปัญหาจากการติดต่อ connection หลายครั้ง ถ้าสงสัยลองทำดูก็ได้ครับ

กรณีนำไปใช้งานจริง ก็จะเป็นประมาณนี้
file name : testadaptor.py
import adaptor

def testsend():
    message = 'test message to q'
    adaptor.adappoolqname.send(msg=message)

if '__main__' == name:
    testsend()
-------------------------------------

วันพฤหัสบดีที่ 5 มีนาคม พ.ศ. 2552

python decorator

Decorator เป็นการเขียน function ครอบ function เพื่อให้สามารถ แยก logic บางอย่าง เช่น validate, connection ต่าง ๆ ออกจาก business ได้

รูปแบบ ก็จะเป็นแบบนี้
function( function( function (data) ) )

function( function( function (data), condition ), condition )
และก็ไม่จำเป็นเสมอไปที่ function ข้างนอกสุดจะทำก่อน มันขึ้นอยู่ตอน เราเขียน decorator
ว่าจะให้ทำอะไรก่อนครับ ตามตัวอย่างได้ อธิบายไว้ ด้านล่าง.

---------------------------------

##Example Decorator class :

## สร้างเพื่อไว้ validate field ที่ต้องการ check ว่าต้องมีส่งมา
## ถ้าไม่มีจะ raise (แจ้ง error) กลับไป ยัง function ที่ทำการเรียก
## และเมื่อ check ว่ามีครบ ก็จะทำการเรียก function ต่อไป
class ReqParam:
    def __init__(self, *args):
        self.fields = args
    def __call__(self, f):
        fileds = self.fields
        def wrapper_func(*arg, **kws):
            dict = kws
            for filed in fields:
                if not kw.has_key(filed) or '' == kw.get(filed):
                    raise Exception('parameter '+filed+' not set.')
            dict = f(*arg, **kws)
            return dict
        return wrapper_func
## จุดสำคัญคือ การว่าในส่วนของ dict = f(*arg, **kws) จะเป็นจุดกำหนดว่าจะทำ function ก่อน
## หรือ Decorator นั้นจะจัดการอะไรบางอย่างก่อนครับ

---------------------------------

##Example function use Decorator :

## ตัวอย่างการเรียกใช้ ในที่นี้เราจะเห็นได้ว่า สามารถมี Decorator ได้มากกว่า 1
    @ReqParam('refno', 'frommsn', 'tomsn', 'msg', 'msgseq')
    def postwap(self, **kw):
        refno = kw.get('refno')
        frommsn = kw.get('frommsn')
        tomsn = kw.get('tomsn')
        msg = kw.get('msg')
        msgindex = kw.get('msgseq')
        print 'refno:', refno, 'from msn:', frommsn, ', to msn:', tomsn, ', message:', msg, ', msgseq:', msgseq
        kw.setdefault('status', 0)
        return kw
## สำหรับการเรียกใช้ function ก็เป็นการเรียก ตามปกติครับ

ไปต่อกันดีกว่าครับที่ decorator ซ้อนหลายชั้น
python multi decorator

---------------------------------

ในส่วนของการ เขียน Decorator นั้น สามารถทำได้ทั้ง แบบ def หรือ class ก็ได้ครับ
ตัวอย่าง :
http://www.python.org/dev/peps/pep-0318/
http://www.artima.com/weblogs/viewpost.jsp?thread=240808

End...

วันพุธที่ 4 มีนาคม พ.ศ. 2552

python script check and replace data key dict() empty

เนื่องจากความง่ายของ python ในการส่ง data เป็น dict ซึ่งจะสามารถทำให้ โยกย้าย หรือแก้ไข script ได้ง่าย และการจัดการ interface ก็แก้ไขน้อยครับ เมื่อเทียบกับ model
แต่ปัญหาก็เกิดขึ้น ถ้ามีการ dev เพิ่มขึ้น ทำ parameter เพิ่มขึ้น การcheck ว่าข้อมูลบางอย่างถูกส่งมาหรือไม่ก็จะเกิดขึ้นมาให้รก code เล่น แต่ก็จำเป็นต้องทำ ถ้าเราไม่ต้องการให้ค่าที่ไม่ได้ส่งมาเป็น None ออกไปยัง function ที่กำลังทำงาน

##Example code function:
my_dict = {}

def add (key):
    if my_dict.has_key(key):
        my_dict[key] += 1
    else:
        my_dict[key] = 1

if __name__ == '__main__':
    add("foo")
    add("bar")
    add("foo")
    print my_dict

## link example from : http://stackoverflow.com/questions/473099/python-how-to-check-if-a-given-index-in-a-dict-exists-yet
-------------------------

##Example code get data :
my_dict = {'a'=1, 'b'='data_b'}

a = kw.get('a') if kw.has_key('a') and int == type(kw.get('a')) else 0
b = kw.get('b') if kw.has_key('b') else ' '
c = kw.get('c') if kw.has_key('c') else 'data_c'
-------------------------

วันจันทร์ที่ 2 มีนาคม พ.ศ. 2552

FileUpload, flash upload multifile Turbogear Python

เริ่มสร้าง ปุ่มสำหรับ การ upload ทีละหลายๆ file บังเอิญว่า ความสามารถ ของ html เพียว ๆ น่าจะไม่สามารถ ถ้าจะใช้ java script ก็จะเยิ้นเย้อ เกินไปหน่ยอ ก็เลยได้ ตัวอย่างนึงมาจาก PHP แล้วก็มาแปลงเอาอ่า

โดย ที่มาจาก :
http://profile.un-no.com/ozone_me/entry-13-Flash+Upload+Multi+File.html
เป็นภาษาไทย ค่อยข้างอ่านรู้เรื่อง จะมีประโยชน์มากถ้าใช้ PHP คือเสนอให้ศึกษาจาก web นี้ก่อนนะครับ ไม่อยากพิมพ์ซ้ำ

จัดการ download :
http://www.codeproject.com/KB/aspnet/FlashUpload.aspx << ยังหา web อื่นไม่เจอครับ แล้วเลือก ที่ Download source code - 475.86 KB
เลือกเอาแค่ file เดียวครับ FlashUpload/FlashFileUpload.swf ที่เหลือไม่ได้ใช้ (.swf เป็น flash file)

แล้วเราก็มาเริ่ม modify กันเลย เพื่อให้ใช้บน Turbogear Python เวอร์ชันที่ใช้ปัจจุบันเป็น version 2
ดังนั้น path ที่แนะนำ

project_folder > package_folder > public > FlashUpload > FlashFileUpload.swf

---------------------------------------------
เพิ่มเติมในส่วน template : uploadfile.html (เพิ่มส่วนนี้ใน body ครับ)

<script language="javascript" type="text/javascript">
function UploadComplete() {
window.location = '/uploadfiles/complete';
}
</script>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="600" height="370" id="fileUpload" align="middle">
<param name="allowScriptAccess" value="sameDomain" />
<param name="movie" value="/FlashUpload/FlashFileUpload.swf" />
<param name="quality" value="high" />
<param name="wmode" value="transparent"/>
<param name="flashvars" value="&completeFunction=UploadComplete()&fileTypes=*.gif%3b+*.png%3b+*.jpg%3b+*.jpeg&fileTypeDescription=Images&totalUploadSize=2097152&fileSizeLimit=524288&uploadPage=/uploadfiles"/>
<embed src="/FlashUpload/FlashFileUpload.swf" flashvars="&completeFunction=UploadComplete()&fileTypes=*.gif%3b+*.png%3b+*.jpg%3b+*.jpeg&fileTypeDescription=Images&totalUploadSize=2097152&fileSizeLimit=524288&uploadPage=/uploadfiles" quality="high" wmode="transparent" width="600" height="370" name="fileUpload" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"/>
</object>

---------------------------------------------
เพิ่มเติมในส่วน controllers : root.py

...
...
from package.controllers.uploadfile import uploadfilesController

class RootController(BaseController):
  admin = Catwalk(model, DBSession)
  error = ErrorController()
  uploadfiles = uploadFilesController()
...
...

---------------------------------------------
เพิ่มเติมในส่วน controllers : uploadfile.py

from tg import expose
from testtg2web.lib.base import BaseController
class uploadfilesController(BaseController):

  @expose('testtg2web.templates.uploadfiles')
  def index(self):
    return dict(page='uploadfiles')

  @expose('testtg2web.templates.index')
  def testupload(self, *arg, **kw):
    f = kw['Filedata']
    upload = f.file.read()
    name = f.filename[f.filename.rfind('\\')+1:]
    file = open(name,'w')
    file.write(upload)
    file.close()
    print "testupload succedss..."
    return dict(page='index')

  @expose('testtg2web.templates.index')
  def complete(self):
    return dict(page='index')

---------------------------------------------

เผอิญไม่รู้ว่า upload เสร็จแล้วจะแสดงอะไร เลย return index เลย เหอ ๆ
จะแก้ไขเป็น return status ก็ทำ template เพิ่มนะครับ

ประมาณนี้ครับ