2011年8月30日火曜日

落ち着いた

色々試行錯誤して、Flask(というかwerkzeug)のデバッグ用shellと、Geventwebsocketとくっつけた上で、ソースが更新されたら鯖プロセスをリロード、ってとこまでできた。


やりたかったのは
・ともかくwebsocket. これが動く環境
・んでもframeworkないとどうしようもないからなんかのframeworkとのセット
・django使ってたけどこの際だからFlask
・Flaskのinteractiveなデバッグ環境に惚れたからあれが動くようにする
・djangoとかみたいに、ソース書き替えたらリロードは必須だと思ったのでこれも動くように

てとこ。
ハマリぽいんとは
・pythonのwebsocketっていうと選択肢が狭くて、GEvent系のGEventwebsocketか、pywebsocketぐらいしかない
・んでもpywebsocketはmod-pythonだからウンコ。
・GEventwebsocketは、GEventだからこれまた癖がある
・GEventはシングルスレッドで動くから、threading.Threadとか使ってauto reloadさせようとしてもうごかない
・GEventのwebsocketがFlaskとかでつつんでしまうと応答しなくなるからWSGIServer.serve_foreverあたりはむき出しにしておかないといけない

とかまぁ、それは多くのハマリポイント。
色々やったら動いたからまぁよし。
これで快適デバッグ環境とwebsocketとFlaskだ。
pycassaについてはあまり触れない。






誰か後からきたひとのためにソース張っておく。
きれいでは無い。清書前だけどとりあえず動くだけのソース。
質問は返答できると思う。


C:\Users\myr>c:\Python26\python.exe c:\prj\groovy\src\groovy\autoreload.py c:\prj\groovy\src\groovy\groovy.py
みたいにうつと、 autoreload.pyがsubprocess.Popenで groovy.py起動しますんで。
subprocessが死なないのはwinだとそういうものなのか?やだなぁ

autoreload.py
# -*- coding: utf-8 -*-
import os
import sys
import subprocess
import time

def file_times(path):
for root, dirs, files in os.walk(path):
# print 'rdf ', root, dirs, files
for file in files:
filename = os.path.join(root, file)
# print 'load,', filename
if filename[-4:] in ('.pyc', '.pyo'):
filename = filename[:-1]
yield os.stat(filename).st_mtime

def print_stdout(process):
stdout = process.stdout
if stdout != None:
print stdout

# We concatenate all of the arguments together, and treat that as the command to run
command = ' '.join(sys.argv[1:])

# The path to watch
path = 'c:\\prj\\groovy\\src'

# How often we check the filesystem for changes (in seconds)
wait = 1

# The process to autoreload
process = subprocess.Popen(command, shell=True)

# The current maximum file modified time under the watched directory
last_mtime = max(file_times(path))


while True:
max_mtime = max(file_times(path))
# print "max_mtime", max_mtime
print_stdout(process)
if max_mtime > last_mtime:
last_mtime = max_mtime
print 'Restarting process.', process
# print "now :",process.poll()
while not process.poll():
try:
process.kill()
except:
pass
process = subprocess.Popen(command, shell=True)
time.sleep(wait)
groovy.py
# -*- coding: utf-8 -*-
from time import gmtime, strftime
import os
import sys
import subprocess
import time
import random
from gevent import pywsgi
import gevent
from geventwebsocket.handler import WebSocketHandler
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
from werkzeug.debug import DebuggedApplication

# demo app

# configuration
DATABASE = '/tmp/flaskr.db'
DEBUG = True
SECRET_KEY = 'development key'
USERNAME = 'admin'
PASSWORD = 'default'


def handle(ws):
""" This is the websocket handler function. Note that we can dispatch based on path in here, too."""
if ws.path == '/echo':
while True:
m = ws.wait()
if m is None:
break
ws.send(m)

elif ws.path == '/data':
for i in xrange(10000):
ws.send("0 %s %s\n" % (i, random.random())) #ここは通信エラーが起きることがある.
print "0 %s %s\n" % (i, random.random())
gevent.sleep(0.1)



#Flash作る. Tornadoとかでもできると思われる.
app = Flask(__name__)
app.debug = True
d_app = DebuggedApplication(app, True)
#app.config.from_object(__name__)
#app.config.from_envvar('FLASKR_SETTINGS', silent=True)
def groovy(environ, start_response):
path = environ["PATH_INFO"]
if path == "/":
return d_app(environ, start_response)
elif path == '/test':
start_response("200 OK", [('Content-Type', 'text/plain')])
return ["blaat"]
elif path == "/data":
handle(environ['wsgi.websocket'])
else:
return d_app(environ, start_response)




@app.route("/")
def hello():
app.logger.debug('AAAAAAAAAA value for debugging???')
# return "Hello World!!!!"
return render_template('base.html', name="unko")


groovy_server = None
def run_groovy():
# from werkzeug.debug import DebuggedApplication
app.debug = True
# a = DebuggedApplication(app, True)
a = app
server = pywsgi.WSGIServer(('0.0.0.0', 8080), groovy, handler_class=WebSocketHandler)
groovy_server = server
server.serve_forever()
print "here"

#app.run(debug=True, port=8080)


print sys.argv[:]
print sys.executable
if __name__ == "__main__":
print "deketa"
run_groovy()



2 件のコメント:

Nariya Takemura さんのコメント...

ぬお、preタグじゃないのか..

Nariya Takemura さんのコメント...

ソース嘘でした。他のエントリーで補足しますが、これだと子プロセスしなないでポートがめつづけるのでhttp responceがかわんないです