2018-06-21 19:24:45 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
2018-12-06 21:50:17 +00:00
|
|
|
|
|
|
|
"github.com/sacloud/libsacloud/sacloud"
|
2018-06-21 19:24:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// SearchMobileGatewayResponse モバイルゲートウェイ検索レスポンス
|
|
|
|
type SearchMobileGatewayResponse struct {
|
|
|
|
// Total 総件数
|
|
|
|
Total int `json:",omitempty"`
|
|
|
|
// From ページング開始位置
|
|
|
|
From int `json:",omitempty"`
|
|
|
|
// Count 件数
|
|
|
|
Count int `json:",omitempty"`
|
|
|
|
// MobileGateways モバイルゲートウェイ リスト
|
|
|
|
MobileGateways []sacloud.MobileGateway `json:"Appliances,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// MobileGatewaySIMRequest SIM一覧取得リクエスト
|
|
|
|
type MobileGatewaySIMRequest struct {
|
|
|
|
From int `json:",omitempty"`
|
|
|
|
Count int `json:",omitempty"`
|
|
|
|
Sort []string `json:",omitempty"`
|
|
|
|
Filter map[string]interface{} `json:",omitempty"`
|
|
|
|
Exclude []string `json:",omitempty"`
|
|
|
|
Include []string `json:",omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type mobileGatewayResponse struct {
|
|
|
|
*sacloud.ResultFlagValue
|
|
|
|
*sacloud.MobileGateway `json:"Appliance,omitempty"`
|
|
|
|
Success interface{} `json:",omitempty"` //HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないためinterface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type mobileGatewaySIMResponse struct {
|
|
|
|
*sacloud.ResultFlagValue
|
|
|
|
SIM []sacloud.SIMInfo `json:"sim,omitempty"`
|
|
|
|
Success interface{} `json:",omitempty"` //HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないためinterface{}
|
|
|
|
}
|
|
|
|
|
2018-12-06 21:50:17 +00:00
|
|
|
type trafficMonitoringBody struct {
|
|
|
|
TrafficMonitoring *sacloud.TrafficMonitoringConfig `json:"traffic_monitoring_config"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type trafficStatusBody struct {
|
|
|
|
TrafficStatus *sacloud.TrafficStatus `json:"traffic_status"`
|
|
|
|
}
|
|
|
|
|
2018-06-21 19:24:45 +00:00
|
|
|
// MobileGatewayAPI モバイルゲートウェイAPI
|
|
|
|
type MobileGatewayAPI struct {
|
|
|
|
*baseAPI
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewMobileGatewayAPI モバイルゲートウェイAPI作成
|
|
|
|
func NewMobileGatewayAPI(client *Client) *MobileGatewayAPI {
|
|
|
|
return &MobileGatewayAPI{
|
|
|
|
&baseAPI{
|
|
|
|
client: client,
|
|
|
|
FuncGetResourceURL: func() string {
|
|
|
|
return "appliance"
|
|
|
|
},
|
|
|
|
FuncBaseSearchCondition: func() *sacloud.Request {
|
|
|
|
res := &sacloud.Request{}
|
|
|
|
res.AddFilter("Class", "mobilegateway")
|
|
|
|
return res
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find 検索
|
|
|
|
func (api *MobileGatewayAPI) Find() (*SearchMobileGatewayResponse, error) {
|
|
|
|
data, err := api.client.newRequest("GET", api.getResourceURL(), api.getSearchState())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var res SearchMobileGatewayResponse
|
|
|
|
if err := json.Unmarshal(data, &res); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &res, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (api *MobileGatewayAPI) request(f func(*mobileGatewayResponse) error) (*sacloud.MobileGateway, error) {
|
|
|
|
res := &mobileGatewayResponse{}
|
|
|
|
err := f(res)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res.MobileGateway, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (api *MobileGatewayAPI) createRequest(value *sacloud.MobileGateway) *mobileGatewayResponse {
|
|
|
|
return &mobileGatewayResponse{MobileGateway: value}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create 新規作成
|
|
|
|
func (api *MobileGatewayAPI) Create(value *sacloud.MobileGateway) (*sacloud.MobileGateway, error) {
|
|
|
|
return api.request(func(res *mobileGatewayResponse) error {
|
|
|
|
return api.create(api.createRequest(value), res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read 読み取り
|
|
|
|
func (api *MobileGatewayAPI) Read(id int64) (*sacloud.MobileGateway, error) {
|
|
|
|
return api.request(func(res *mobileGatewayResponse) error {
|
|
|
|
return api.read(id, nil, res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update 更新
|
|
|
|
func (api *MobileGatewayAPI) Update(id int64, value *sacloud.MobileGateway) (*sacloud.MobileGateway, error) {
|
|
|
|
return api.request(func(res *mobileGatewayResponse) error {
|
|
|
|
return api.update(id, api.createRequest(value), res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateSetting 設定更新
|
|
|
|
func (api *MobileGatewayAPI) UpdateSetting(id int64, value *sacloud.MobileGateway) (*sacloud.MobileGateway, error) {
|
|
|
|
req := &sacloud.MobileGateway{
|
|
|
|
// Settings
|
|
|
|
Settings: value.Settings,
|
|
|
|
}
|
|
|
|
return api.request(func(res *mobileGatewayResponse) error {
|
|
|
|
return api.update(id, api.createRequest(req), res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete 削除
|
|
|
|
func (api *MobileGatewayAPI) Delete(id int64) (*sacloud.MobileGateway, error) {
|
|
|
|
return api.request(func(res *mobileGatewayResponse) error {
|
|
|
|
return api.delete(id, nil, res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Config 設定変更の反映
|
|
|
|
func (api *MobileGatewayAPI) Config(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/config", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsUp 起動しているか判定
|
|
|
|
func (api *MobileGatewayAPI) IsUp(id int64) (bool, error) {
|
|
|
|
lb, err := api.Read(id)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return lb.Instance.IsUp(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsDown ダウンしているか判定
|
|
|
|
func (api *MobileGatewayAPI) IsDown(id int64) (bool, error) {
|
|
|
|
lb, err := api.Read(id)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return lb.Instance.IsDown(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Boot 起動
|
|
|
|
func (api *MobileGatewayAPI) Boot(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/power", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shutdown シャットダウン(graceful)
|
|
|
|
func (api *MobileGatewayAPI) Shutdown(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "DELETE"
|
|
|
|
uri = fmt.Sprintf("%s/%d/power", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop シャットダウン(force)
|
|
|
|
func (api *MobileGatewayAPI) Stop(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "DELETE"
|
|
|
|
uri = fmt.Sprintf("%s/%d/power", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
return api.modify(method, uri, map[string]bool{"Force": true})
|
|
|
|
}
|
|
|
|
|
|
|
|
// RebootForce 再起動
|
|
|
|
func (api *MobileGatewayAPI) RebootForce(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/reset", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResetForce リセット
|
|
|
|
func (api *MobileGatewayAPI) ResetForce(id int64, recycleProcess bool) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/reset", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
return api.modify(method, uri, map[string]bool{"RecycleProcess": recycleProcess})
|
|
|
|
}
|
|
|
|
|
|
|
|
// SleepUntilUp 起動するまで待機
|
|
|
|
func (api *MobileGatewayAPI) SleepUntilUp(id int64, timeout time.Duration) error {
|
|
|
|
handler := waitingForUpFunc(func() (hasUpDown, error) {
|
|
|
|
return api.Read(id)
|
|
|
|
}, 0)
|
|
|
|
return blockingPoll(handler, timeout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SleepUntilDown ダウンするまで待機
|
|
|
|
func (api *MobileGatewayAPI) SleepUntilDown(id int64, timeout time.Duration) error {
|
|
|
|
handler := waitingForDownFunc(func() (hasUpDown, error) {
|
|
|
|
return api.Read(id)
|
|
|
|
}, 0)
|
|
|
|
return blockingPoll(handler, timeout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SleepWhileCopying コピー終了まで待機
|
|
|
|
func (api *MobileGatewayAPI) SleepWhileCopying(id int64, timeout time.Duration, maxRetry int) error {
|
|
|
|
handler := waitingForAvailableFunc(func() (hasAvailable, error) {
|
|
|
|
return api.Read(id)
|
|
|
|
}, maxRetry)
|
|
|
|
return blockingPoll(handler, timeout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AsyncSleepWhileCopying コピー終了まで待機(非同期)
|
|
|
|
func (api *MobileGatewayAPI) AsyncSleepWhileCopying(id int64, timeout time.Duration, maxRetry int) (chan (interface{}), chan (interface{}), chan (error)) {
|
|
|
|
handler := waitingForAvailableFunc(func() (hasAvailable, error) {
|
|
|
|
return api.Read(id)
|
|
|
|
}, maxRetry)
|
|
|
|
return poll(handler, timeout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConnectToSwitch 指定のインデックス位置のNICをスイッチへ接続
|
|
|
|
func (api *MobileGatewayAPI) ConnectToSwitch(id int64, switchID int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/interface/%d/to/switch/%d", api.getResourceURL(), id, 1, switchID)
|
|
|
|
)
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DisconnectFromSwitch 指定のインデックス位置のNICをスイッチから切断
|
|
|
|
func (api *MobileGatewayAPI) DisconnectFromSwitch(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "DELETE"
|
|
|
|
uri = fmt.Sprintf("%s/%d/interface/%d/to/switch", api.getResourceURL(), id, 1)
|
|
|
|
)
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDNS DNSサーバ設定 取得
|
|
|
|
func (api *MobileGatewayAPI) GetDNS(id int64) (*sacloud.MobileGatewayResolver, error) {
|
|
|
|
var (
|
|
|
|
method = "GET"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/dnsresolver", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
data, err := api.client.newRequest(method, uri, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var res sacloud.MobileGatewayResolver
|
|
|
|
if err := json.Unmarshal(data, &res); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &res, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetDNS DNSサーバ設定
|
|
|
|
func (api *MobileGatewayAPI) SetDNS(id int64, dns *sacloud.MobileGatewayResolver) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/dnsresolver", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
return api.modify(method, uri, dns)
|
|
|
|
}
|
|
|
|
|
2018-09-08 10:09:59 +00:00
|
|
|
// GetSIMRoutes SIMルート 取得
|
|
|
|
func (api *MobileGatewayAPI) GetSIMRoutes(id int64) ([]*sacloud.MobileGatewaySIMRoute, error) {
|
|
|
|
var (
|
|
|
|
method = "GET"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/simroutes", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
data, err := api.client.newRequest(method, uri, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var res sacloud.MobileGatewaySIMRoutes
|
|
|
|
|
|
|
|
if err := json.Unmarshal(data, &res); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res.SIMRoutes, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetSIMRoutes SIMルート 設定
|
|
|
|
func (api *MobileGatewayAPI) SetSIMRoutes(id int64, simRoutes *sacloud.MobileGatewaySIMRoutes) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/simroutes", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
return api.modify(method, uri, simRoutes)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddSIMRoute SIMルート 個別追加
|
|
|
|
func (api *MobileGatewayAPI) AddSIMRoute(id int64, simID int64, prefix string) (bool, error) {
|
|
|
|
|
|
|
|
routes, err := api.GetSIMRoutes(id)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
param := &sacloud.MobileGatewaySIMRoutes{
|
|
|
|
SIMRoutes: routes,
|
|
|
|
}
|
|
|
|
index, added := param.AddSIMRoute(simID, prefix)
|
|
|
|
if index < 0 || added == nil {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return api.SetSIMRoutes(id, param)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteSIMRoute SIMルート 個別削除
|
|
|
|
func (api *MobileGatewayAPI) DeleteSIMRoute(id int64, simID int64, prefix string) (bool, error) {
|
|
|
|
|
|
|
|
routes, err := api.GetSIMRoutes(id)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
param := &sacloud.MobileGatewaySIMRoutes{
|
|
|
|
SIMRoutes: routes,
|
|
|
|
}
|
|
|
|
deleted := param.DeleteSIMRoute(simID, prefix)
|
|
|
|
if !deleted {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = api.SetSIMRoutes(id, param)
|
|
|
|
return deleted, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteSIMRoutes SIMルート 全件削除
|
|
|
|
func (api *MobileGatewayAPI) DeleteSIMRoutes(id int64) (bool, error) {
|
|
|
|
return api.SetSIMRoutes(id, &sacloud.MobileGatewaySIMRoutes{
|
|
|
|
SIMRoutes: []*sacloud.MobileGatewaySIMRoute{},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-06-21 19:24:45 +00:00
|
|
|
// ListSIM SIM一覧取得
|
|
|
|
func (api *MobileGatewayAPI) ListSIM(id int64, req *MobileGatewaySIMRequest) ([]sacloud.SIMInfo, error) {
|
|
|
|
var (
|
|
|
|
method = "GET"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/sims", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
data, err := api.client.newRequest(method, uri, req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var res mobileGatewaySIMResponse
|
|
|
|
if err := json.Unmarshal(data, &res); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res.SIM, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddSIM SIM登録
|
|
|
|
func (api *MobileGatewayAPI) AddSIM(id int64, simID int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "POST"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/sims", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
return api.modify(method, uri, map[string]interface{}{
|
|
|
|
"sim": map[string]interface{}{
|
|
|
|
"resource_id": fmt.Sprintf("%d", simID),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteSIM SIM登録
|
|
|
|
func (api *MobileGatewayAPI) DeleteSIM(id int64, simID int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "DELETE"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/sims/%d", api.getResourceURL(), id, simID)
|
|
|
|
)
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Logs セッションログ取得(複数SIM)
|
|
|
|
func (api *MobileGatewayAPI) Logs(id int64, body interface{}) ([]sacloud.SIMLog, error) {
|
|
|
|
var (
|
|
|
|
method = "GET"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/sessionlog", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
res := &simLogResponse{}
|
|
|
|
err := api.baseAPI.request(method, uri, body, res)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res.Logs, nil
|
|
|
|
}
|
2018-12-06 21:50:17 +00:00
|
|
|
|
|
|
|
// GetTrafficMonitoringConfig トラフィックコントロール 取得
|
|
|
|
func (api *MobileGatewayAPI) GetTrafficMonitoringConfig(id int64) (*sacloud.TrafficMonitoringConfig, error) {
|
|
|
|
var (
|
|
|
|
method = "GET"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/traffic_monitoring", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
res := &trafficMonitoringBody{}
|
|
|
|
err := api.baseAPI.request(method, uri, nil, res)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res.TrafficMonitoring, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetTrafficMonitoringConfig トラフィックコントロール 設定
|
|
|
|
func (api *MobileGatewayAPI) SetTrafficMonitoringConfig(id int64, trafficMonConfig *sacloud.TrafficMonitoringConfig) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/traffic_monitoring", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
req := &trafficMonitoringBody{
|
|
|
|
TrafficMonitoring: trafficMonConfig,
|
|
|
|
}
|
|
|
|
return api.modify(method, uri, req)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DisableTrafficMonitoringConfig トラフィックコントロール 解除
|
|
|
|
func (api *MobileGatewayAPI) DisableTrafficMonitoringConfig(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "DELETE"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/traffic_monitoring", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTrafficStatus 当月通信量 取得
|
|
|
|
func (api *MobileGatewayAPI) GetTrafficStatus(id int64) (*sacloud.TrafficStatus, error) {
|
|
|
|
var (
|
|
|
|
method = "GET"
|
|
|
|
uri = fmt.Sprintf("%s/%d/mobilegateway/traffic_status", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
res := &trafficStatusBody{}
|
|
|
|
err := api.baseAPI.request(method, uri, nil, res)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res.TrafficStatus, nil
|
|
|
|
}
|