package wfclient import ( "encoding/base64" "encoding/json" "encoding/xml" "errors" "fmt" "net/http" "strconv" "strings" "git.qianqiusoft.com/qianqiusoft/light-apiengine/config" "git.qianqiusoft.com/qianqiusoft/light-apiengine/entitys" "git.qianqiusoft.com/qianqiusoft/light-apiengine/utils" ) type Filter struct { GroupOp string `json:"groupOp"` Rules []*FilterField `json:"rules"` } type FilterField struct { Field string `json:"field"` Op string `json:"op"` Data string `json:"data"` } type WFClient struct { endpoint string authorization string userId string username string token string domain string } var _wfendpoint = "" func init() { _wfendpoint = config.AppConfig.GetKey("wfendpoint") } /** * @brief: single instance */ func NewWFClient(c *entitys.CtrlContext) *WFClient { tk, _ := c.Ctx.Get("token") token := tk.(*entitys.Token) instance := &WFClient{} instance.endpoint = _wfendpoint instance.authorization, _ = instance.createAuthorization(token.LoginID, token.AccessToken, token.Domain) instance.userId = token.UserId instance.token = token.AccessToken HttpClientInstance().setRequestInterseptor(instance.wfReqInterseptor) return instance } /** * @brief: init * @param1 endpoint: endpoint of wf service, do not end with /; such as http://wf.qianqiusoft.com * @param2 userId: user's id * @param3 username: username * @param4 token: token * @param5 domain: domain, its default value is qianqiusoft.com * @return1: information of error, nil if everything is all right */ func (w *WFClient) Init(endpoint, userId, username, token, domain string) error { if w.token == token && w.authorization != "" { fmt.Println("wfclient token", w.token, "does already exist, token is", w.authorization) return nil } var err error = nil w.endpoint = endpoint w.userId = userId w.authorization, err = w.createAuthorization(username, token, domain) w.token = token if err != nil { return err } else { return nil } } /** * @brief: create or update the define, * @param1 defineId: id of define, if the define with id does already exist, update the define * @param2 defineName: name of define * @param3 defineDesc: description of define * @param4 diagram: diagram of define * @param5 formName: name of the form * @return1 information of error */ func (w *WFClient) CreateOrUpdateDefine(defineId, defineName, defineDesc, diagram, formName, tag, code string) ([]byte, error) { if defineId == "" { defineId = utils.NewUUID() } url := w.getFullUrl(fmt.Sprintf("api/wf_define/%s", defineId)) fmt.Println("----url:", url) params := make(map[string]string) params["define_id"] = defineId params["name"] = defineName params["descript"] = defineDesc params["data"] = diagram params["form"] = formName params["code"] = code params["tag"] = tag return HttpClientInstance().post(url, params, nil) } func (w *WFClient) FetchDefine(defineId string) ([]byte, error) { url := w.getFullUrl("api/wf_define/" + defineId) fmt.Println(url) return HttpClientInstance().get(url, nil, nil) } func (w *WFClient) FetchAllDefines() ([]byte, error) { url := w.getFullUrl("api/wf_define/all") return HttpClientInstance().get(url, nil, nil) } /** * @brief: get the flow define by tag * @param1 tag: tag of the define, split by , * @return1: content of response * @return2: information of error, nil if everything is all right */ func (w *WFClient) FetchDefinesByTag(tag string) ([]byte, error) { url := w.getFullUrl("api/wf_define/list/tag") params := make(map[string]string) params["tag"] = tag return HttpClientInstance().get(url, params, nil) } /** * @brief: get the flow design diagram * @param1 id: id of flow define * @return1: content of response * @return2: information of error, nil if everything is all right */ func (w *WFClient) FetchDesignDiagram(defineId string) ([]byte, error) { url := w.getFullUrl(fmt.Sprintf("api/wf_define/designer/%s", defineId)) return HttpClientInstance().get(url, nil, nil) } /** * @brief: create a wf instance * @param1 defineId: id of wf define * @param2 name: name of instance * @param3 formData: data to submit * @return1: content of response * @return2: error */ func (w *WFClient) CreateInstance(defineId, name, formData string) ([]byte, error) { url := w.getFullUrl("api/wf_instance") params := make(map[string]string) params["define_id"] = defineId params["name"] = name params["form_data"] = formData return HttpClientInstance().post(url, params, nil) } // 更新流程实例表单 func (w *WFClient) UpdateInstanceForm(instanceId, formData string) ([]byte, error) { url := w.getFullUrl("api/wf_instance/updateFormData") params := make(map[string]string) params["instance_id"] = instanceId params["form_data"] = formData return HttpClientInstance().post(url, params, nil) } type Choice struct { XMLName xml.Name `xml:"choice"json:"-"` Name string `json:"name"xml:"name"` Trans Transition `json:"trans"xml:"transition"` } type Transition struct { XMLName xml.Name `xml:"transition"json:"-"` Name string `json:"name"xml:"name"` To string `json:"to"xml:"to"` Points string `json:"-"xml:"points"` Conditions []*Condition `json:"conditions,omitempty"` Callback string `json:"callback"xml:"callback"` } type Condition struct { Operator string `json:"operator"xml:"operator"` DataKey string `json:"data_key"xml:"data_key"` Value string `json:"value"xml:"value"` Logic string `json:"logic"xml:"logic"` } /** * @brief: run the wf instance * @param1 instanceId: id of instance * @param2 userId: approver id * @param3 choice: choice * @param4 options: options * @return1 content of response * @return2 error */ func (w *WFClient) Run(instanceId, userId, choice, options, nextStep string, c *entitys.CtrlContext) ([]byte, error) { url := w.getFullUrl("api/wf_instance/run") params := make(map[string]string) params["instance_id"] = instanceId params["users"] = userId if choice != "" { params["choice"] = choice } if options != "" { params["opinion"] = options } if nextStep != "" { params["nextStep"] = nextStep } var RunRespInfo struct { DefineId string `json:"define_id"` InstanceId string `json:"instance_id"` DefineName string `json:"define_name"` InstanceName string `json:"instance_name"` Choices []*Choice `json:"choices"` Transition *Transition `json:"transition"` StepType string `json:"step_type"` FormData string `json:"form_data"` StepName string `json:"step_name"` ActorType string `json:"actor_type"` Executor string `json:"executor"` StartCallback string `json:"start_callback"` } bytess, err := HttpClientInstance().post(url, params, nil) if err != nil { return nil, err } //fmt.Println("------------->>>>>--------", string(bytess)) err = json.Unmarshal(bytess, &RunRespInfo) if err != nil { return nil, err } fmt.Println("------------------------------------->121", RunRespInfo.StartCallback) // 节点回调 callbacks := strings.Split(RunRespInfo.StartCallback, ",") for _, callbackKye := range callbacks { callWFCallback(callbackKye, &CallbackArg{ DefineId: RunRespInfo.DefineId, InstanceId: RunRespInfo.DefineId, DefineName: RunRespInfo.DefineName, InstanceName: RunRespInfo.InstanceName, FormData: RunRespInfo.FormData, Choice: choice, Executor: RunRespInfo.Executor, UserId: w.userId, Context: c, }) } // 连线回调 linkCallbacks := []string{} if RunRespInfo.StepType == "begin" || RunRespInfo.StepType == "normal" { linkCallbacks = strings.Split(RunRespInfo.Transition.Callback, ",") } else { for _, c := range RunRespInfo.Choices { if c.Name == choice { linkCallbacks = strings.Split(c.Trans.Callback, ",") } } } for _, callbackKye := range linkCallbacks { callWFCallback(callbackKye, &CallbackArg{ DefineId: RunRespInfo.DefineId, InstanceId: RunRespInfo.DefineId, DefineName: RunRespInfo.DefineName, InstanceName: RunRespInfo.InstanceName, FormData: RunRespInfo.FormData, Choice: choice, Executor: RunRespInfo.Executor, UserId: w.userId, Context: c, }) } return []byte{}, nil } /** * @brief: pre the wf instance * @param1 instanceId: id of instance * @param2 choice: choice of step * @return1 content of response * @return2 error */ func (w *WFClient) PreRun(instanceId, choice string) ([]byte, error) { url := w.getFullUrl("api/wf_instance/prerun") params := make(map[string]string) params["instance_id"] = instanceId params["choice"] = choice return HttpClientInstance().post(url, params, nil) } /** * @brief: fetch my instances * @param1 page: page num, start from 1 * @param2 rows: count per page, its default value is 10000 * @return1: content of response * @return2: information of error */ func (w *WFClient) FetchMyInstances(page, rows int) ([]byte, error) { url := w.getFullUrl("/api/wf_instance/mime") params := make(map[string]string) params["page"] = strconv.FormatInt(int64(page), 10) params["pageSize"] = strconv.FormatInt(int64(rows), 10) return HttpClientInstance().get(url, params, nil) } /** * @brief: fetch current step of login user * @param1 instanceId: id of instance * @return1 content of response * @return2 error */ func (w *WFClient) FetchCurrentStepByLoginUser(instanceId string) ([]byte, error) { url := w.getFullUrl("/api/wf_instance/user/current") params := make(map[string]string) params["instance_id"] = instanceId return HttpClientInstance().get(url, params, nil) } /** * @brief: fetch current step of instance * @param1 instanceId: id of instance * @return1 content of response * @return2 error */ func (w *WFClient) FetchCurrentStep(instanceId string) ([]byte, error) { url := w.getFullUrl("/api/wf_instance/current") params := make(map[string]string) params["instance_id"] = instanceId return HttpClientInstance().get(url, params, nil) } /** * @brief: fetch my to do list * @param1 page: page num, start from 1 * @param2 rows: count per page, its default value is 10000 * @return1: content of response * @return2: information of error */ func (w *WFClient) FetchToDoList(page, rows int) ([]byte, error) { url := w.getFullUrl("/api/wf_instance/todo") params := make(map[string]string) params["page"] = strconv.FormatInt(int64(page), 10) params["pageSize"] = strconv.FormatInt(int64(rows), 10) return HttpClientInstance().get(url, params, nil) } /** * @brief: fetch my done list * @param1 page: page num, start from 1 * @param2 rows: count per page, its default value is 10000 * @return1: content of response * @return2: information of error */ func (w *WFClient) FetchDoneList(page, rows int) ([]byte, error) { url := w.getFullUrl("/api/wf_instance/done") params := make(map[string]string) params["page"] = strconv.FormatInt(int64(page), 10) params["pageSize"] = strconv.FormatInt(int64(rows), 10) return HttpClientInstance().get(url, params, nil) } func (w *WFClient) FetchWFINstances(page, rows int, filters, sidx, sord string) ([]byte, error) { url := w.getFullUrl("/api/wf_instance/list") fmt.Println("wf url: ", url) params := make(map[string]string) params["page"] = strconv.FormatInt(int64(page), 10) params["rows"] = strconv.FormatInt(int64(rows), 10) params["sidx"] = sidx params["sord"] = sord params["filters"] = filters return HttpClientInstance().get(url, params, nil) } /** * @brief: wf req interseptor * @param1 r: http req */ func (w *WFClient) wfReqInterseptor(r *http.Request) { //r.Header.Add("Authorization", w.authorization) fmt.Println("header add token", w.token) r.Header.Add("token", w.token) } /** * @brief: create the authorization by username, token and domain * @param2 username: username * @param3 token: token * @param4 domain: domain, its default value is qianqiusoft.com * @return1 authorization, such as Bearer adfeadfsdfsdffds * @return2 information of error, nil if everything is all right */ func (w *WFClient) createAuthorization(username, token, domain string) (string, error) { if username == "" || token == "" { return "", errors.New("username or token is empty") } if domain == "" { domain = "qianqiusoft.com" } w.username = username w.token = token w.domain = domain tstr := fmt.Sprintf("%s:%s:%s", username, token, domain) tbase64str := base64.StdEncoding.EncodeToString([]byte(tstr)) finalStr := "sso-auth-token:" + tbase64str return "Bearer " + base64.StdEncoding.EncodeToString([]byte(finalStr)), nil } /** * @brief: get full url * @param1 path: api path, such as /api/wf_instance/done * @return1 url with query params */ func (w *WFClient) getFullUrl(path string) string { path = strings.TrimLeft(path, "/") return fmt.Sprintf("%s/%s", w.endpoint, path) } //撤回 func (w *WFClient) Recall(definedId string) ([]byte, error) { url := w.getFullUrl("/api/wf_instance/recall") params := make(map[string]string) params["instance_id"] = definedId return HttpClientInstance().post(url, params, nil) } //终止 func (w *WFClient) Interrupt(definedId string, formData map[string]interface{}, c *entitys.CtrlContext) ([]byte, error) { url := w.getFullUrl("/api/wf_instance/interrupt") params := make(map[string]string) params["instance_id"] = definedId var RunRespInfo struct { DefineId string `json:"define_id"` InstanceId string `json:"instance_id"` DefineName string `json:"define_name"` InstanceName string `json:"instance_name"` Choices []*Choice `json:"choices"` Transition *Transition `json:"transition"` StepType string `json:"step_type"` FormData string `json:"form_data"` StepName string `json:"step_name"` ActorType string `json:"actor_type"` Executor string `json:"executor"` StartCallback string `json:"start_callback"` } bytess, err := HttpClientInstance().post(url, params, nil) if err != nil { return nil, err } callWFCallback("interrupt", &CallbackArg{ DefineId: RunRespInfo.DefineId, InstanceId: definedId, DefineName: RunRespInfo.DefineName, InstanceName: RunRespInfo.InstanceName, FormData: formData["form_data"].(string), Executor: RunRespInfo.Executor, UserId: w.userId, Context: c, }) return bytess, err } //撤回 func (w *WFClient) Delete(definedId string) ([]byte, error) { url := w.getFullUrl("/api/wf_define/delete") params := make(map[string]string) params["define_id"] = definedId return HttpClientInstance().post(url, params, nil) }