openapi/waiter.go (82 lines of code) (raw):
// Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package openapi
import (
"fmt"
"strconv"
"time"
"github.com/aliyun/aliyun-cli/v3/cli"
"github.com/aliyun/aliyun-cli/v3/i18n"
)
var WaiterFlag = &cli.Flag{Category: "helper",
Name: "waiter",
AssignedMode: cli.AssignedRepeatable,
Short: i18n.T(
"use `--waiter expr=<jmesPath> to=<value>` to pull api until result equal to expected value",
"使用 `--waiter expr=<jmesPath> to=<value>` 来轮询调用OpenAPI,直到返回期望的值"),
Long: i18n.T(
"",
""),
Fields: []cli.Field{
{Key: "expr", Required: true, Short: i18n.T("", "")},
{Key: "to", Required: true, Short: i18n.T("", "")},
{Key: "timeout", DefaultValue: "180", Short: i18n.T("", "")},
{Key: "interval", DefaultValue: "5", Short: i18n.T("", "")},
},
ExcludeWith: []string{"pager"},
}
type Waiter struct {
expr string
to string
// timeout time.Duration TODO use Flag.Field to validate
// interval time.Duration TODO use Flag.Field to validate
}
func GetWaiter() *Waiter {
if !WaiterFlag.IsAssigned() {
return nil
}
waiter := &Waiter{}
waiter.expr, _ = WaiterFlag.GetFieldValue("expr")
waiter.to, _ = WaiterFlag.GetFieldValue("to")
//waiter.timeout = time.Duration(time.Second * 180)
//waiter.interval = time.Duration(time.Second * 5)
return waiter
}
func (a *Waiter) CallWith(invoker Invoker) (string, error) {
//
// timeout is 1-600 seconds, default is 180
timeout := time.Duration(time.Second * 180)
if s, ok := WaiterFlag.GetFieldValue("timeout"); ok {
if n, err := strconv.Atoi(s); err == nil {
if n <= 0 && n > 600 {
return "", fmt.Errorf("--waiter timeout=%s must between 1-600 (seconds)", s)
}
timeout = time.Duration(time.Second * time.Duration(n))
} else {
return "", fmt.Errorf("--waiter timeout=%s must be integer", s)
}
}
//
// interval is 2-10 seconds, default is 5
interval := time.Duration(time.Second * 5)
if s, ok := WaiterFlag.GetFieldValue("interval"); ok {
if n, err := strconv.Atoi(s); err == nil {
if n <= 1 && n > 10 {
return "", fmt.Errorf("--waiter interval=%s must between 2-10 (seconds)", s)
}
interval = time.Duration(time.Second * time.Duration(n))
} else {
return "", fmt.Errorf("--waiter interval=%s must be integer", s)
}
}
begin := time.Now()
for {
resp, err := invoker.Call()
if err != nil {
return "", err
}
v, err := evaluateExpr(resp.GetHttpContentBytes(), a.expr)
if err != nil {
return "", err
}
if v == a.to {
return resp.GetHttpContentString(), nil
}
duration := time.Since(begin)
if duration > timeout {
return "", fmt.Errorf("wait '%s' to '%s' timeout(%dseconds), last='%s'",
a.expr, a.to, timeout/time.Second, v)
}
time.Sleep(interval)
}
}