大道至简,新一代企业应用无栈开发

平台之上,一种语言,可视化、脚本化、全端一体化开发

远端运行环境

脚本发送到远端环境运行,包括用于桌面开发的桌面助手,以及用于自动化脚本的站点机器人

.. contents:: .. sectnum::

通过前端组件在桌面运行 (联机桌面脚本)

把联机脚本,下发到桌面助手运行。出于安全考虑,联机桌面脚本需要签名。

用户可以在前端点击浏览器的某个链接按钮触发联机脚本::

view.native.call_script(script_name, 
    args=None, kw=None, onduplicate='warn', on_return_url='')

参数说明:

  • script_name: 脚本的完整名字,例如 zopen.aaa:bbb

  • args: <tuple/list/None> 参数列表

  • kw: <dict/None> 命名参数列表

  • disable_upgrade:如果桌面助手版本太低,是否禁止升级(默认会升级)

  • onduplicate: 任务重复时的处理策略,可选值 warn/run/ignore:

    • warn: 冒泡提示用户任务重复,并且不运行
    • run: 仍然运行重复的任务
    • ignore: 不提示用户,且不运行
  • on_return_url: 处理脚本运行结果的URL。指定此参数则脚本将同步(阻塞式)运行,并将脚本返回的结果POST给这个URL。

    • 如果运行成功,脚本的返回结果经过 JSON dumps 之后存放在result字段;
    • 如果运行出错,traceback信息经过 JSON dumps 之后存放在traceback字段;

发送给连接的用户运行(联机服务脚本)

也可以在后台给指定用户发送脚本执行指令::

remote = root.get_remote(receiver='')

其中 receivers 运行脚本的机器人。

可以在远端异步调用一个脚本::

taskid = remote.call_script_async(
    'zopen.xxx:xxxx',
    args=(),
    kw={}, 
    callback_url='',
    error_callback_url ='',
)

其中:

  • args/kw: 运行这个脚本传入的参数

  • callback_url: 脚本运行成功的回调URL。脚本的返回结果会以POST方式发送给这个地址,包含以下参数:

    • result: 脚本的返回值 经过JSON序列化 后的内容
  • error_callback_url: 设置脚本出错后的回调URL。如果脚本运行出错:

    • 没有设置error_callback_url,则会通过系统通知渠道,告知发送脚本的用户(调用 root.get_remote() 时的当前用户);

    • 如果有设置error_callback_url,则会发送一个POST请求到这个地址,包含以下数据:

      • traceback: 脚本发生错误时捕获的错误堆栈信息(字符串)

callback_url和error_callback_url可用下面地址生成::

obj.api_url(requset, script_name, auth_=True)

直接调用远端 (联机服务脚本)

先用token来链接远端::

remote = root.get_remote(host='', port=0, token="")

可以继续异步调用::

taskid = remote.call_script_async(
    'zopen.xxx:xxxx',
    args=(),
    kw={}, 
    callback_url='',
    error_callback_url ='',
)

也可以同步调用::

remote.call_script('zopen.xxx:xxxx', args=(), kw={})

联机脚本函数

如果联机脚本太复杂,或者有可重用的逻辑,可以封装到独立的脚本中,调用方法为::

call_script(script_name, *args, **kwargs)

例如,以下代码会调用 zopen.xx:yy 脚本::

call_script('zopen.xx:yy', a, b, c d=1, e=2)

call_script 会实时下载指定脚本来运行,下载失败将抛出 ScriptDownloadError ,带有一个 error 属性保存了原始的异常实例。

如果调用的脚本运行时抛出了异常,call_script 将不会做任何处理,直接抛出。

注意,只能调用受信任的脚本。

远端运行环境类库

可用的类库

除了标准库,shell脚本还可以用如下第三方库:

  • requests
  • reportlab
  • PyPDF2
  • PyCrypto
  • certifi
  • watchdog
  • python-dateutil
  • psutil
  • sh (只在 Linux/Mac 系统可用)
  • fabric2
  • fabric

可以用 install_addon 安装插件::

install_addon('http://xxx/edo_fabric.py', '0.1')

或者使用 require(package_name) 安装额外的第三方包

  1. 调用 pip 安装额外的第三方包到 ~/edo_assistent/addons 目录中。

  2. 调用完成后即可使用 import 来导入安装的第三方包。如果 addons 目录中已经安装了指定的包,则不会重复安装。

    • 此功能在 Windows 平台上,需要独立安装的 Python 2 和 pip 工具,并且 pip 工具需要在 PATH 中。
    • 如果使用 Linux 版本的 deb 包安装SiteBot,此功能也需要独立安装的 Python 2 和 pip 工具。
    • 如果指定的包需要编译或其他预处理才能安装,机器上需要安装有对应的编译器或预处理工具,且要保证可被 pip 调用。

utils: 工具模块

包含的主要函数:

  • getmtimt(path) 获取本地文件的修改时间。内部会对异常的时间做修复处理。
  • get_file_md5(path) 获取本地文件的 MD5
  • get_file_size(path) 获取本地文件大小
  • get_human_ltime(dt) 获取 datetime 对象的友好形式。
  • get_human_size(size) 获取文件大小的友好形式。
  • get_numbered_filename(name) 获取编号后的文件名,例如 file-1.txt 会返回 file-2.txt
  • get_site_public_key(wo_server, account, instance, token=None) 获取指定站点的公钥(优先使用缓存的公钥)。
  • get_message_client(token=None, server=None, account=None, instance=None) 获取一个 edo_client.MessageClient 实例。
  • get_upload_client(token=None, server=None, account=None, instance=None) 获取一个 edo_client.UploadClient 实例。
  • get_wo_client(token=None, server=None, account=None, instance=None) 获取一个 edo_client.WoClient 实例。

内置的变量和方法

worker_db: 当前任务的数据 ...................................... 包括了访问服务器的信息,接口与 dict 完全一致。需要持久化到磁盘时调用 .sync() 方法即可。

包含如下一组固定变量:

  • server: 指定wo服务器
  • oc_server: 指定 oc 服务器
  • account: 指定账户
  • instance: 指定实例
  • token: 当前用户的oauth认证token

report(text) 通知脚本发送者 ...................................... 一个快捷函数,用于发送一条通知消息给下发脚本的用户。

如果需要向下发脚本的用户发一个通知消息,可以如下代码示例::

report('Hi, this notification comes from the running script worker.')

acquire_lock(name, timeout=0, description=None) 加锁 ............................................................... 锁可以用于协调多个脚本任务的资源占用。当一个任务已经加锁之后,其他任务再加同一把锁会失败。

例如,以下代码示例尝试加一把名为 test-lock 的锁,如果超过两分钟加锁还未成功,将会显示一个错误消息::

try:
    acquire_lock('test-lock', timeout=120)  # 此方法会阻塞,直到锁获取成功或超时(由 timeout 指定)
except LockAcquireTimeout:
    ui_client.message('加锁', '超过 2 分钟仍未加锁成功')

如果没有指定 timeout,则默认为 0。此时如果加锁失败会直接抛出 LockAcquireFailure 错误。

release_lock(name) 解锁 ............................................................... 以下代码示例将会解开一把名为 test-lock 的锁,如果失败将显示一个消息::

try:
    release_lock('test-lock')
except LockReleaseFailure:
    ui_client.message('解锁', '解锁失败')

safe_call(cmd, shell=False, timeout=10*60) 调用外部程序 ............................................................... 如果外部程序没有在指定时间内完成,将会被杀死(包括调用产生的所有子进程),是作为 subprocess.call 的一个替代。

以下代码将会打开 python 解释器,并在 10 秒后杀死解释器进程::

safe_call('python', timeout=10)

异常类

LockAcquireTimeout 加锁超时 ............................................................... 具有如下属性:

  • worker_id 任务 ID
  • lock_name 锁的名字
  • timeout_value 按秒计算的超时时间

LockAcquireFailure 加锁失败 ............................................................... 具有与 LockAcquireTimeout 一致的属性

LockReleaseFailure 解锁失败 ............................................................... 具有与 LockAcquireTimeout 一致的属性

ScriptDownloadError 下载脚本失败 ............................................................... 具有如下属性

  • script_name 脚本名字
  • error 抛出的原始异常实例