Skip to content

longguikeji/arkfbp-javascript

Repository files navigation

1. ArkFBP-JavaScript

ArkFBP-JavaScript是一个ArkFBP的JS的实现。

2. 简介 Introduction

ArkFBP是一个基于Flow-Based Programming的一个开发框架,目前有JavaScript,Python,Golang等几个不同版本。

3. 快速上手 QuickStart

3.1. 安装环境 SetUp

3.1.1. 安装Arkfbp Tooling Install ArkFBP Tooling

  1. 下载arkfbp预编译文件 Download precompiled arkfbp cli binary

    wget https://github.com/arkfbp/arkfbp/releases/download/0.0.3-rc/arkfbp-darwin

  2. 给二进制文件赋予执行权限 Give the execution permission

    chmod +x arkfbp

  3. 将文件移动到系统PATH目录下 Move the arkfbp cli to the OS Path

    move arkfbp-darwin /usr/local/bin/arkfbp

3.1.2. 安装VScode ArkFBP扩展 Install VSCode ArkFBP Extension

  1. 下载扩展文件 Download VSCode Extension File

    https://github.com/arkfbp/arkfbp/releases/download/0.0.3-rc/arkfbp-0.0.3.vsix

  2. 安装扩展文件 Install the arkfbp Extension

    https://vscode-docs.readthedocs.io/en/stable/extensions/install-extension/

3.2. 创建第一个项目 Create your first project

arkfbp create --type server --language javascript --name helloworld

3.3. 构建项目 Build the project

3.4. 运行项目 Launch the project

3.4.3. 以WEBServer的方式启动 Run as the WEBServer

3.4.4. 启动单条流 # Run individual flow

3.5. 项目目录结构

用arkfbp cli工具(https://github.com/longguikeji/arkfbp)创建一个js项目后,项目主体代码均在src目录中。

src //源代码根目录,@
    databases //数据库的定义
    flows //流,所有流存放的目录
    models //ORM的数据库配置,由CLI工具自动生成
    routes //路由,定义所有开放的API接口
    testFlows //测试流,所有测试流存放的目录

所有flow都应该创建在flows目录中。

3.6. flow的结构

  1. 每一个flow都由一个目录组成,目录名即为流的名字。
  2. 在flow的根目录下的index.js文件中,定义了该流的『图』。
  3. flow目录下有nodes目录,其中存放所有该流所包含的节点定义。
  4. 每个节点都是一个js文件,用面向对象的方式继承自某个基础节点。

3.7. 流程图的定义

import { Flow } from 'arkfbp/lib/flow'
import { Graph } from 'arkfbp/lib/graph'
import { StartNode } from 'arkfbp/lib/StartNode'
import { StopNode } from 'arkfbp/lib/StopNode'

import { AddVendorNode } from './nodes/addVendorNode'

export class Main extends Flow {

    createNodes() {
        return [
            {
                cls: StartNode,
                id: '1',
                next: '2',
            },
            {
                cls: AddVendorNode,
                id: '2',
                next: '3',
            },
            {
                cls: StopNode,
                id: '3',
            },
        ]
    }

    createGraph() {
        const g = new Graph()
        g.nodes = this.createNodes()
        return g
    }

}

createNodes方法中,return的数据中包含了图的定义。个我们统一定义为 flow chart params,节点的流程图参数

3.7.5. 流程图参数

参数名 类型 含义 示例
cls Class 节点类型 cls: StartNode
cls: xxxxNode(xxxNode为某个Node的子类)
id String 当前节点id id: '1'
id: 'start'
next String 下一个节点的id next: 'stop'
next: '1'

一些特殊节点会有特殊的参数,如LoopNode的body。参见每个节点说明。

3.8. 「流」级别的全局变量

一个能在流内任意节点读写的变量,this.$state. 该变量不能直接使用,通过各种方法来进行读写。

主要用来跨节点传输数据

函数 参数 功能 示例
commit() function 修改state变量 this.$state.commit(state => {
    state.a = 1;
    state.b = 2;
    return state;
} )
fetch() 获取最新的state变量 const a = this.$state.fetch().a

4. 基础节点用法

  1. 节点的用法,需要先继承基础节点,然后确定该节点的参数与重载函数,最后在流程图中定义好该节点的流程图参数即可。
  2. 所有节点都有一个共同的重载函数run,作为节点运行的主函数。
  3. run函数的返回值会成为该节点的outputs,即下一个节点的inputs
  4. 节点参数仅支持静态值,对节点内部如this.inputs或this.$state等值的访问都只能在函数中进行。

4.9. 开始节点(StartNode)

4.9.6. 流程图参数

[cls,id,next]

4.9.7. 节点参数

4.9.8. 重载函数

函数名 描述 是否必须重载 示例
run() 作为节点运行主函数,默认功能是将inputs直接返回 一般不用,可在此函数中做一些对数据的预处理。
参考[FunctionNode]

4.10. 结束节点(StopNode)

4.10.9. 流程图参数

[cls,id,next]

4.10.10. 节点参数

4.10.11. 重载函数

函数名 描述 是否必须重载 示例
run() 作为节点运行主函数,默认功能是将inputs直接返回 一般不用,可在此函数中完成对流的返回值的最后整理。
参考[FunctionNode]

4.11. 函数节点(FunctionNode)

4.11.12. 流程图参数

[cls,id,next]

4.11.13. 节点参数

4.11.14. 重载函数

函数名 描述 是否必须重载
run() 作为节点运行主函数

示例:

import { FunctionNode } from 'arkfbp/lib/functionNode'

export class CaseNode extends FunctionNode {
    async run() {
      	const data = this.inputs.a
        data.name = this.$state.fetch().name
      	this.$state.commit( state=>{
        	state.count ++;
          return state;
        })
        return data
    }
}

4.12. 条件节点(IFNode)

4.12.15. 流程图参数

[cls,id]

注意:IFNode没有next

参数名 类型 含义 示例
positiveNext String 当expression返回值为true时,会运行的下一个节点id positiveNext:'4'
negativeNext String 当expression返回值为false时,会运行的下一个节点id negativeNext: 'stop'

4.12.16. 节点参数

4.12.17. 重载函数

函数名 描述 是否必须重载
run() 作为节点运行主函数
condition() 条件,返回bool值, 默认返回true
positive() 条件满足的时候执行
negative() 条件不满足的时候执行

示例:

import { IFNode } from 'arkfbp/lib/ifNode'

export class MyIFNode extends IFNode {

  	condition(){
    	return this.inputs.a === 1
    }

    positive() {
        return {'error': 0}
    }

    negative() {
        return {'error': -1}
    }
}

4.13. Switch节点(SwitchNode)

实现多条件分支的逻辑,满足任一条件后,剩余的部分将不会被执行

4.13.18. 流程图参数

cls,id
注意:SwitchNode没有next

参数名 类型 含义 示例
route [] 是个数组,每一项即为一个条件 {
```cls: MySwitchNode,
id: "1",
route: [
{
'condition': 'condition1',
'positive': 'positive1',
'negative': 'negative1',
'next': '2',
},
{
'condition': 'condition2',
'positive': 'positive2',
'negative': 'negative2',
'next': '3',
},
{
'condition': 'condition3',
'positive': 'positive3',
'negative': 'negative3',
'next': '4',
},
]
}```

4.13.19. 节点参数

4.13.20. 重载函数


示例:

import { SwitchNode } from 'arkfbp/lib/switchNode'

export class MySwitchNode extends IFNode {

    condition1() {
        return this.inputs.a === 1
    }

    positive1() {
        // put any logic here
    }

    negative1() {
        // put any logic here
    }

    condition2() {
        return this.inputs.a === 2
    }

    positive2() {
        // put any logic here
    }

    negative2() {
        // put any logic here
    }

    condition3() {
        return this.inputs.a === 3
    }

    positive3() {
        // put any logic here
    }

    negative3() {
        // put any logic here
    }

}

4.14. API节点(APINode)

4.14.21. 流程图参数

[cls,id,next]

4.14.22. 节点参数

参数名 类型 是否必须 描述 示例
mode string 请求方式,可选值:direct,proxy, 默认值为direct mode: proxy(通过ArkOS的APIserver发送请求)
mode: direct(直接向目标发送请求)
url string 请求地址 url: 'https://www.x.com/api'
method string 请求方式,可选值:
post,get等Http协议支持的选项
method:POST
method:GET
auth null 签名,保留字段,预计会用于用户验证
headers any | null http请求的headers headers = {
'Accept': 'application/json;charset=utf-8',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0',
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
}
params any | null http请求的参数,可由buildParams()函数代替 params: 'a=1&b=2'

4.14.23. 重载函数

函数名 描述 是否必须重载
run() 作为节点运行主函数
buildParams() 构建参数 否,优先级比params高,注意不要重复使用

示例:

import { APINode } from 'arkfbp/lib/apiNode'

export class PostAPINode extends APINode {
    mode = 'direct'
    url = 'https://sms.yunpian.com/v2/sms/tpl_batch_send.json'
    method = 'post'
    headers = {
        'Accept': 'application/json;charset=utf-8',
        'X-Requested-With': 'XMLHttpRequest',
        'User-Agent': 'Mozilla/5.0',
        'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
    }

    buildParams() {
        console.log('PostApiNode:',this.inputs)
        return this.inputs
    }
}

4.15. 循环节点(LoopNode)

4.15.24. 流程图参数

[cls,id,next]

参数名 类型 含义 示例
body Number String 循环体的下一个节点,从这个节点开始的后续节点都是在循环体内

4.15.25. 节点参数

4.15.26. 重载函数

函数名 描述 是否必须重载
initStatement() 初始化状态(i = 0)
conditionStatement() 条件判断(i<10)
postStatement() 末尾状态(i++)
process() 循环程序,返回值会被作为body循环体的输入

示例:

import { LoopNode } from 'arkfbp/lib/loopNode'

export class LoopSendNode extends LoopNode {

    _i = 0

    initStatement() {
        this._i = 0
    }

    conditionStatement() {
        return this._i < this.inputs.mobiles.length
    }

    postStatement() {
        this._i++
    }

    process() {
        const data = 'mobile='+this.inputs.mobiles[this._i]
        return data
    }
}

4.16. 流节点(FlowNode)

4.16.27. 流程图参数

[cls,id,next]

4.16.28. 节点参数

参数名 类型 是否必须 描述 示例
flow Flow 需要运行的流

4.16.29. 重载函数

函数名 描述 是否必须重载
buildInputs() 构建运行flow时的输入

示例:

import { TriggerFlowNode } from 'arkfbp/lib/triggerFlowNode'
import {Main as FooBarFlow} from '@/flows/foo/bar'

export class RunFooBarFlowNode extends TriggerFlowNode {

    flow = FooBarFlow

  	buildInputs(){
      	return {a: 1}
    }

}

4.17. 测试节点(TestNode)

4.17.30. 流程图参数

[cls,id,next]

4.17.31. 节点参数

参数名 类型 是否必须 描述 示例
flow Flow 需要测试的流的类
start String 测试目标流的起始节点id
,为空则代表从流的第一个节点开始
start: '5'
stop String 测试目标流的结束节点id
,为空则代表直到流结束
stop:'6'

4.17.32. 重载函数

函数名 描述 是否必须重载
setUp() 在所有case执行前执行,可以用来准备测试数据
tearDown() 在所有case执行完后执行,可以用来清理测试数据,比如删除操作
test{CaseName}() case,测试用例 - testA(){}
test{CaseName}SetUp() 在对应case之前执行,用来准备测试数据 - testASetup()
test{CaseName}TearDown() 在对应case之后执行,用来清理测试数据 - testATearDown()

示例:

import { TestNode } from 'arkfbp/lib/testNode'
import {Main as RegisterFlow} from '@/flows/main/register'
import {Config} from '@/models/config'
import assert from 'assert'

export class Node1 extends TestNode {

    flow = RegisterFlow

    setUp() {
    }

    tearDown() {
      	//在所有case执行完后执行
        console.info('tearDown')
    }

    testASetUp(){
        // 在testA之前执行
        //在所有case执行前执行
        this.inputs = {
            appid : 'demoapp',
            keys: [{
                key: 'testkey1',
                discription: 'testkey1 description11'
            },{
                key: 'testkey2',
                discription: 'testkey2 description22'
            }]
    		}
    }
   	testATearDown(){
        // 在testA之后执行
    }
    async testA() {
        const config = await Config.findOne({
            where: { appid: 'demoapp', key: 'testkey1' }
        })
        assert.strictEqual('testkey1',config.key)
    }

    async testB() {
        const config = await Config.findOne({
            where: { appid: 'demoapp', key: 'testkey2' }
        })
        assert.strictEqual('testkey2',config.key)
    }
}

4.18. 空节点(NopNode)

什么也不做

4.18.33. 流程图参数

cls,id,next

4.18.34. 节点参数

4.18.35. 重载函数

About

面向流的可视化编程Javascript implementation of the ArkFBP Framework, with NodeJS & Browser supported, productivity as the first citizen.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •