基于Webpy实现服务器策略模型

jopen 9年前

现在我们来谈一些(黑)科技,希望能给大家一些启发和帮助。现在我有一个策略文件addition.policy:

acquire: first_str -> a  apply: concat_with_time(a) -> a  acquire: first_str -> b  apply: concat_with_time(b) -> b    await: return_result  apply: join_line(a, b) -> result  yield: result

还有一个委托函数的Python源码addition.delegate.py:

# addition.delegate.py    import time    def concat_with_time(s):      return s + time.ctime()        def join_line(s1, s2):      return s1 + "\n" + s2 + "\n"

这是什么语法?但是我们大抵都能明白它想干什么:先后获取两个字符串,分别将它们和时间拼接在一起,然后在获取return_result后回传结果。然后呢?然后我们有一些Web接口,简单地用web.py编写main.py:

#!/usr/bin/env python  import web  from policy import resume  class first_str_view:   def GET(self):    resume("addition", "first_str", value = web.input()["value"])    return ""  class second_str_view:   def GET(self):    resume("addition", "second_str", value = web.input()["value"])    return ""  class return_result_view:   def GET(self):    return resume("addition", "return_result")  urls = [   '/first_str/?', first_str_view,   '/second_str/?', second_str_view,   '/return_result/?', return_result_view,  ]  if __name__ == "__main__":   app = web.application(urls, globals())   app.run()

就算没用过web.py的人都大抵能明白这个结构是什么意思了,除了那个resume有点不知所谓之外,但是结合上面的那个addition.policy,好像看上去也挺合理,大概就是从acquire处断开,然后得到输入后继续执行那个policy。如你所料:

$ ./main.py 9999 &  [1] 19121  http://0.0.0.0:9999/  $ curl "http://localhost:9999/first_str?value=First+Record+"  $ curl "http://localhost:9999/second_str?value=Second+Record+"  $ curl "http://localhost:9999/return_result"  First Record Sat Sep  5 15:59:25 2015  Second Record Sat Sep  5 15:59:28 2015

这样可以解决很多问题。比如在用户更变邮箱的时候,用户先提交新邮箱,然后还要等等他什么时候去邮箱里收验证邮件,这样更变邮箱的操作才完成。还有一些更麻烦的操作,整个流程下来,要收几次输入,然后才能真正地输入成功存进数据库。举个例子,你可以简单地写一个策略文件,让它控制整个流程,接口只需要跟用户打交道就好了:

assert: is_authenticated()  acquire: modify_email -> address  execute: send_verification_mail(address)  await: email_verified  execute: save_user_info("email", address)

不得不说这种模型有点像是协程(coroutine),但是不是用它来实现的,毕竟:一次请求完成了整个线程大大小小都结束了哪里还有协程啊对吧。这也不是WebSocket能解决的:比如收验证邮件,都在第二个地方连接了,哪里还有Socket可言。这里针对的情况是,两次连接之间的时间段是 断开 的情况。

实现思路

主要是在模拟恢复执行的时候能较好地恢复原有上下文,在Python有exec的情况下,想办法生成可配合执行Python代码是一个不错的选择。恢复执行有这些步骤:

  • 解析策略文件

  • 从持久存储设备中反序列化变量

  • 找到断点应该在哪里,按照这个位置:

    • 载入模块(如上面的time)

    • 载入上下文变量(如上面的a,b)

    </li>
  • 一直执行到下一个await点,退出执行

  • </ul>

    /* 具体的实现明天看有没有时间再更 */

    附: 语法清单

    digit  := '0' | ... | '9'  underscore := '_'  symbol ::=   letter | underscore   { letter | underscore | digit }  command ::= symbol  variable ::= symbol  string ::=   '"' {   [ 0x00 | ... | 0x21 | 0x23 | ... | 0x7f | '\n' | '\r' | '\"' | '\\' ]   } '"'  value ::= string | variable  parameter ::= value  parameter-list ::=   '('   [ parameter-list ',' parameter | parameter ]   ')'  argument ::= symbol [ parameter-list ]  argument-list ::= argument-list argument | argument  command-line ::=   command ':'   argument-list   [ '->' variable ]  policy ::=   policy \n command-line | command-line
    原文 http://segmentfault.com/a/1190000003708486