mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-29 03:51:54 +08:00
Feature/yousong text (#7487)
* notify: log with context info * region: guests: log with context info * region: hosts: log with context info * region: misc: remove redundant log * region: skus: use NewInternalServerError instead of NewGeneralError * appsrv: dispatcher: preserve text id * appsrv: dispatcher: remove commented-out code * cloudcommon: db_dispatcher: note errors that won't be translated * cloudcommon: db: rbac: preserve text id * cloudcommon: caller: preserve text id * treewide: fix fmt string * region: guest_actions: preserve text id * region: guest_actions: fix fmt string * region: usages: fix fmt string * mcclient: hosts: remove redundant return value * cloudcommon: fetch: preserve text id * region: guest_template: preserve text id * cloudcommon: db: db_dispatcher: preserve text id * region: guest_actions: preserve text id * httperrors: add funcs for wrap lang tag into context * vendor: golang.org/x/text * httperrors: error with context * httperrors: HTTPError * treewide: fix typo * treewide: use en in source code * locales: initial version
This commit is contained in:
@@ -37,3 +37,6 @@ GTAGS
|
||||
pkg/generated
|
||||
|
||||
*.orig
|
||||
|
||||
# gotext extracted
|
||||
out.gotext.json
|
||||
|
||||
@@ -120,6 +120,7 @@ require (
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8
|
||||
golang.org/x/text v0.3.3
|
||||
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20191008142428-8d021180e987
|
||||
|
||||
@@ -926,6 +926,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package locales
|
||||
+3252
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -188,7 +188,7 @@ func (h *AuthHandlers) GetRegionsResponse(ctx context.Context, w http.ResponseWr
|
||||
func (h *AuthHandlers) getRegions(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
resp, err := h.GetRegionsResponse(ctx, w, req)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, resp)
|
||||
@@ -197,7 +197,7 @@ func (h *AuthHandlers) getRegions(ctx context.Context, w http.ResponseWriter, re
|
||||
func (h *AuthHandlers) getUser(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
data, err := getUserInfo(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.NotFoundError(w, err.Error())
|
||||
httperrors.NotFoundError(ctx, w, err.Error())
|
||||
return
|
||||
}
|
||||
body := jsonutils.NewDict()
|
||||
@@ -470,12 +470,12 @@ type PreLoginFunc func(ctx context.Context, req *http.Request, uname string, bod
|
||||
func (h *AuthHandlers) postLoginHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
body, err := appsrv.FetchJSON(req)
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w, "fetch json for request: %v", err)
|
||||
httperrors.InvalidInputError(ctx, w, "fetch json for request: %v", err)
|
||||
return
|
||||
}
|
||||
err = h.doLogin(ctx, w, req, body)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
// normal
|
||||
@@ -928,7 +928,7 @@ func (h *AuthHandlers) getPermissionDetails(ctx context.Context, w http.Response
|
||||
|
||||
_, query, body := appsrv.FetchEnv(ctx, w, req)
|
||||
if body == nil {
|
||||
httperrors.InvalidInputError(w, "body is empty")
|
||||
httperrors.InvalidInputError(ctx, w, "body is empty")
|
||||
return
|
||||
}
|
||||
var name string
|
||||
@@ -937,7 +937,7 @@ func (h *AuthHandlers) getPermissionDetails(ctx context.Context, w http.Response
|
||||
}
|
||||
result, err := policy.ExplainRpc(ctx, t, body, name)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -957,18 +957,18 @@ func (h *AuthHandlers) getResources(ctx context.Context, w http.ResponseWriter,
|
||||
func (h *AuthHandlers) doCreatePolicies(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
t := AppContextToken(ctx)
|
||||
// if !utils.IsInStringArray("admin", t.GetRoles()) || t.GetProjectName() != "system" {
|
||||
// httperrors.ForbiddenError(w, "not allow to create policy")
|
||||
// httperrors.ForbiddenError(ctx, w, "not allow to create policy")
|
||||
// return
|
||||
// }
|
||||
_, _, body := appsrv.FetchEnv(ctx, w, req)
|
||||
if body == nil {
|
||||
httperrors.InvalidInputError(w, "body is empty")
|
||||
httperrors.InvalidInputError(ctx, w, "body is empty")
|
||||
return
|
||||
}
|
||||
s := auth.GetSession(ctx, t, FetchRegion(req), "")
|
||||
result, err := policytool.PolicyCreate(s, body)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, result)
|
||||
@@ -977,18 +977,18 @@ func (h *AuthHandlers) doCreatePolicies(ctx context.Context, w http.ResponseWrit
|
||||
func (h *AuthHandlers) doPatchPolicy(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
t := AppContextToken(ctx)
|
||||
// if !utils.IsInStringArray("admin", t.GetRoles()) || t.GetProjectName() != "system" {
|
||||
// httperrors.ForbiddenError(w, "not allow to create policy")
|
||||
// httperrors.ForbiddenError(ctx, w, "not allow to create policy")
|
||||
// return
|
||||
// }
|
||||
params, _, body := appsrv.FetchEnv(ctx, w, req)
|
||||
if body == nil {
|
||||
httperrors.InvalidInputError(w, "request body is empty")
|
||||
httperrors.InvalidInputError(ctx, w, "request body is empty")
|
||||
return
|
||||
}
|
||||
s := auth.GetSession(ctx, t, FetchRegion(req), "")
|
||||
result, err := policytool.PolicyPatch(s, params["<policy_id>"], body)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, result)
|
||||
@@ -997,7 +997,7 @@ func (h *AuthHandlers) doPatchPolicy(ctx context.Context, w http.ResponseWriter,
|
||||
func (h *AuthHandlers) doDeletePolicies(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
t := AppContextToken(ctx)
|
||||
// if !utils.IsInStringArray("admin", t.GetRoles()) || t.GetProjectName() != "system" {
|
||||
// httperrors.ForbiddenError(w, "not allow to create policy")
|
||||
// httperrors.ForbiddenError(ctx, w, "not allow to create policy")
|
||||
// return
|
||||
// }
|
||||
_, query, _ := appsrv.FetchEnv(ctx, w, req)
|
||||
@@ -1005,7 +1005,7 @@ func (h *AuthHandlers) doDeletePolicies(ctx context.Context, w http.ResponseWrit
|
||||
|
||||
idlist, e := query.GetArray("id")
|
||||
if e != nil || len(idlist) == 0 {
|
||||
httperrors.InvalidInputError(w, "missing id")
|
||||
httperrors.InvalidInputError(ctx, w, "missing id")
|
||||
return
|
||||
}
|
||||
idStrList := jsonutils.JSONArray2StringArray(idlist)
|
||||
@@ -1040,19 +1040,19 @@ func (h *AuthHandlers) doDeletePolicies(ctx context.Context, w http.ResponseWrit
|
||||
func (h *AuthHandlers) resetUserPassword(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
t, authToken, err := fetchAuthInfo(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail: %s", err)
|
||||
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, _, body := appsrv.FetchEnv(ctx, w, req)
|
||||
if body == nil {
|
||||
httperrors.InvalidInputError(w, "body is empty")
|
||||
httperrors.InvalidInputError(ctx, w, "body is empty")
|
||||
return
|
||||
}
|
||||
|
||||
user, err := fetchUserInfoFromToken(ctx, req, t)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1062,13 +1062,13 @@ func (h *AuthHandlers) resetUserPassword(ctx context.Context, w http.ResponseWri
|
||||
passcode, _ := body.GetString("passcode")
|
||||
|
||||
if newPwd != confirmPwd {
|
||||
httperrors.InputParameterError(w, "new password mismatch")
|
||||
httperrors.InputParameterError(ctx, w, "new password mismatch")
|
||||
return
|
||||
}
|
||||
|
||||
// 1.验证原密码正确,且idp_driver为空
|
||||
if isIdpUser(user) {
|
||||
httperrors.ForbiddenError(w, "not support reset user password")
|
||||
httperrors.ForbiddenError(ctx, w, "not support reset user password")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1078,11 +1078,11 @@ func (h *AuthHandlers) resetUserPassword(ctx context.Context, w http.ResponseWri
|
||||
switch httperr := err.(type) {
|
||||
case *httputils.JSONClientError:
|
||||
if httperr.Code == 409 {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
httperrors.InputParameterError(w, "密码错误")
|
||||
httperrors.InputParameterError(ctx, w, "密码错误")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1091,7 +1091,7 @@ func (h *AuthHandlers) resetUserPassword(ctx context.Context, w http.ResponseWri
|
||||
if isMfaEnabled(user) {
|
||||
err = authToken.VerifyTotpPasscode(s, t.GetUserId(), passcode)
|
||||
if err != nil {
|
||||
httperrors.InputParameterError(w, "invalid passcode")
|
||||
httperrors.InputParameterError(ctx, w, "invalid passcode")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1101,7 +1101,7 @@ func (h *AuthHandlers) resetUserPassword(ctx context.Context, w http.ResponseWri
|
||||
params.Set("password", jsonutils.NewString(newPwd))
|
||||
_, err = modules.UsersV3.Patch(s, t.GetUserId(), params)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ func validateTotpRecoverySecrets(s *mcclient.ClientSession, uid string, question
|
||||
func initTotpSecrets(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
t, authToken, err := fetchAuthInfo(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail %s", err)
|
||||
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail %s", err)
|
||||
return
|
||||
}
|
||||
if authToken.IsTotpInitialized() {
|
||||
@@ -216,7 +216,7 @@ func initTotpSecrets(ctx context.Context, w http.ResponseWriter, req *http.Reque
|
||||
s := auth.GetAdminSession(ctx, FetchRegion(req), "")
|
||||
code, err := doCreateUserTotpCred(s, t)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -232,25 +232,25 @@ func initTotpSecrets(ctx context.Context, w http.ResponseWriter, req *http.Reque
|
||||
func validatePasscodeHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
t, authToken, err := fetchAuthInfo(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail %s", err)
|
||||
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
s := auth.GetAdminSession(ctx, FetchRegion(req), "")
|
||||
_, _, body := appsrv.FetchEnv(ctx, w, req)
|
||||
if body == nil {
|
||||
httperrors.InvalidInputError(w, "body is empty")
|
||||
httperrors.InvalidInputError(ctx, w, "body is empty")
|
||||
return
|
||||
}
|
||||
|
||||
passcode, err := body.GetString("passcode")
|
||||
if err != nil {
|
||||
httperrors.MissingParameterError(w, "passcode")
|
||||
httperrors.MissingParameterError(ctx, w, "passcode")
|
||||
return
|
||||
}
|
||||
|
||||
if len(passcode) != 6 {
|
||||
httperrors.InputParameterError(w, "passcode is a 6-digits string")
|
||||
httperrors.InputParameterError(ctx, w, "passcode is a 6-digits string")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ func validatePasscodeHandler(ctx context.Context, w http.ResponseWriter, req *ht
|
||||
|
||||
if err != nil {
|
||||
log.Warningf("VerifyTotpPasscode %s", err.Error())
|
||||
httperrors.InvalidCredentialError(w, "invalid passcode: %v", err)
|
||||
httperrors.InvalidCredentialError(ctx, w, "invalid passcode: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -271,32 +271,32 @@ func validatePasscodeHandler(ctx context.Context, w http.ResponseWriter, req *ht
|
||||
func resetTotpSecrets(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
t, _, err := fetchAuthInfo(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail %s", err)
|
||||
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
s := auth.GetAdminSession(ctx, FetchRegion(req), "")
|
||||
_, _, body := appsrv.FetchEnv(ctx, w, req)
|
||||
if body == nil {
|
||||
httperrors.InvalidInputError(w, "body is empty")
|
||||
httperrors.InvalidInputError(ctx, w, "body is empty")
|
||||
return
|
||||
}
|
||||
|
||||
uid := t.GetUserId()
|
||||
if len(uid) == 0 {
|
||||
httperrors.ConflictError(w, "uid is empty")
|
||||
httperrors.ConflictError(ctx, w, "uid is empty")
|
||||
return
|
||||
}
|
||||
|
||||
err = validateTotpRecoverySecrets(s, uid, body)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
code, err := resetUserTotpCred(s, t)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ func resetTotpSecrets(ctx context.Context, w http.ResponseWriter, req *http.Requ
|
||||
func listTotpRecoveryQuestions(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
t, _, err := fetchAuthInfo(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail %s", err)
|
||||
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ func listTotpRecoveryQuestions(ctx context.Context, w http.ResponseWriter, req *
|
||||
ss, err := modules.Credentials.GetRecoverySecrets(s, t.GetUserId())
|
||||
if len(ss) == 0 {
|
||||
log.Errorf("ListTotpRecoveryQuestions %s", err.Error())
|
||||
httperrors.NotFoundError(w, "no revocery questions.")
|
||||
httperrors.NotFoundError(ctx, w, "no revocery questions.")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -335,27 +335,27 @@ func listTotpRecoveryQuestions(ctx context.Context, w http.ResponseWriter, req *
|
||||
func resetTotpRecoveryQuestions(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
t, _, err := fetchAuthInfo(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail %s", err)
|
||||
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
s := auth.GetAdminSession(ctx, FetchRegion(req), "")
|
||||
_, _, body := appsrv.FetchEnv(ctx, w, req)
|
||||
if body == nil {
|
||||
httperrors.InvalidInputError(w, "body is empty")
|
||||
httperrors.InvalidInputError(ctx, w, "body is empty")
|
||||
return
|
||||
}
|
||||
|
||||
questions := make([]modules.SRecoverySecret, 0)
|
||||
err = body.Unmarshal(&questions)
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w, "unmarshal questions: %v", err)
|
||||
httperrors.InvalidInputError(ctx, w, "unmarshal questions: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = setTotpRecoverySecrets(s, t.GetUserId(), questions)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -47,18 +47,18 @@ func (h *CSRFResourceHandler) Bind(app *appsrv.Application) {
|
||||
func getAdminSession(ctx context.Context, apiVer string, region string, w http.ResponseWriter) *mcclient.ClientSession {
|
||||
adminToken := auth.AdminCredential()
|
||||
if adminToken == nil {
|
||||
httperrors.NotFoundError(w, "get admin credential is nil")
|
||||
httperrors.NotFoundError(ctx, w, "get admin credential is nil")
|
||||
return nil
|
||||
}
|
||||
regions := adminToken.GetRegions()
|
||||
log.Infof("CSRF regions: %v", regions)
|
||||
if len(regions) == 0 {
|
||||
httperrors.NotFoundError(w, "no usable regions, please contact admin")
|
||||
httperrors.NotFoundError(ctx, w, "no usable regions, please contact admin")
|
||||
return nil
|
||||
}
|
||||
ret, _ := sets.InArray(region, regions)
|
||||
if !ret {
|
||||
httperrors.NotFoundError(w, "illegal region %s, please contact admin", region)
|
||||
httperrors.NotFoundError(ctx, w, "illegal region %s, please contact admin", region)
|
||||
}
|
||||
s := auth.GetAdminSession(ctx, region, apiVer)
|
||||
return s
|
||||
@@ -71,7 +71,7 @@ func fetchEnv3Csrf(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
module3, e := modulebase.GetModule(session, params[ResName3])
|
||||
if e != nil || module == nil {
|
||||
httperrors.NotFoundError(w, fmt.Sprintf("resource %s not found", params[ResName3]))
|
||||
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s not found", params[ResName3]))
|
||||
return nil, nil, nil, nil, nil, nil, nil
|
||||
}
|
||||
return module, module2, module3, session, params, query, body
|
||||
@@ -84,7 +84,7 @@ func fetchEnv2Csrf(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
module2, e := modulebase.GetModule(session, params[ResName2])
|
||||
if e != nil || module == nil {
|
||||
httperrors.NotFoundError(w, fmt.Sprintf("resource %s not found", params[ResName2]))
|
||||
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s not found", params[ResName2]))
|
||||
return nil, nil, nil, nil, nil, nil
|
||||
}
|
||||
return module, module2, session, params, query, body
|
||||
@@ -94,7 +94,7 @@ func fetchEnvCsrf(ctx context.Context, w http.ResponseWriter, r *http.Request) (
|
||||
session, params, query, body := fetchEnvCsrf0(ctx, w, r)
|
||||
module, e := modulebase.GetModule(session, params[ResName])
|
||||
if e != nil || module == nil {
|
||||
httperrors.NotFoundError(w, fmt.Sprintf("resource %s not found", params[ResName]))
|
||||
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s not found", params[ResName]))
|
||||
return nil, nil, nil, nil, nil
|
||||
}
|
||||
return module, session, params, query, body
|
||||
@@ -105,7 +105,7 @@ func fetchEnvCsrf0(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
region := r.URL.Query().Get("region")
|
||||
log.Println("csrf region from url:", region)
|
||||
if len(region) < 1 {
|
||||
httperrors.NotFoundError(w, fmt.Sprintf("region %s is empty", region))
|
||||
httperrors.NotFoundError(ctx, w, fmt.Sprintf("region %s is empty", region))
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
log.Infof("csrf region from url: %s", region)
|
||||
@@ -135,7 +135,7 @@ func getHandlerCsrf(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
obj, e := module.Get(session, params[ResID], query)
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func (h *AuthHandlers) getIdpSsoRedirectUri(ctx context.Context, w http.Response
|
||||
if query != nil && query.Contains("linkuser") {
|
||||
t, authToken, _ := fetchAuthInfo(ctx, req)
|
||||
if t == nil {
|
||||
httperrors.InvalidCredentialError(w, "invalid credential")
|
||||
httperrors.InvalidCredentialError(ctx, w, "invalid credential")
|
||||
return
|
||||
}
|
||||
linkuser = t.GetUserId()
|
||||
@@ -101,7 +101,7 @@ func (h *AuthHandlers) getIdpSsoRedirectUri(ctx context.Context, w http.Response
|
||||
}
|
||||
resp, err := modules.IdentityProviders.GetSpecific(s, idpId, "sso-redirect-uri", jsonutils.Marshal(input))
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
redirUrl, _ := resp.GetString("uri")
|
||||
@@ -151,7 +151,7 @@ func (h *AuthHandlers) handleSsoLogin(ctx context.Context, w http.ResponseWriter
|
||||
missing = append(missing, "idp_referer")
|
||||
}
|
||||
if len(missing) > 0 {
|
||||
httperrors.TimeoutError(w, "session expires, missing %s", strings.Join(missing, ","))
|
||||
httperrors.TimeoutError(ctx, w, "session expires, missing %s", strings.Join(missing, ","))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -165,21 +165,21 @@ func (h *AuthHandlers) handleSsoLogin(ctx context.Context, w http.ResponseWriter
|
||||
case "GET":
|
||||
body, err = jsonutils.ParseQueryString(req.URL.RawQuery)
|
||||
if err != nil {
|
||||
httperrors.InputParameterError(w, "parse query string error: %s", err)
|
||||
httperrors.InputParameterError(ctx, w, "parse query string error: %s", err)
|
||||
return
|
||||
}
|
||||
case "POST":
|
||||
formData, err := appsrv.Fetch(req)
|
||||
if err != nil {
|
||||
httperrors.InputParameterError(w, "fetch formdata error: %s", err)
|
||||
httperrors.InputParameterError(ctx, w, "fetch formdata error: %s", err)
|
||||
}
|
||||
body, err = jsonutils.ParseQueryString(string(formData))
|
||||
if err != nil {
|
||||
httperrors.InputParameterError(w, "parse form data error: %s", err)
|
||||
httperrors.InputParameterError(ctx, w, "parse form data error: %s", err)
|
||||
return
|
||||
}
|
||||
default:
|
||||
httperrors.InputParameterError(w, "invalid request")
|
||||
httperrors.InputParameterError(ctx, w, "invalid request")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ func handleUnlinkIdp(ctx context.Context, w http.ResponseWriter, req *http.Reque
|
||||
|
||||
body, err := appsrv.FetchJSON(req)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -365,7 +365,7 @@ func handleUnlinkIdp(ctx context.Context, w http.ResponseWriter, req *http.Reque
|
||||
idpEntityId, _ := body.GetString("idp_entity_id")
|
||||
|
||||
if len(idpId) == 0 || len(idpEntityId) == 0 {
|
||||
httperrors.InputParameterError(w, "empty idp_id or idp_entity_id")
|
||||
httperrors.InputParameterError(ctx, w, "empty idp_id or idp_entity_id")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -376,7 +376,7 @@ func handleUnlinkIdp(ctx context.Context, w http.ResponseWriter, req *http.Reque
|
||||
}
|
||||
_, err = modules.UsersV3.PerformAction(s, t.GetUserId(), "unlink-idp", jsonutils.Marshal(input))
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.Send(w, "")
|
||||
@@ -388,7 +388,7 @@ func fetchIdpBasicConfig(ctx context.Context, w http.ResponseWriter, req *http.R
|
||||
idpId := params["<idp_id>"]
|
||||
info, err := getIdpBasicConfig(s, idpId)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, info)
|
||||
@@ -426,7 +426,7 @@ func fetchIdpSAMLMetadata(ctx context.Context, w http.ResponseWriter, req *http.
|
||||
query.Set("redirect_uri", jsonutils.NewString(getSsoCallbackUrl()))
|
||||
md, err := modules.IdentityProviders.GetSpecific(s, idpId, "saml-metadata", query)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, md)
|
||||
|
||||
@@ -65,15 +65,18 @@ func readImageForm(r *multipart.Reader) (map[string]string, *multipart.Part, err
|
||||
}
|
||||
|
||||
func imageUploadHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
const (
|
||||
invalidForm = "invalid form"
|
||||
)
|
||||
reader, e := r.MultipartReader()
|
||||
if e != nil {
|
||||
httperrors.InvalidInputError(w, "无效的表单")
|
||||
httperrors.InvalidInputError(ctx, w, invalidForm)
|
||||
return
|
||||
}
|
||||
|
||||
p, f, e := readImageForm(reader)
|
||||
if e != nil {
|
||||
httperrors.InvalidInputError(w, "无效的表单")
|
||||
httperrors.InvalidInputError(ctx, w, invalidForm)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -81,19 +84,19 @@ func imageUploadHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
|
||||
name, ok := p["name"]
|
||||
if !ok {
|
||||
httperrors.InvalidInputError(w, "缺少镜像名称")
|
||||
httperrors.InvalidInputError(ctx, w, "missing image name")
|
||||
return
|
||||
}
|
||||
params.Add(jsonutils.NewString(name), "name")
|
||||
|
||||
_imageSize, ok := p["image_size"]
|
||||
if !ok {
|
||||
httperrors.InvalidInputError(w, "缺少文件信息")
|
||||
httperrors.InvalidInputError(ctx, w, "missing image size")
|
||||
return
|
||||
}
|
||||
imageSize, e := strconv.ParseInt(_imageSize, 10, 64)
|
||||
if e != nil {
|
||||
httperrors.InvalidInputError(w, "文件信息错误")
|
||||
httperrors.InvalidInputError(ctx, w, "invalid image size")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -110,7 +113,7 @@ func imageUploadHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
|
||||
res, e := modules.Images.Upload(s, params, f, imageSize)
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
return
|
||||
} else {
|
||||
appsrv.SendJSON(w, res)
|
||||
|
||||
@@ -89,12 +89,12 @@ func (h *K8sResourceHandler) fetchEnv(ctx context.Context, req *http.Request) (*
|
||||
func (h *K8sResourceHandler) Get(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
env, err := h.fetchEnv(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
detail, err := k8s.RawResource.Get(env.session, env.kind, env.namespace, env.name, env.cluster)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, detail)
|
||||
@@ -103,12 +103,12 @@ func (h *K8sResourceHandler) Get(ctx context.Context, w http.ResponseWriter, req
|
||||
func (h *K8sResourceHandler) GetYAML(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
env, err := h.fetchEnv(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
detail, err := k8s.RawResource.GetYAML(env.session, env.kind, env.namespace, env.name, env.cluster)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.Send(w, string(detail))
|
||||
@@ -117,17 +117,17 @@ func (h *K8sResourceHandler) GetYAML(ctx context.Context, w http.ResponseWriter,
|
||||
func (h *K8sResourceHandler) Put(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
env, err := h.fetchEnv(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
data, err := appsrv.FetchJSON(req)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
err = k8s.RawResource.Put(env.session, env.kind, env.namespace, env.name, data, env.cluster)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
@@ -136,11 +136,11 @@ func (h *K8sResourceHandler) Put(ctx context.Context, w http.ResponseWriter, req
|
||||
func (h *K8sResourceHandler) Delete(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
env, err := h.fetchEnv(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
if err := k8s.RawResource.Delete(env.session, env.kind, env.namespace, env.name, env.cluster); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
@@ -129,7 +129,7 @@ func FetchAuthToken(f func(context.Context, http.ResponseWriter, *http.Request))
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
ctx, err := fetchAndSetAuthContext(ctx, w, r)
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "No token in header: %v", err)
|
||||
httperrors.InvalidCredentialError(ctx, w, "No token in header: %v", err)
|
||||
return
|
||||
}
|
||||
f(ctx, w, r)
|
||||
|
||||
@@ -112,7 +112,7 @@ func (mh *MiscHandler) PostUploads(ctx context.Context, w http.ResponseWriter, r
|
||||
var maxMemory int64 = 10 << 20
|
||||
e := req.ParseMultipartForm(maxMemory)
|
||||
if e != nil {
|
||||
httperrors.InvalidInputError(w, "invalid form")
|
||||
httperrors.InvalidInputError(ctx, w, "invalid form")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ func (mh *MiscHandler) PostUploads(ctx context.Context, w http.ResponseWriter, r
|
||||
actions, ok := params["action"]
|
||||
if !ok || len(actions) == 0 || len(actions[0]) == 0 {
|
||||
err := httperrors.NewInputParameterError("Missing parameter %s", "action")
|
||||
httperrors.JsonClientError(w, err)
|
||||
httperrors.JsonClientError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ func (mh *MiscHandler) PostUploads(ctx context.Context, w http.ResponseWriter, r
|
||||
return
|
||||
default:
|
||||
err := httperrors.NewInputParameterError("Unsupported action %s", actions[0])
|
||||
httperrors.JsonClientError(w, err)
|
||||
httperrors.JsonClientError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -147,7 +147,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
|
||||
hostfiles, ok := files["hosts"]
|
||||
if !ok || len(hostfiles) == 0 || hostfiles[0] == nil {
|
||||
e := httperrors.NewInputParameterError("Missing parameter %s", "hosts")
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
|
||||
contentType := fileHeader.Get("Content-Type")
|
||||
if contentType != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" {
|
||||
e := httperrors.NewInputParameterError("Wrong content type %s, required application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", contentType)
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
e := httperrors.NewInternalServerError("can't open file")
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -172,14 +172,14 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
e := httperrors.NewInternalServerError("can't parse file")
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
rows := xlsx.GetRows("hosts")
|
||||
if len(rows) == 0 {
|
||||
e := httperrors.NewGeneralError(fmt.Errorf("empty file content"))
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
|
||||
}
|
||||
|
||||
if !titlesOk {
|
||||
httperrors.InputParameterError(w, "template file is invalid.please check.")
|
||||
httperrors.InputParameterError(ctx, w, "template file is invalid.please check.")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
|
||||
paramKeys = append(paramKeys, "access_ip")
|
||||
default:
|
||||
e := httperrors.NewInternalServerError("empty file content")
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -231,7 +231,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
|
||||
// skipped header row
|
||||
if len(rows) > BATCH_HOST_REGISTER_QUANTITY_LIMITATION {
|
||||
e := httperrors.NewInputParameterError(fmt.Sprintf("beyond limitation. excel file rows must less than %d", BATCH_HOST_REGISTER_QUANTITY_LIMITATION))
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
|
||||
}
|
||||
|
||||
if e != nil {
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
|
||||
submitResult, err := modules.Hosts.BatchRegister(s, paramKeys, params)
|
||||
if err != nil {
|
||||
e := httperrors.NewGeneralError(err)
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
|
||||
userfiles, ok := files["users"]
|
||||
if !ok || len(userfiles) == 0 || userfiles[0] == nil {
|
||||
e := httperrors.NewInputParameterError("Missing parameter %s", "users")
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
|
||||
contentType := fileHeader.Get("Content-Type")
|
||||
if contentType != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" {
|
||||
e := httperrors.NewInputParameterError("Wrong content type %s, required application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", contentType)
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
e := httperrors.NewInternalServerError("can't open file")
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
e := httperrors.NewInternalServerError("can't parse file")
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -328,11 +328,11 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
|
||||
rows := xlsx.GetRows("users")
|
||||
if len(rows) <= 1 {
|
||||
e := httperrors.NewInputParameterError("empty file")
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
} else if len(rows) > BATCH_USER_REGISTER_QUANTITY_LIMITATION {
|
||||
e := httperrors.NewInputParameterError(fmt.Sprintf("beyond limitation.excel file rows must less than %d", BATCH_USER_REGISTER_QUANTITY_LIMITATION))
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
|
||||
|
||||
if len(name) == 0 {
|
||||
e := httperrors.NewClientError("row %d name is empty", rowIdx)
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -362,13 +362,13 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
|
||||
if !ok {
|
||||
if len(domain) == 0 {
|
||||
e := httperrors.NewClientError("row %d domain is empty", rowIdx)
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := modules.Domains.GetId(adminS, domain, nil)
|
||||
if err != nil {
|
||||
httperrors.JsonClientError(w, httperrors.NewGeneralError(err))
|
||||
httperrors.JsonClientError(ctx, w, httperrors.NewGeneralError(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
|
||||
|
||||
if _, ok := names[name+"/"+domainId]; ok {
|
||||
e := httperrors.NewClientError("row %d duplicate name %s", rowIdx, name)
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
} else {
|
||||
names[name+"/"+domainId] = true
|
||||
@@ -417,7 +417,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
|
||||
|
||||
if err := userG.Wait(); err != nil {
|
||||
e := httperrors.NewGeneralError(err)
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -428,7 +428,7 @@ func (mh *MiscHandler) getDownloadsHandler(ctx context.Context, w http.ResponseW
|
||||
params := appctx.AppContextParams(ctx)
|
||||
template, ok := params["<template_id>"]
|
||||
if !ok || len(template) == 0 {
|
||||
httperrors.InvalidInputError(w, "not found")
|
||||
httperrors.InvalidInputError(ctx, w, "not found")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -439,28 +439,28 @@ func (mh *MiscHandler) getDownloadsHandler(ctx context.Context, w http.ResponseW
|
||||
records := [][]string{BatchHostRegisterTemplate}
|
||||
content, err = writeXlsx("hosts", records)
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(w, "internal server error")
|
||||
httperrors.InternalServerError(ctx, w, "internal server error")
|
||||
return
|
||||
}
|
||||
case "BatchHostISORegister":
|
||||
records := [][]string{BatchHostISORegisterTemplate}
|
||||
content, err = writeXlsx("hosts", records)
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(w, "internal server error")
|
||||
httperrors.InternalServerError(ctx, w, "internal server error")
|
||||
return
|
||||
}
|
||||
case "BatchHostPXERegister":
|
||||
records := [][]string{BatchHostPXERegisterTemplate}
|
||||
content, err = writeXlsx("hosts", records)
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(w, "internal server error")
|
||||
httperrors.InternalServerError(ctx, w, "internal server error")
|
||||
return
|
||||
}
|
||||
case "BatchUserRegister":
|
||||
records := [][]string{{"*用户名(user)", "用户密码(password)", "*部门/域(domain)", "*是否登录控制台(allow_web_console:true、false)"}}
|
||||
content, err = writeXlsx("users", records)
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(w, "internal server error")
|
||||
httperrors.InternalServerError(ctx, w, "internal server error")
|
||||
return
|
||||
}
|
||||
case "BatchProjectRegister":
|
||||
@@ -474,11 +474,11 @@ func (mh *MiscHandler) getDownloadsHandler(ctx context.Context, w http.ResponseW
|
||||
records := [][]string{titles}
|
||||
content, err = writeXlsx("projects", records)
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(w, "internal server error")
|
||||
httperrors.InternalServerError(ctx, w, "internal server error")
|
||||
return
|
||||
}
|
||||
default:
|
||||
httperrors.InputParameterError(w, "template not found %s", template)
|
||||
httperrors.InputParameterError(ctx, w, "template not found %s", template)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -492,12 +492,12 @@ func (mh *MiscHandler) postPIUploads(ctx context.Context, w http.ResponseWriter,
|
||||
// 5 MB
|
||||
var maxMemory int64 = 5 << 20
|
||||
if req.ContentLength > maxMemory {
|
||||
httperrors.InvalidInputError(w, "request body is too large.")
|
||||
httperrors.InvalidInputError(ctx, w, "request body is too large.")
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.Contains(req.Header.Get("Content-Type"), "multipart/form-data") {
|
||||
httperrors.InvalidInputError(w, "invalid multipart form")
|
||||
httperrors.InvalidInputError(ctx, w, "invalid multipart form")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -507,7 +507,7 @@ func (mh *MiscHandler) postPIUploads(ctx context.Context, w http.ResponseWriter,
|
||||
header.Set("Content-Length", req.Header.Get("Content-Length"))
|
||||
resp, err := modules.ProcessInstance.Upload(s, header, req.Body)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -518,38 +518,38 @@ func (mh *MiscHandler) postS3UploadHandler(ctx context.Context, w http.ResponseW
|
||||
reader, e := r.MultipartReader()
|
||||
if e != nil {
|
||||
log.Debugf("postS3UploadHandler.MultipartReader %s", e)
|
||||
httperrors.InvalidInputError(w, "invalid form")
|
||||
httperrors.InvalidInputError(ctx, w, "invalid form")
|
||||
return
|
||||
}
|
||||
|
||||
p, f, e := readImageForm(reader)
|
||||
if e != nil {
|
||||
log.Debugf("postS3UploadHandler.readImageForm %s", e)
|
||||
httperrors.InvalidInputError(w, "invalid form")
|
||||
httperrors.InvalidInputError(ctx, w, "invalid form")
|
||||
return
|
||||
}
|
||||
|
||||
bucket_id, ok := p["bucket_id"]
|
||||
if !ok {
|
||||
httperrors.MissingParameterError(w, "bucket_id")
|
||||
httperrors.MissingParameterError(ctx, w, "bucket_id")
|
||||
return
|
||||
}
|
||||
|
||||
key, ok := p["key"]
|
||||
if !ok {
|
||||
httperrors.MissingParameterError(w, "key")
|
||||
httperrors.MissingParameterError(ctx, w, "key")
|
||||
return
|
||||
}
|
||||
|
||||
_content_length, ok := p["content_length"]
|
||||
if !ok {
|
||||
httperrors.MissingParameterError(w, "content_length")
|
||||
httperrors.MissingParameterError(ctx, w, "content_length")
|
||||
return
|
||||
}
|
||||
|
||||
content_length, e := strconv.ParseInt(_content_length, 10, 64)
|
||||
if e != nil {
|
||||
httperrors.InvalidInputError(w, "invalid content_length %s", _content_length)
|
||||
httperrors.InvalidInputError(ctx, w, "invalid content_length %s", _content_length)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -563,7 +563,7 @@ func (mh *MiscHandler) postS3UploadHandler(ctx context.Context, w http.ResponseW
|
||||
meta.Set("Content-Type", "application/octet-stream")
|
||||
e = modules.Buckets.Upload(s, bucket_id, key, f, content_length, storage_class, acl, meta)
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, jsonutils.NewDict())
|
||||
|
||||
@@ -145,7 +145,7 @@ func doOIDCAuth(ctx context.Context, req *http.Request, query jsonutils.JSONObje
|
||||
func handleOIDCToken(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
resp, err := validateOIDCToken(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, jsonutils.Marshal(resp))
|
||||
@@ -327,7 +327,7 @@ func handleOIDCConfiguration(ctx context.Context, w http.ResponseWriter, req *ht
|
||||
func handleOIDCJWKeys(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
keyJson, err := clientman.GetJWKs(ctx)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, keyJson)
|
||||
@@ -336,7 +336,7 @@ func handleOIDCJWKeys(ctx context.Context, w http.ResponseWriter, req *http.Requ
|
||||
func handleOIDCUserInfo(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
data, err := getUserInfo(ctx, req)
|
||||
if err != nil {
|
||||
httperrors.NotFoundError(w, err.Error())
|
||||
httperrors.NotFoundError(ctx, w, "%v", err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, data)
|
||||
|
||||
@@ -137,7 +137,7 @@ func (f *ResourceHandlers) AddDelete(mf appsrv.MiddlewareFunc) *ResourceHandlers
|
||||
return f
|
||||
}
|
||||
|
||||
func fetchIdList(query jsonutils.JSONObject, w http.ResponseWriter) []string {
|
||||
func fetchIdList(ctx context.Context, query jsonutils.JSONObject, w http.ResponseWriter) []string {
|
||||
idlist, e := query.GetArray("id")
|
||||
if e == nil && len(idlist) > 0 {
|
||||
queryDict := query.(*jsonutils.JSONDict)
|
||||
@@ -146,7 +146,7 @@ func fetchIdList(query jsonutils.JSONObject, w http.ResponseWriter) []string {
|
||||
return jsonutils.JSONArray2StringArray(idlist)
|
||||
} else {
|
||||
log.Debugf("Cannot find idlist in query: %s", query)
|
||||
httperrors.InvalidInputError(w, "No idlist found")
|
||||
httperrors.InvalidInputError(ctx, w, "No idlist found")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -157,20 +157,20 @@ func fetchIdList(query jsonutils.JSONObject, w http.ResponseWriter) []string {
|
||||
func (f *ResourceHandlers) listHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r)
|
||||
if req.Error() != nil {
|
||||
httperrors.GeneralServerError(w, req.Error())
|
||||
httperrors.GeneralServerError(ctx, w, req.Error())
|
||||
return
|
||||
}
|
||||
jmod, _ := modulebase.GetJointModule(req.Session(), req.ResName())
|
||||
if jmod != nil {
|
||||
f.doList(req.Session(), jmod, req.Query(), w, r)
|
||||
f.doList(ctx, req.Session(), jmod, req.Query(), w, r)
|
||||
} else {
|
||||
if err := req.WithMod1().Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
batchGet, err := req.Query().Bool("batchGet")
|
||||
if err == nil && batchGet {
|
||||
idlist := fetchIdList(req.Query(), w)
|
||||
idlist := fetchIdList(ctx, req.Query(), w)
|
||||
if idlist == nil {
|
||||
return
|
||||
}
|
||||
@@ -182,12 +182,12 @@ func (f *ResourceHandlers) listHandler(ctx context.Context, w http.ResponseWrite
|
||||
ret := req.Mod1().BatchGet(req.Session(), idlist, req.Query())
|
||||
appsrv.SendJSON(w, modulebase.ListResult2JSON(modulebase.SubmitResults2ListResult(ret)))
|
||||
} else {
|
||||
f.doList(req.Session(), req.Mod1(), req.Query(), w, r)
|
||||
f.doList(ctx, req.Session(), req.Mod1(), req.Query(), w, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *ResourceHandlers) doList(session *mcclient.ClientSession, module modulebase.IBaseManager, query jsonutils.JSONObject, w http.ResponseWriter, r *http.Request) {
|
||||
func (f *ResourceHandlers) doList(ctx context.Context, session *mcclient.ClientSession, module modulebase.IBaseManager, query jsonutils.JSONObject, w http.ResponseWriter, r *http.Request) {
|
||||
var exportKeys []string
|
||||
var exportTexts []string
|
||||
exportFormat, _ := query.GetString("export")
|
||||
@@ -201,13 +201,13 @@ func (f *ResourceHandlers) doList(session *mcclient.ClientSession, module module
|
||||
exportTexts = strings.Split(exportTextStr, ",")
|
||||
}
|
||||
if len(exportKeys) == 0 {
|
||||
httperrors.InvalidInputError(w, "missing export keys")
|
||||
httperrors.InvalidInputError(ctx, w, "missing export keys")
|
||||
return
|
||||
} else if len(exportKeys) != len(exportTexts) {
|
||||
if len(exportTexts) == 0 {
|
||||
exportTexts = exportKeys
|
||||
} else {
|
||||
httperrors.InvalidInputError(w, "inconsistent export keys and texts")
|
||||
httperrors.InvalidInputError(ctx, w, "inconsistent export keys and texts")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -219,7 +219,7 @@ func (f *ResourceHandlers) doList(session *mcclient.ClientSession, module module
|
||||
|
||||
ret, e := module.List(session, query)
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else if len(exportFormat) > 0 {
|
||||
w.Header().Set("Content-Description", "File Transfer")
|
||||
w.Header().Set("Content-Transfer-Encoding", "binary")
|
||||
@@ -236,12 +236,12 @@ func (f *ResourceHandlers) doList(session *mcclient.ClientSession, module module
|
||||
func (f *ResourceHandlers) getHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
obj, e := req.Mod1().Get(req.Session(), req.ResID(), req.Query())
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -255,7 +255,7 @@ func (f *ResourceHandlers) getHandler(ctx context.Context, w http.ResponseWriter
|
||||
func (f *ResourceHandlers) getSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
session := req.Session()
|
||||
@@ -272,14 +272,14 @@ func (f *ResourceHandlers) getSpecHandler(ctx context.Context, w http.ResponseWr
|
||||
ret, e = module2.ListInContext(session, query, module, req.ResID())
|
||||
}
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, modulebase.ListResult2JSON(ret))
|
||||
}
|
||||
} else {
|
||||
obj, e := module.GetSpecific(session, req.ResID(), req.Spec(), query)
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -291,7 +291,7 @@ func (f *ResourceHandlers) getSpecHandler(ctx context.Context, w http.ResponseWr
|
||||
func (f *ResourceHandlers) getJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1().WithMod2()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -301,12 +301,12 @@ func (f *ResourceHandlers) getJointHandler(ctx context.Context, w http.ResponseW
|
||||
|
||||
jmod, e := modulebase.GetJointModule2(session, module, module2)
|
||||
if e != nil {
|
||||
httperrors.NotFoundError(w, fmt.Sprintf("resource %s-%s not exist", req.ResName(), req.ResName2()))
|
||||
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s-%s not exist", req.ResName(), req.ResName2()))
|
||||
return
|
||||
}
|
||||
obj, e := jmod.Get(session, req.ResID(), req.ResID2(), req.Query())
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -317,7 +317,7 @@ func (f *ResourceHandlers) getJointHandler(ctx context.Context, w http.ResponseW
|
||||
func (f *ResourceHandlers) listInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
module := req.Mod1()
|
||||
@@ -330,7 +330,7 @@ func (f *ResourceHandlers) listInContextsHandler(ctx context.Context, w http.Res
|
||||
{InstanceManager: module2, InstanceId: req.ResID2()},
|
||||
})
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, modulebase.ListResult2JSON(obj))
|
||||
}
|
||||
@@ -342,7 +342,7 @@ func (f *ResourceHandlers) listInContextsHandler(ctx context.Context, w http.Res
|
||||
func (f *ResourceHandlers) createHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
module := req.Mod1()
|
||||
@@ -353,7 +353,7 @@ func (f *ResourceHandlers) createHandler(ctx context.Context, w http.ResponseWri
|
||||
if e == nil && count > 1 {
|
||||
bodyDict, ok := body.(*jsonutils.JSONDict)
|
||||
if !ok {
|
||||
httperrors.GeneralServerError(w, fmt.Errorf("Fail to decode body"))
|
||||
httperrors.GeneralServerError(ctx, w, fmt.Errorf("Fail to decode body"))
|
||||
} else {
|
||||
nbody := bodyDict.Copy("__count__")
|
||||
ret := module.BatchCreate(session, nbody, int(count))
|
||||
@@ -363,7 +363,7 @@ func (f *ResourceHandlers) createHandler(ctx context.Context, w http.ResponseWri
|
||||
} else {
|
||||
obj, e := module.Create(session, body)
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -375,7 +375,7 @@ func (f *ResourceHandlers) createHandler(ctx context.Context, w http.ResponseWri
|
||||
func (f *ResourceHandlers) batchPerformActionHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
module := req.Mod1()
|
||||
@@ -385,7 +385,7 @@ func (f *ResourceHandlers) batchPerformActionHandler(ctx context.Context, w http
|
||||
|
||||
if idlist, e := query.GetArray("id"); e != nil || len(idlist) == 0 {
|
||||
if obj, e := module.PerformClassAction(session, req.Action(), body); e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -403,7 +403,7 @@ func (f *ResourceHandlers) batchPerformActionHandler(ctx context.Context, w http
|
||||
func (f *ResourceHandlers) performActionHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
module := req.Mod1()
|
||||
@@ -415,14 +415,14 @@ func (f *ResourceHandlers) performActionHandler(ctx context.Context, w http.Resp
|
||||
var idlist []string
|
||||
if module2, e := modulebase.GetModule(session, req.Action()); e == nil {
|
||||
if jmod, e := modulebase.GetJointModule2(session, module, module2); e == nil {
|
||||
if idlist = fetchIdList(query, w); idlist == nil {
|
||||
if idlist = fetchIdList(ctx, query, w); idlist == nil {
|
||||
return
|
||||
}
|
||||
ret := jmod.BatchAttach(session, req.ResID(), idlist, body)
|
||||
w.WriteHeader(207)
|
||||
appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
|
||||
} else if jmod, e := modulebase.GetJointModule2(session, module2, module); e == nil {
|
||||
if idlist = fetchIdList(query, w); idlist == nil {
|
||||
if idlist = fetchIdList(ctx, query, w); idlist == nil {
|
||||
return
|
||||
}
|
||||
ret := jmod.BatchAttach2(session, req.ResID(), idlist, body)
|
||||
@@ -430,14 +430,14 @@ func (f *ResourceHandlers) performActionHandler(ctx context.Context, w http.Resp
|
||||
appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
|
||||
} else {
|
||||
if obj, e = module2.CreateInContext(session, body, module, req.ResID()); e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if obj, e = module.PerformAction(session, req.ResID(), req.Action(), body); e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -449,7 +449,7 @@ func (f *ResourceHandlers) performActionHandler(ctx context.Context, w http.Resp
|
||||
func (f *ResourceHandlers) attachHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1().WithMod2()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
module := req.Mod1()
|
||||
@@ -459,12 +459,12 @@ func (f *ResourceHandlers) attachHandler(ctx context.Context, w http.ResponseWri
|
||||
|
||||
jmod, e := modulebase.GetJointModule2(session, module, module2)
|
||||
if e != nil {
|
||||
httperrors.NotFoundError(w, fmt.Sprintf("resource %s-%s not exists", req.ResName(), req.ResName2()))
|
||||
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s-%s not exists", req.ResName(), req.ResName2()))
|
||||
return
|
||||
}
|
||||
obj, e := jmod.Attach(session, req.ResID(), req.ResID2(), body)
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -475,7 +475,7 @@ func (f *ResourceHandlers) attachHandler(ctx context.Context, w http.ResponseWri
|
||||
func (f *ResourceHandlers) batchUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ func (f *ResourceHandlers) batchUpdateHandler(ctx context.Context, w http.Respon
|
||||
query := req.Query()
|
||||
body := req.Body()
|
||||
|
||||
idlist := fetchIdList(query, w)
|
||||
idlist := fetchIdList(ctx, query, w)
|
||||
if idlist == nil {
|
||||
return
|
||||
}
|
||||
@@ -498,7 +498,7 @@ func (f *ResourceHandlers) batchUpdateHandler(ctx context.Context, w http.Respon
|
||||
func (f *ResourceHandlers) batchPatchHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -506,7 +506,7 @@ func (f *ResourceHandlers) batchPatchHandler(ctx context.Context, w http.Respons
|
||||
query := req.Query()
|
||||
body := req.Body()
|
||||
|
||||
idlist := fetchIdList(query, w)
|
||||
idlist := fetchIdList(ctx, query, w)
|
||||
if idlist == nil {
|
||||
return
|
||||
}
|
||||
@@ -521,7 +521,7 @@ func (f *ResourceHandlers) batchPatchHandler(ctx context.Context, w http.Respons
|
||||
func (f *ResourceHandlers) updateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -530,7 +530,7 @@ func (f *ResourceHandlers) updateHandler(ctx context.Context, w http.ResponseWri
|
||||
|
||||
obj, e := module.Update(req.Session(), req.ResID(), body)
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -541,7 +541,7 @@ func (f *ResourceHandlers) updateHandler(ctx context.Context, w http.ResponseWri
|
||||
func (f *ResourceHandlers) patchHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -550,7 +550,7 @@ func (f *ResourceHandlers) patchHandler(ctx context.Context, w http.ResponseWrit
|
||||
|
||||
obj, e := module.Patch(req.Session(), req.ResID(), body)
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -562,7 +562,7 @@ func (f *ResourceHandlers) patchHandler(ctx context.Context, w http.ResponseWrit
|
||||
func (f *ResourceHandlers) updateJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1().WithMod2()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
session := req.Session()
|
||||
@@ -578,7 +578,7 @@ func (f *ResourceHandlers) updateJointHandler(ctx context.Context, w http.Respon
|
||||
obj, e = module2.PutInContext(session, req.ResID2(), body, module, req.ResID())
|
||||
}
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -587,7 +587,7 @@ func (f *ResourceHandlers) updateJointHandler(ctx context.Context, w http.Respon
|
||||
func (f *ResourceHandlers) patchJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1().WithMod2()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
session := req.Session()
|
||||
@@ -603,7 +603,7 @@ func (f *ResourceHandlers) patchJointHandler(ctx context.Context, w http.Respons
|
||||
obj, e = module2.PatchInContext(session, req.ResID2(), body, module, req.ResID())
|
||||
}
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -616,7 +616,7 @@ func (f *ResourceHandlers) patchJointHandler(ctx context.Context, w http.Respons
|
||||
func (f *ResourceHandlers) batchUpdateJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
session := req.Session()
|
||||
@@ -629,7 +629,7 @@ func (f *ResourceHandlers) batchUpdateJointHandler(ctx context.Context, w http.R
|
||||
spec := req.ResName2()
|
||||
obj, e := module.PutSpecific(session, req.ResID(), spec, query, body)
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -638,16 +638,16 @@ func (f *ResourceHandlers) batchUpdateJointHandler(ctx context.Context, w http.R
|
||||
|
||||
req = req.WithMod2()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
module2 := req.Mod2()
|
||||
jmod, e := modulebase.GetJointModule2(session, module, module2)
|
||||
if e != nil { // update joint
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
idlist := fetchIdList(query, w)
|
||||
idlist := fetchIdList(ctx, query, w)
|
||||
ret := jmod.BatchUpdate(session, req.ResID(), idlist, query, body)
|
||||
w.WriteHeader(207)
|
||||
appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
|
||||
@@ -658,7 +658,7 @@ func (f *ResourceHandlers) batchUpdateJointHandler(ctx context.Context, w http.R
|
||||
func (f *ResourceHandlers) updateInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -667,7 +667,7 @@ func (f *ResourceHandlers) updateInContextsHandler(ctx context.Context, w http.R
|
||||
{InstanceManager: req.Mod2(), InstanceId: req.ResID2()},
|
||||
})
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -676,7 +676,7 @@ func (f *ResourceHandlers) updateInContextsHandler(ctx context.Context, w http.R
|
||||
func (f *ResourceHandlers) patchInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
module := req.Mod1()
|
||||
@@ -690,7 +690,7 @@ func (f *ResourceHandlers) patchInContextsHandler(ctx context.Context, w http.Re
|
||||
{InstanceManager: module2, InstanceId: req.ResID2()},
|
||||
})
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -701,11 +701,11 @@ func (f *ResourceHandlers) patchInContextsHandler(ctx context.Context, w http.Re
|
||||
func (f *ResourceHandlers) batchDeleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
idlist := fetchIdList(req.Query(), w)
|
||||
idlist := fetchIdList(ctx, req.Query(), w)
|
||||
if idlist == nil {
|
||||
return
|
||||
}
|
||||
@@ -719,12 +719,12 @@ func (f *ResourceHandlers) batchDeleteHandler(ctx context.Context, w http.Respon
|
||||
func (f *ResourceHandlers) deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
obj, e := req.Mod1().DeleteWithParam(req.Session(), req.ResID(), req.Query(), req.Body())
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -735,10 +735,10 @@ func (f *ResourceHandlers) deleteHandler(ctx context.Context, w http.ResponseWri
|
||||
func (f *ResourceHandlers) batchDetachHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1().WithMod2()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
idlist := fetchIdList(req.Query(), w)
|
||||
idlist := fetchIdList(ctx, req.Query(), w)
|
||||
if idlist == nil {
|
||||
return
|
||||
}
|
||||
@@ -767,7 +767,7 @@ func (f *ResourceHandlers) batchDetachHandler(ctx context.Context, w http.Respon
|
||||
func (f *ResourceHandlers) detachHandle(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1().WithMod2()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
session := req.Session()
|
||||
@@ -782,7 +782,7 @@ func (f *ResourceHandlers) detachHandle(ctx context.Context, w http.ResponseWrit
|
||||
obj, e = module2.DeleteInContextWithParam(session, req.ResID2(), req.Query(), req.Body(), module, req.ResID())
|
||||
}
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
@@ -793,7 +793,7 @@ func (f *ResourceHandlers) detachHandle(ctx context.Context, w http.ResponseWrit
|
||||
func (f *ResourceHandlers) deleteInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
|
||||
if err := req.Error(); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
session := req.Session()
|
||||
@@ -808,7 +808,7 @@ func (f *ResourceHandlers) deleteInContextsHandler(ctx context.Context, w http.R
|
||||
{InstanceManager: module2, InstanceId: req.ResID2()},
|
||||
})
|
||||
if e != nil {
|
||||
httperrors.GeneralServerError(w, e)
|
||||
httperrors.GeneralServerError(ctx, w, e)
|
||||
} else {
|
||||
appsrv.SendJSON(w, obj)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ func RpcHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
log.Errorf("Error get JSON body: %s", e)
|
||||
}
|
||||
default:
|
||||
httperrors.InvalidInputError(w, fmt.Sprintf("Unsupported RPC method %s", req.Method))
|
||||
httperrors.InvalidInputError(ctx, w, fmt.Sprintf("Unsupported RPC method %s", req.Method))
|
||||
return
|
||||
}
|
||||
token := AppContextToken(ctx)
|
||||
@@ -91,13 +91,13 @@ func RpcHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
if e != nil {
|
||||
log.Debugf("module %s not found %s", resType, e)
|
||||
}
|
||||
httperrors.NotFoundError(w, fmt.Sprintf("resource %s not exists", resType))
|
||||
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s not exists", resType))
|
||||
return
|
||||
}
|
||||
modvalue := reflect.ValueOf(mod)
|
||||
funcvalue := modvalue.MethodByName(funcname)
|
||||
if !funcvalue.IsValid() || funcvalue.IsNil() {
|
||||
httperrors.NotFoundError(w, fmt.Sprintf("RPC method %s not found", funcname))
|
||||
httperrors.NotFoundError(ctx, w, fmt.Sprintf("RPC method %s not found", funcname))
|
||||
return
|
||||
}
|
||||
callParams := make([]reflect.Value, 0)
|
||||
@@ -127,14 +127,14 @@ func RpcHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
httperrors.BadGatewayError(w, "recv invalid data")
|
||||
httperrors.BadGatewayError(ctx, w, "recv invalid data")
|
||||
} else {
|
||||
v, ok := reterr.Interface().(*httputils.JSONClientError)
|
||||
if ok {
|
||||
httperrors.JsonClientError(w, v)
|
||||
httperrors.JsonClientError(ctx, w, v)
|
||||
return
|
||||
}
|
||||
|
||||
httperrors.BadGatewayError(w, fmt.Sprintf("%s", reterr.Interface()))
|
||||
httperrors.BadGatewayError(ctx, w, fmt.Sprintf("%s", reterr.Interface()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,6 +283,7 @@ func (app *Application) defaultHandle(w http.ResponseWriter, r *http.Request, ri
|
||||
if cancel != nil {
|
||||
defer cancel()
|
||||
}
|
||||
ctx = httperrors.WithRequestLang(ctx, r)
|
||||
session := hand.workerMan
|
||||
if session == nil {
|
||||
if r.Method == "GET" || r.Method == "HEAD" {
|
||||
@@ -321,7 +322,7 @@ func (app *Application) defaultHandle(w http.ResponseWriter, r *http.Request, ri
|
||||
},
|
||||
currentWorker,
|
||||
func(err error) {
|
||||
httperrors.InternalServerError(&fw, "Internal server error: %s", err)
|
||||
httperrors.InternalServerError(ctx, &fw, "Internal server error: %s", err)
|
||||
fw.closeChannels()
|
||||
},
|
||||
)
|
||||
@@ -330,20 +331,20 @@ func (app *Application) defaultHandle(w http.ResponseWriter, r *http.Request, ri
|
||||
switch runErr.(type) {
|
||||
case *httputils.JSONClientError:
|
||||
je := runErr.(*httputils.JSONClientError)
|
||||
httperrors.GeneralServerError(w, je)
|
||||
httperrors.GeneralServerError(ctx, w, je)
|
||||
default:
|
||||
httperrors.InternalServerError(w, "Internal server error")
|
||||
httperrors.InternalServerError(ctx, w, "Internal server error")
|
||||
}
|
||||
}
|
||||
fw.closeChannels()
|
||||
return hand, appParams
|
||||
} else {
|
||||
log.Errorf("Invalid handler for %s", r.URL)
|
||||
httperrors.InternalServerError(w, "Invalid handler %s", r.URL)
|
||||
ctx := httperrors.WithRequestLang(context.TODO(), r)
|
||||
httperrors.InternalServerError(ctx, w, "Invalid handler %s", r.URL)
|
||||
}
|
||||
} else if !isCors {
|
||||
log.Errorf("Handler not found")
|
||||
httperrors.NotFoundError(w, "Handler not found")
|
||||
ctx := httperrors.WithRequestLang(context.TODO(), r)
|
||||
httperrors.NotFoundError(ctx, w, "Handler not found")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ func listHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
func handleList(ctx context.Context, w http.ResponseWriter, manager IModelDispatchHandler, ctxIds []SResourceContext, query jsonutils.JSONObject) {
|
||||
listResult, err := manager.List(ctx, query, ctxIds)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, modulebase.ListResult2JSONWithKey(listResult, manager.KeywordPlural()))
|
||||
@@ -272,7 +272,7 @@ func getHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
result, err := manager.Get(ctx, params["<resid>"], mergeQueryParams(params, query, "<resid>"), false)
|
||||
if err != nil {
|
||||
e := httperrors.NewGeneralError(err)
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
if result != nil {
|
||||
@@ -285,7 +285,7 @@ func getSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
result, err := manager.GetSpecific(ctx, params["<resid>"], params["<spec>"], mergeQueryParams(params, query, "<resid>", "<spec>"))
|
||||
if err != nil {
|
||||
e := httperrors.NewGeneralError(err)
|
||||
httperrors.JsonClientError(w, e)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
if result != nil {
|
||||
@@ -293,6 +293,18 @@ func getSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func writeErrNoRequestKey(ctx context.Context, w http.ResponseWriter, r *http.Request, key string) {
|
||||
ctx = httperrors.WithRequestLang(ctx, r)
|
||||
httperrors.InvalidInputError(ctx, w,
|
||||
"No request key: %s", key)
|
||||
}
|
||||
|
||||
func writeErrInvalidRequestHeader(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) {
|
||||
ctx = httperrors.WithRequestLang(ctx, r)
|
||||
httperrors.InvalidInputError(ctx, w,
|
||||
"Invalid request header: %v", err)
|
||||
}
|
||||
|
||||
func createHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
manager, params, query, body := fetchEnv(ctx, w, r)
|
||||
handleCreate(ctx, w, manager, nil, mergeQueryParams(params, query), body, r)
|
||||
@@ -306,29 +318,27 @@ func handleCreate(ctx context.Context, w http.ResponseWriter, manager IModelDisp
|
||||
count, _ = body.Int("count")
|
||||
data, err = body.Get(manager.Keyword())
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w,
|
||||
fmt.Sprintf("No request key: %s", manager.Keyword()))
|
||||
writeErrNoRequestKey(ctx, w, r, manager.Keyword())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
data, err = manager.FetchCreateHeaderData(ctx, r.Header)
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w,
|
||||
fmt.Sprintf("In valid request header: %s", err))
|
||||
writeErrInvalidRequestHeader(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if count <= 1 {
|
||||
result, err := manager.Create(ctx, query, data, ctxIds)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
|
||||
} else {
|
||||
results, err := manager.BatchCreate(ctx, query, data, int(count), ctxIds)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
ret := jsonutils.NewArray()
|
||||
@@ -365,7 +375,7 @@ func performClassActionHandler(ctx context.Context, w http.ResponseWriter, r *ht
|
||||
}
|
||||
results, err := manager.PerformClassAction(ctx, params["<action>"], mergeQueryParams(params, query, "<action>"), data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
if results == nil {
|
||||
@@ -392,31 +402,13 @@ func performActionHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
result, err := manager.PerformAction(ctx, params["<resid>"], params["<action>"], mergeQueryParams(params, query, "<resid>", "<action>"), data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
sendJSON(ctx, w, result, manager.Keyword())
|
||||
// appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
|
||||
}
|
||||
|
||||
/*
|
||||
func updateClassHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
manager, _, query, body := fetchEnv(ctx, w, r)
|
||||
data, err := body.Get(manager.KeywordPlural())
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w,
|
||||
fmt.Sprintf("No request key: %s", manager.KeywordPlural()))
|
||||
return
|
||||
}
|
||||
result, err := manager.UpdateClass(ctx, tr, data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, wrapBody(result, manager.KeywordPlural()))
|
||||
}
|
||||
*/
|
||||
|
||||
func updateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
manager, params, query, body := fetchEnv(ctx, w, r)
|
||||
handleUpdate(ctx, w, manager, params["<resid>"], nil, mergeQueryParams(params, query, "<resid>"), body, r)
|
||||
@@ -429,8 +421,7 @@ func handleUpdate(ctx context.Context, w http.ResponseWriter, manager IModelDisp
|
||||
if body.Contains(manager.Keyword()) {
|
||||
data, err = body.Get(manager.Keyword())
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w,
|
||||
fmt.Sprintf("No request key: %s", manager.Keyword()))
|
||||
writeErrNoRequestKey(ctx, w, r, manager.Keyword())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -439,14 +430,13 @@ func handleUpdate(ctx context.Context, w http.ResponseWriter, manager IModelDisp
|
||||
} else {
|
||||
data, err = manager.FetchUpdateHeaderData(ctx, r.Header)
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w,
|
||||
fmt.Sprintf("In valid request header: %s", err))
|
||||
writeErrInvalidRequestHeader(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
result, err := manager.Update(ctx, resId, query, data, ctxIds)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
sendJSON(ctx, w, result, manager.Keyword())
|
||||
@@ -468,8 +458,7 @@ func updateSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Reque
|
||||
if body.Contains(manager.Keyword()) {
|
||||
data, err = body.Get(manager.Keyword())
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w,
|
||||
fmt.Sprintf("No request key: %s", manager.Keyword()))
|
||||
writeErrNoRequestKey(ctx, w, r, manager.Keyword())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -478,41 +467,19 @@ func updateSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Reque
|
||||
} else {
|
||||
data, err = manager.FetchUpdateHeaderData(ctx, r.Header)
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w,
|
||||
fmt.Sprintf("In valid request header: %s", err))
|
||||
writeErrInvalidRequestHeader(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
result, err := manager.UpdateSpec(ctx, params["<resid>"], params["<spec>"], mergeQueryParams(params, query, "<resid>", "<spec>"), data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
sendJSON(ctx, w, result, manager.Keyword())
|
||||
// appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
|
||||
}
|
||||
|
||||
/*
|
||||
func deleteClassHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
tr, manager, _, query, body := fetchEnv(ctx, w, r)
|
||||
var data jsonutils.JSONObject
|
||||
if body != nil {
|
||||
data, err := body.Get(manager.KeywordPlural())
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w,
|
||||
fmt.Sprintf("No request key: %s", manager.KeywordPlural()))
|
||||
return
|
||||
}
|
||||
}
|
||||
result, err := manager.DeleteClass(ctx, tr, query, data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, wrapBody(result, manager.KeywordPlural()))
|
||||
}
|
||||
*/
|
||||
|
||||
func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
manager, params, query, body := fetchEnv(ctx, w, r)
|
||||
handleDelete(ctx, w, manager, params["<resid>"], nil, mergeQueryParams(params, query, "<resid>"), body, r)
|
||||
@@ -525,8 +492,7 @@ func handleDelete(ctx context.Context, w http.ResponseWriter, manager IModelDisp
|
||||
if body.Contains(manager.Keyword()) {
|
||||
data, err = body.Get(manager.Keyword())
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w,
|
||||
fmt.Sprintf("No request key: %s", manager.Keyword()))
|
||||
writeErrNoRequestKey(ctx, w, r, manager.Keyword())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -537,7 +503,7 @@ func handleDelete(ctx context.Context, w http.ResponseWriter, manager IModelDisp
|
||||
}
|
||||
result, err := manager.Delete(ctx, resId, query, data, ctxIds)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
sendJSON(ctx, w, result, manager.Keyword())
|
||||
@@ -559,8 +525,7 @@ func deleteSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Reque
|
||||
if body.Contains(manager.Keyword()) {
|
||||
data, err = body.Get(manager.Keyword())
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w,
|
||||
fmt.Sprintf("No request key: %s", manager.Keyword()))
|
||||
writeErrNoRequestKey(ctx, w, r, manager.Keyword())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -571,7 +536,7 @@ func deleteSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
result, err := manager.DeleteSpec(ctx, params["<resid>"], params["<spec>"], mergeQueryParams(params, query, "<resid>", "<spec>"), data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
sendJSON(ctx, w, result, manager.Keyword())
|
||||
|
||||
@@ -118,7 +118,7 @@ func jointListHandler(ctx context.Context, w http.ResponseWriter, r *http.Reques
|
||||
manager, params, query, _ := fetchJointEnv(ctx, w, r)
|
||||
listResult, err := manager.List(ctx, mergeQueryParams(params, query), nil)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, modulebase.ListResult2JSONWithKey(listResult, manager.KeywordPlural()))
|
||||
@@ -134,7 +134,7 @@ func jointListDescendentHandler(ctx context.Context, w http.ResponseWriter, r *h
|
||||
listResult, err = manager.ListSlaveDescendent(ctx, params["<slave_id>"], mergeQueryParams(params, query, "<slave_id>"))
|
||||
}
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, modulebase.ListResult2JSONWithKey(listResult, manager.KeywordPlural()))
|
||||
@@ -144,7 +144,7 @@ func jointGetHandler(ctx context.Context, w http.ResponseWriter, r *http.Request
|
||||
manager, params, query, _ := fetchJointEnv(ctx, w, r)
|
||||
result, err := manager.Get(ctx, params["<master_id>"], params["<slave_id>"], mergeQueryParams(params, query, "<master_id>", "<slave_id>"))
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
|
||||
@@ -162,7 +162,7 @@ func attachHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
result, err := manager.Attach(ctx, params["<master_id>"], params["<slave_id>"], mergeQueryParams(params, query, "<master_id>", "<slave_id>"), data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
|
||||
@@ -172,12 +172,12 @@ func updateJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
manager, params, query, body := fetchJointEnv(ctx, w, r)
|
||||
data, err := body.Get(manager.Keyword())
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
result, err := manager.Update(ctx, params["<master_id>"], params["<slave_id>"], mergeQueryParams(params, query, "<master_id>", "<slave_id>"), data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
|
||||
@@ -191,7 +191,7 @@ func detachHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
result, err := manager.Detach(ctx, params["<master_id>"], params["<slave_id>"], mergeQueryParams(params, query, "<master_id>", "<slave_id>"), data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
|
||||
|
||||
@@ -261,7 +261,7 @@ func (ctx *Context) ResponseJson(obj jsonutils.JSONObject) {
|
||||
}
|
||||
|
||||
func (ctx *Context) ResponseError(err error) {
|
||||
httperrors.GeneralServerError(ctx.writer, err)
|
||||
httperrors.GeneralServerError(ctx, ctx.writer, err)
|
||||
}
|
||||
|
||||
func (ctx *Context) Request() *http.Request {
|
||||
|
||||
@@ -274,8 +274,8 @@ func (i *BmRegisterInput) responseSucc(bmId string) {
|
||||
close(i.C)
|
||||
}
|
||||
|
||||
func (i *BmRegisterInput) responseErr(err error) {
|
||||
httperrors.GeneralServerError(i.W, err)
|
||||
func (i *BmRegisterInput) responseErr(ctx context.Context, err error) {
|
||||
httperrors.GeneralServerError(ctx, i.W, err)
|
||||
close(i.C)
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
|
||||
if input.isTimeout() {
|
||||
return
|
||||
} else if err != nil {
|
||||
input.responseErr(httperrors.NewBadRequestError("Verify network failed: %s", err))
|
||||
input.responseErr(ctx, httperrors.NewBadRequestError("Verify network failed: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
|
||||
if input.isTimeout() {
|
||||
return
|
||||
} else if err != nil {
|
||||
input.responseErr(httperrors.NewBadRequestError("SSH verify failed: %s", err))
|
||||
input.responseErr(ctx, httperrors.NewBadRequestError("SSH verify failed: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -311,7 +311,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
|
||||
if input.isTimeout() {
|
||||
return
|
||||
} else if err != nil {
|
||||
input.responseErr(httperrors.NewBadRequestError("Fetch ipmi address failed: %s", err))
|
||||
input.responseErr(ctx, httperrors.NewBadRequestError("Fetch ipmi address failed: %s", err))
|
||||
return
|
||||
}
|
||||
log.Infof("Find ipmi address %s", input.IpAddr)
|
||||
@@ -320,7 +320,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
|
||||
if input.isTimeout() {
|
||||
return
|
||||
} else if err != nil {
|
||||
input.responseErr(httperrors.NewBadRequestError("Verify network failed: %s", err))
|
||||
input.responseErr(ctx, httperrors.NewBadRequestError("Verify network failed: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -328,7 +328,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
|
||||
if input.isTimeout() {
|
||||
return
|
||||
} else if err != nil {
|
||||
input.responseErr(httperrors.NewBadRequestError("IPMI login info not correct: %s", err))
|
||||
input.responseErr(ctx, httperrors.NewBadRequestError("IPMI login info not correct: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
|
||||
if input.isTimeout() {
|
||||
return
|
||||
} else if err != nil {
|
||||
input.responseErr(httperrors.NewBadRequestError("Verify mac address failed: %s", err))
|
||||
input.responseErr(ctx, httperrors.NewBadRequestError("Verify mac address failed: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
|
||||
bmId, err = registerTask.UpdateBaremetal()
|
||||
}
|
||||
if err != nil {
|
||||
input.responseErr(httperrors.NewInternalServerError(err.Error()))
|
||||
input.responseErr(ctx, httperrors.NewInternalServerError("%v", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ func performImageCache(
|
||||
|
||||
disk, err := body.Get("disk")
|
||||
if err != nil {
|
||||
httperrors.MissingParameterError(w, "disk")
|
||||
httperrors.MissingParameterError(ctx, w, "disk")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -109,7 +108,7 @@ func callObject(modelVal reflect.Value, fName string, inputs ...interface{}) ([]
|
||||
|
||||
func callFunc(funcVal reflect.Value, fName string, inputs ...interface{}) ([]reflect.Value, error) {
|
||||
if !funcVal.IsValid() || funcVal.IsNil() {
|
||||
return nil, httperrors.NewActionNotFoundError(fmt.Sprintf("%s method not found", fName))
|
||||
return nil, httperrors.NewActionNotFoundError("%s method not found", fName)
|
||||
}
|
||||
funcType := funcVal.Type()
|
||||
paramLen := funcType.NumIn()
|
||||
|
||||
@@ -1165,7 +1165,7 @@ func _doCreateItem(
|
||||
|
||||
err = jsonutils.CheckRequiredFields(dataDict, createRequireFields(manager, userCred))
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
model, err := NewModelObject(manager)
|
||||
if err != nil {
|
||||
@@ -1398,7 +1398,7 @@ func (dispatcher *DBModelDispatcher) BatchCreate(ctx context.Context, query json
|
||||
body, err := getItemDetails(manager, res.model, ctx, userCred, query)
|
||||
if err != nil {
|
||||
result.Status = 500
|
||||
result.Data = jsonutils.NewString(err.Error())
|
||||
result.Data = jsonutils.NewString(err.Error()) // no translation here
|
||||
} else {
|
||||
result.Status = 200
|
||||
result.Data = body
|
||||
@@ -1535,9 +1535,8 @@ func reflectDispatcherInternal(
|
||||
if !funcValue.IsValid() || funcValue.IsNil() {
|
||||
funcValue = modelValue.MethodByName(generalFuncName)
|
||||
if !funcValue.IsValid() || funcValue.IsNil() {
|
||||
msg := fmt.Sprintf("%s %s %s not found", dispatcher.Keyword(), operator, spec)
|
||||
log.Errorf(msg)
|
||||
return nil, httperrors.NewActionNotFoundError(msg)
|
||||
return nil, httperrors.NewActionNotFoundError("%s %s %s not found",
|
||||
dispatcher.Keyword(), operator, spec)
|
||||
} else {
|
||||
isGeneral = true
|
||||
funcName = generalFuncName
|
||||
@@ -1572,9 +1571,8 @@ func reflectDispatcherInternal(
|
||||
allowFuncName := "Allow" + funcName
|
||||
allowFuncValue := modelValue.MethodByName(allowFuncName)
|
||||
if !allowFuncValue.IsValid() || allowFuncValue.IsNil() {
|
||||
msg := fmt.Sprintf("%s allow %s %s not found", dispatcher.Keyword(), operator, spec)
|
||||
log.Errorf(msg)
|
||||
return nil, httperrors.NewActionNotFoundError(msg)
|
||||
return nil, httperrors.NewActionNotFoundError("%s allow %s %s not found",
|
||||
dispatcher.Keyword(), operator, spec)
|
||||
}
|
||||
|
||||
outs, err := callFunc(allowFuncValue, allowFuncName, params...)
|
||||
@@ -1741,7 +1739,7 @@ func deleteItem(manager IModelManager, model IModel, ctx context.Context, userCr
|
||||
err = CustomizeDelete(model, ctx, userCred, query, data)
|
||||
if err != nil {
|
||||
log.Errorf("customize delete error: %s", err)
|
||||
return nil, httperrors.NewNotAcceptableError(err.Error())
|
||||
return nil, httperrors.NewNotAcceptableError("%v", err)
|
||||
}
|
||||
|
||||
details, err := getItemDetails(manager, model, ctx, userCred, query)
|
||||
|
||||
@@ -387,7 +387,8 @@ func FetchCheckQueryOwnerScope(ctx context.Context, userCred mcclient.TokenCrede
|
||||
requireScope = queryScope
|
||||
}
|
||||
if doCheckRbac && requireScope.HigherThan(allowScope) {
|
||||
return nil, scope, httperrors.NewForbiddenError(fmt.Sprintf("not enough privilege(require:%s,allow:%s,query:%s)", requireScope, allowScope, queryScope))
|
||||
return nil, scope, httperrors.NewForbiddenError("not enough privilege (require:%s,allow:%s,query:%s)",
|
||||
requireScope, allowScope, queryScope)
|
||||
}
|
||||
return ownerId, queryScope, nil
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func AddScopeResourceCountHandler(prefix string, app *appsrv.Application) {
|
||||
func getAllScopeResourceCountsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
cnt, err := getAllScopeResourceCounts()
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, jsonutils.Marshal(cnt))
|
||||
|
||||
@@ -186,7 +186,7 @@ func (manager *SQuotaBaseManager) getQuotaHandler(ctx context.Context, w http.Re
|
||||
}
|
||||
ownerId, scope, err = db.FetchCheckQueryOwnerScope(ctx, userCred, data, manager.GetIQuotaManager(), policy.PolicyActionGet, true)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -206,7 +206,7 @@ func (manager *SQuotaBaseManager) getQuotaHandler(ctx context.Context, w http.Re
|
||||
primary := jsonutils.QueryBoolean(query, "primary", false)
|
||||
quotaList, err := manager.listQuotas(ctx, userCred, keys.DomainId, keys.ProjectId, scope == rbacutils.ScopeDomain, primary, refresh)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
if len(quotaList) == 0 {
|
||||
@@ -223,7 +223,7 @@ func (manager *SQuotaBaseManager) getQuotaHandler(ctx context.Context, w http.Re
|
||||
|
||||
quotaList, err = manager.listQuotas(ctx, userCred, keys.DomainId, keys.ProjectId, scope == rbacutils.ScopeDomain, primary, refresh)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -301,7 +301,7 @@ func (manager *SQuotaBaseManager) cleanPendingUsageHandler(ctx context.Context,
|
||||
}
|
||||
ownerId, scope, err = db.FetchCheckQueryOwnerScope(ctx, userCred, data, manager, policy.PolicyActionGet, true)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -323,7 +323,7 @@ func (manager *SQuotaBaseManager) cleanPendingUsageHandler(ctx context.Context,
|
||||
}
|
||||
err = manager.cleanPendingUsage(ctx, userCred, keys)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
rbody := jsonutils.NewDict()
|
||||
@@ -347,7 +347,7 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
|
||||
err := body.Unmarshal(quota, manager.KeywordPlural())
|
||||
if err != nil {
|
||||
log.Errorf("Fail to decode JSON request body: %s", err)
|
||||
httperrors.InvalidInputError(w, "fail to decode body")
|
||||
httperrors.InvalidInputError(httperrors.WithRequestLang(ctx, r), w, "fail to decode body")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
|
||||
}
|
||||
ownerId, scope, requestScope, err := manager.fetchSetQuotaScope(ctx, userCred, data, isBaseQuota)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
|
||||
if err != nil {
|
||||
if errors.Cause(err) != sql.ErrNoRows {
|
||||
log.Errorf("get quota %s fail %s", QuotaKeyString(keys), err)
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
} else {
|
||||
isNew = true
|
||||
@@ -393,11 +393,11 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
|
||||
if action == QUOTA_ACTION_DELETE {
|
||||
if isNew {
|
||||
// no need to delete
|
||||
httperrors.NotFoundError(w, "Quota %s not found", QuotaKeyString(keys))
|
||||
httperrors.NotFoundError(ctx, w, "Quota %s not found", QuotaKeyString(keys))
|
||||
return
|
||||
} else if isBaseQuota {
|
||||
// base quota is not deletable
|
||||
httperrors.ForbiddenError(w, "Default quota %s not allow to delete", QuotaKeyString(keys))
|
||||
httperrors.ForbiddenError(ctx, w, "Default quota %s not allow to delete", QuotaKeyString(keys))
|
||||
return
|
||||
}
|
||||
policyAction = policy.PolicyActionDelete
|
||||
@@ -414,14 +414,14 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
|
||||
// check rbac policy
|
||||
ownerScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policyAction)
|
||||
if requestScope.HigherThan(ownerScope) {
|
||||
httperrors.ForbiddenError(w, "not enough privilleges")
|
||||
httperrors.ForbiddenError(ctx, w, "not enough privilleges")
|
||||
return
|
||||
}
|
||||
|
||||
if action == QUOTA_ACTION_DELETE {
|
||||
err = manager.DeleteQuota(ctx, userCred, keys)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -445,14 +445,14 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
|
||||
err = manager.SetQuota(ctx, userCred, oquota)
|
||||
if err != nil {
|
||||
log.Errorf("set quota fail %s", err)
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
quotaList, err := manager.listQuotas(ctx, userCred, baseKeys.OwnerId().GetProjectDomainId(), baseKeys.OwnerId().GetProjectId(), scope == rbacutils.ScopeDomain, false, true)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
manager.sendQuotaList(w, quotaList)
|
||||
@@ -465,12 +465,12 @@ func (manager *SQuotaBaseManager) listDomainQuotaHandler(ctx context.Context, w
|
||||
if consts.IsRbacEnabled() {
|
||||
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionList)
|
||||
if allowScope != rbacutils.ScopeSystem {
|
||||
httperrors.ForbiddenError(w, "not allow to list domain quotas")
|
||||
httperrors.ForbiddenError(ctx, w, "not allow to list domain quotas")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !userCred.HasSystemAdminPrivilege() {
|
||||
httperrors.ForbiddenError(w, "out of privileges")
|
||||
httperrors.ForbiddenError(ctx, w, "out of privileges")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -479,7 +479,7 @@ func (manager *SQuotaBaseManager) listDomainQuotaHandler(ctx context.Context, w
|
||||
primary := jsonutils.QueryBoolean(query, "primary", false)
|
||||
quotaList, err := manager.listQuotas(ctx, userCred, "", "", false, primary, refresh)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
manager.sendQuotaList(w, sortQuotaByUsage(quotaList))
|
||||
@@ -496,7 +496,7 @@ func (manager *SQuotaBaseManager) listProjectQuotaHandler(ctx context.Context, w
|
||||
_, query, _ := appsrv.FetchEnv(ctx, w, r)
|
||||
owner, err := db.FetchDomainInfo(ctx, query)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
if owner == nil {
|
||||
@@ -507,12 +507,12 @@ func (manager *SQuotaBaseManager) listProjectQuotaHandler(ctx context.Context, w
|
||||
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionList)
|
||||
if (allowScope == rbacutils.ScopeDomain && userCred.GetProjectDomainId() == owner.GetProjectDomainId()) || allowScope == rbacutils.ScopeSystem {
|
||||
} else {
|
||||
httperrors.ForbiddenError(w, "not allow to list project quotas")
|
||||
httperrors.ForbiddenError(ctx, w, "not allow to list project quotas")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !userCred.HasSystemAdminPrivilege() {
|
||||
httperrors.ForbiddenError(w, "out of privileges")
|
||||
httperrors.ForbiddenError(ctx, w, "out of privileges")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -522,7 +522,7 @@ func (manager *SQuotaBaseManager) listProjectQuotaHandler(ctx context.Context, w
|
||||
primary := jsonutils.QueryBoolean(query, "primary", false)
|
||||
quotaList, err := manager.listQuotas(ctx, userCred, domainId, "", false, primary, refresh)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
manager.sendQuotaList(w, sortQuotaByUsage(quotaList))
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
@@ -72,7 +70,7 @@ func isObjectRbacAllowed(model IModel, userCred mcclient.TokenCredential, action
|
||||
if !requireScope.HigherThan(scope) {
|
||||
return nil
|
||||
}
|
||||
return httperrors.NewForbiddenError(fmt.Sprintf("not enough privilege(require:%s,allow:%s:resource:%s)", requireScope, scope, resScope))
|
||||
return httperrors.NewForbiddenError("not enough privilege (require:%s,allow:%s:resource:%s)", requireScope, scope, resScope)
|
||||
}
|
||||
|
||||
func isJointObjectRbacAllowed(item IJointModel, userCred mcclient.TokenCredential, action string, extra ...string) error {
|
||||
@@ -124,7 +122,7 @@ func isClassRbacAllowed(manager IModelManager, userCred mcclient.TokenCredential
|
||||
if !requireScope.HigherThan(allowScope) {
|
||||
return nil
|
||||
}
|
||||
return httperrors.NewForbiddenError(fmt.Sprintf("not enough privilege(require:%s,allow:%s)", requireScope, allowScope))
|
||||
return httperrors.NewForbiddenError("not enough privilege (require:%s,allow:%s)", requireScope, allowScope)
|
||||
}
|
||||
|
||||
type IResource interface {
|
||||
|
||||
@@ -111,11 +111,11 @@ func newInvalidIntChoiceError(key string, choices []int64, choice int64) error {
|
||||
}
|
||||
|
||||
func newStringTooShortError(key string, got, want int) error {
|
||||
return newError(ERR_INVALID_LENGTH, "%q too short, got %d, min %s", key, got, want)
|
||||
return newError(ERR_INVALID_LENGTH, "%q too short, got %d, min %d", key, got, want)
|
||||
}
|
||||
|
||||
func newStringTooLongError(key string, got, want int) error {
|
||||
return newError(ERR_INVALID_LENGTH, "%q too long, got %d, max %s", key, got, want)
|
||||
return newError(ERR_INVALID_LENGTH, "%q too long, got %d, max %d", key, got, want)
|
||||
}
|
||||
|
||||
func newNotInRangeError(key string, value, lower, upper int64) error {
|
||||
|
||||
@@ -36,12 +36,12 @@ func capaHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
capa, err := models.GetCapabilities(ctx, userCred, query, nil, nil)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, jsonutils.Marshal(capa))
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
@@ -56,14 +55,14 @@ func getBmAgentUrl(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
|
||||
n, _ := models.NetworkManager.GetOnPremiseNetworkOfIP(ipAddr, "", tristate.None)
|
||||
if n == nil {
|
||||
httperrors.NotFoundError(w, "Network not found")
|
||||
httperrors.NotFoundError(ctx, w, "Network not found")
|
||||
return
|
||||
}
|
||||
|
||||
zoneId := n.GetWire().ZoneId
|
||||
bmAgent := models.BaremetalagentManager.GetAgent(compute.AgentTypeBaremetal, zoneId)
|
||||
if bmAgent == nil {
|
||||
httperrors.InternalServerError(w, "Baremetal agent not found")
|
||||
httperrors.InternalServerError(ctx, w, "Baremetal agent not found")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -72,13 +71,12 @@ func getBmAgentUrl(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
|
||||
func getBmPrepareScript(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
if len(options.Options.BaremetalPreparePackageUrl) == 0 {
|
||||
httperrors.NotAcceptableError(w, "Baremetal package not prepared")
|
||||
httperrors.NotAcceptableError(ctx, w, "Baremetal package not prepared")
|
||||
return
|
||||
}
|
||||
regionUrl, err := auth.GetPublicServiceURL("compute_v2", options.Options.Region, "")
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
httperrors.InternalServerError(w, err.Error())
|
||||
httperrors.InternalServerError(ctx, w, "%v", err)
|
||||
return
|
||||
}
|
||||
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
|
||||
|
||||
@@ -532,7 +532,7 @@ func (manager *SDiskManager) validateDiskOnStorage(diskConfig *api.DiskConfig, s
|
||||
if host := storage.GetMasterHost(); host != nil {
|
||||
//公有云磁盘大小检查。
|
||||
if err := host.GetHostDriver().ValidateDiskSize(storage, diskConfig.SizeMb>>10); err != nil {
|
||||
return httperrors.NewInputParameterError(err.Error())
|
||||
return httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
}
|
||||
hoststorages := HoststorageManager.Query().SubQuery()
|
||||
@@ -916,7 +916,7 @@ func (disk *SDisk) doResize(ctx context.Context, userCred mcclient.TokenCredenti
|
||||
}
|
||||
if host := storage.GetMasterHost(); host != nil {
|
||||
if err := host.GetHostDriver().ValidateDiskSize(storage, sizeMb>>10); err != nil {
|
||||
return httperrors.NewInputParameterError(err.Error())
|
||||
return httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
}
|
||||
if int64(addDisk) > storage.GetFreeCapacity() && !storage.IsEmulated {
|
||||
@@ -924,7 +924,7 @@ func (disk *SDisk) doResize(ctx context.Context, userCred mcclient.TokenCredenti
|
||||
}
|
||||
if guest != nil {
|
||||
if err := guest.ValidateResizeDisk(disk, storage); err != nil {
|
||||
return httperrors.NewInputParameterError(err.Error())
|
||||
return httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
}
|
||||
pendingUsage := SQuota{Storage: int(addDisk)}
|
||||
|
||||
@@ -1345,7 +1345,7 @@ func (self *SElasticip) PerformChangeBandwidth(ctx context.Context, userCred mcc
|
||||
}
|
||||
|
||||
if err := factory.ValidateChangeBandwidth(self.AssociateId, bandwidth); err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ func (group *SGroup) ValidateDeleteCondition(ctx context.Context) error {
|
||||
return errors.Wrapf(err, "fail to check that if there are any guest in this group %s", group.Name)
|
||||
}
|
||||
if count > 0 {
|
||||
return httperrors.NewUnsupportOperationError("请在解绑所有主机后重试")
|
||||
return httperrors.NewUnsupportOperationError("please retry after unbind all guests in group")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -582,7 +582,7 @@ func (self *SGuest) PerformDeploy(ctx context.Context, userCred mcclient.TokenCr
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("update keypair fail: %s", err)
|
||||
return nil, httperrors.NewInternalServerError(err.Error())
|
||||
return nil, httperrors.NewInternalServerError("%v", err)
|
||||
}
|
||||
|
||||
db.OpsLog.LogEvent(self, db.ACT_UPDATE, diff, userCred)
|
||||
@@ -615,7 +615,7 @@ func (self *SGuest) PerformDeploy(ctx context.Context, userCred mcclient.TokenCr
|
||||
|
||||
deployStatus, err := self.GetDriver().GetDeployStatus()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
|
||||
if utils.IsInStringArray(self.Status, deployStatus) {
|
||||
@@ -1427,7 +1427,7 @@ func (self *SGuest) PerformRebuildRoot(ctx context.Context, userCred mcclient.To
|
||||
|
||||
rebuildStatus, err := self.GetDriver().GetRebuildRootStatus()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
|
||||
if !self.GetDriver().IsRebuildRootSupportChangeImage() && len(imageId) > 0 {
|
||||
@@ -1569,7 +1569,7 @@ func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.Tok
|
||||
diskInfo, err := parseDiskInfo(ctx, userCred, diskDefArray[diskIdx])
|
||||
if err != nil {
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_CREATE, err.Error(), userCred, false)
|
||||
return nil, httperrors.NewBadRequestError(err.Error())
|
||||
return nil, httperrors.NewBadRequestError("%v", err)
|
||||
}
|
||||
if len(diskInfo.Backend) == 0 {
|
||||
diskInfo.Backend = self.getDefaultStorageType()
|
||||
@@ -1609,7 +1609,7 @@ func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.Tok
|
||||
err = quotas.CheckSetPendingQuota(ctx, userCred, pendingUsage)
|
||||
if err != nil {
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_CREATE, err.Error(), userCred, false)
|
||||
return nil, httperrors.NewOutOfQuotaError(err.Error())
|
||||
return nil, httperrors.NewOutOfQuotaError("%v", err)
|
||||
}
|
||||
|
||||
lockman.LockObject(ctx, host)
|
||||
@@ -1619,7 +1619,7 @@ func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.Tok
|
||||
if err != nil {
|
||||
quotas.CancelPendingUsage(ctx, userCred, pendingUsage, pendingUsage, false)
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_CREATE, err.Error(), userCred, false)
|
||||
return nil, httperrors.NewBadRequestError(err.Error())
|
||||
return nil, httperrors.NewBadRequestError("%v", err)
|
||||
}
|
||||
err = self.StartGuestCreateDiskTask(ctx, userCred, disksConf, "")
|
||||
return nil, err
|
||||
@@ -1755,9 +1755,10 @@ func (self *SGuest) PerformDetachIsolatedDevice(ctx context.Context, userCred mc
|
||||
func (self *SGuest) startDetachIsolateDevice(ctx context.Context, userCred mcclient.TokenCredential, device string) error {
|
||||
iDev, err := IsolatedDeviceManager.FetchByIdOrName(userCred, device)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Isolated device %s not found", device)
|
||||
msgFmt := "Isolated device %s not found"
|
||||
msg := fmt.Sprintf(msgFmt, device)
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false)
|
||||
return httperrors.NewBadRequestError(msg)
|
||||
return httperrors.NewBadRequestError(msgFmt, device)
|
||||
}
|
||||
dev := iDev.(*SIsolatedDevice)
|
||||
host := self.GetHost()
|
||||
@@ -1848,9 +1849,10 @@ func (self *SGuest) startAttachIsolatedDevices(ctx context.Context, userCred mcc
|
||||
func (self *SGuest) startAttachIsolatedDevice(ctx context.Context, userCred mcclient.TokenCredential, device string) error {
|
||||
iDev, err := IsolatedDeviceManager.FetchByIdOrName(userCred, device)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Isolated device %s not found", device)
|
||||
msgFmt := "Isolated device %s not found"
|
||||
msg := fmt.Sprintf(msgFmt, device)
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_ATTACH_ISOLATED_DEVICE, msg, userCred, false)
|
||||
return httperrors.NewBadRequestError(msg)
|
||||
return httperrors.NewBadRequestError(msgFmt, device)
|
||||
}
|
||||
dev := iDev.(*SIsolatedDevice)
|
||||
host := self.GetHost()
|
||||
@@ -2062,7 +2064,7 @@ func (self *SGuest) PerformChangeIpaddr(ctx context.Context, userCred mcclient.T
|
||||
if err2 != nil {
|
||||
log.Errorf("recover detached network fail %s", err2)
|
||||
}
|
||||
return nil, httperrors.NewBadRequestError(err.Error())
|
||||
return nil, httperrors.NewBadRequestError("%v", err)
|
||||
}
|
||||
|
||||
return ngn, nil
|
||||
@@ -2188,7 +2190,7 @@ func (self *SGuest) PerformAttachnetwork(ctx context.Context, userCred mcclient.
|
||||
pendingUsage.SetKeys(keys)
|
||||
err = quotas.CheckSetPendingQuota(ctx, userCred, pendingUsage)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewOutOfQuotaError(err.Error())
|
||||
return nil, httperrors.NewOutOfQuotaError("%v", err)
|
||||
}
|
||||
host := self.GetHost()
|
||||
defer host.ClearSchedDescCache()
|
||||
@@ -2197,7 +2199,7 @@ func (self *SGuest) PerformAttachnetwork(ctx context.Context, userCred mcclient.
|
||||
logclient.AddSimpleActionLog(self, logclient.ACT_ATTACH_NETWORK, input.Nets[i], userCred, err == nil)
|
||||
if err != nil {
|
||||
quotas.CancelPendingUsage(ctx, userCred, pendingUsage, pendingUsage, false)
|
||||
return nil, httperrors.NewBadRequestError(err.Error())
|
||||
return nil, httperrors.NewBadRequestError("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2218,8 +2220,7 @@ func (self *SGuest) AllowPerformChangeBandwidth(ctx context.Context, userCred mc
|
||||
|
||||
func (self *SGuest) PerformChangeBandwidth(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
if !utils.IsInStringArray(self.Status, []string{api.VM_READY, api.VM_RUNNING}) {
|
||||
msg := fmt.Sprintf("Cannot change bandwidth in status %s", self.Status)
|
||||
return nil, httperrors.NewBadRequestError(msg)
|
||||
return nil, httperrors.NewBadRequestError("Cannot change bandwidth in status %s", self.Status)
|
||||
}
|
||||
|
||||
bandwidth, err := data.Int("bandwidth")
|
||||
@@ -2256,8 +2257,7 @@ func (self *SGuest) AllowPerformModifySrcCheck(ctx context.Context, userCred mcc
|
||||
|
||||
func (self *SGuest) PerformModifySrcCheck(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
if !utils.IsInStringArray(self.Status, []string{api.VM_READY, api.VM_RUNNING}) {
|
||||
msg := fmt.Sprintf("Cannot change seting in status %s", self.Status)
|
||||
return nil, httperrors.NewBadRequestError(msg)
|
||||
return nil, httperrors.NewBadRequestError("Cannot change setting in status %s", self.Status)
|
||||
}
|
||||
|
||||
argValue := func(name string, val *bool) error {
|
||||
@@ -2319,7 +2319,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
|
||||
|
||||
changeStatus, err := self.GetDriver().GetChangeConfigStatus(self)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
if !utils.IsInStringArray(self.Status, changeStatus) {
|
||||
return nil, httperrors.NewInvalidStatusError("Cannot change config in %s", self.Status)
|
||||
@@ -2463,7 +2463,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
|
||||
}
|
||||
err = self.ValidateResizeDisk(disk, storage)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewUnsupportOperationError(err.Error())
|
||||
return nil, httperrors.NewUnsupportOperationError("%v", err)
|
||||
}
|
||||
if !storage.IsEmulated && storage.GetFreeCapacity() < int64(addDisk) {
|
||||
return nil, httperrors.NewInsufficientResourceError("Not enough free space")
|
||||
@@ -2793,7 +2793,7 @@ func (self *SGuest) PerformSendkeys(ctx context.Context, userCred mcclient.Token
|
||||
}
|
||||
err = self.VerifySendKeys(keys)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewBadRequestError(err.Error())
|
||||
return nil, httperrors.NewBadRequestError("%v", err)
|
||||
}
|
||||
cmd := fmt.Sprintf("sendkey %s", keys)
|
||||
duration, err := data.Int("duration")
|
||||
@@ -3435,7 +3435,7 @@ func (self *SGuest) StartGuestCreateBackupTask(
|
||||
req.SetKeys(keys)
|
||||
err = quotas.CheckSetPendingQuota(ctx, userCred, &req)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewOutOfQuotaError(err.Error())
|
||||
return nil, httperrors.NewOutOfQuotaError("%v", err)
|
||||
}
|
||||
|
||||
params := data.(*jsonutils.JSONDict)
|
||||
@@ -4232,11 +4232,11 @@ func (self *SGuest) PerformSyncFixNics(ctx context.Context,
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return nil, httperrors.NewInvalidStatusError(errors.NewAggregate(errs).Error())
|
||||
return nil, httperrors.NewInvalidStatusError("%v", errors.NewAggregate(errs))
|
||||
}
|
||||
result := self.SyncVMNics(ctx, userCred, host, vnics, iplist)
|
||||
if result.IsError() {
|
||||
return nil, httperrors.NewInternalServerError(result.Result())
|
||||
return nil, httperrors.NewInternalServerError("%s", result.Result())
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -4425,7 +4425,7 @@ func (manager *SGuestManager) PerformBatchMigrate(ctx context.Context, userCred
|
||||
q := GuestManager.Query().In("id", params.GuestIds)
|
||||
err = db.FetchModelObjects(GuestManager, q, &guests)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError(err.Error())
|
||||
return nil, httperrors.NewInternalServerError("%v", err)
|
||||
}
|
||||
if len(guests) != len(params.GuestIds) {
|
||||
return nil, httperrors.NewBadRequestError("Check input guests is exist")
|
||||
@@ -4530,7 +4530,7 @@ func (self *SGuest) validateCreateInstanceSnapshot(
|
||||
if storage := disks[i].GetDisk().GetStorage(); utils.IsInStringArray(storage.StorageType, api.FIEL_STORAGE) {
|
||||
count, err := SnapshotManager.GetDiskManualSnapshotCount(disks[i].DiskId)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError(err.Error())
|
||||
return nil, httperrors.NewInternalServerError("%v", err)
|
||||
}
|
||||
if count >= options.Options.DefaultMaxManualSnapshotCount {
|
||||
return nil, httperrors.NewBadRequestError("guests disk %d snapshot full, can't take anymore", i)
|
||||
@@ -4600,7 +4600,7 @@ func (self *SGuest) PerformInstanceSnapshotReset(
|
||||
) (jsonutils.JSONObject, error) {
|
||||
|
||||
if self.Status != api.VM_READY {
|
||||
return nil, httperrors.NewInvalidStatusError("guest can't do snapshot in status ", self.Status)
|
||||
return nil, httperrors.NewInvalidStatusError("guest can't do snapshot in status %s", self.Status)
|
||||
}
|
||||
|
||||
dataDict := data.(*jsonutils.JSONDict)
|
||||
|
||||
@@ -195,7 +195,7 @@ func Brand2Hypervisor(brand string) string {
|
||||
func (gtm *SGuestTemplateManager) validateContent(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, content *jsonutils.JSONDict) (*computeapis.ServerCreateInput, error) {
|
||||
input, err := GuestManager.validateCreateData(ctx, userCred, ownerId, query, content)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
// check Image
|
||||
imageId := input.Disks[0].ImageId
|
||||
@@ -230,7 +230,7 @@ func (gtm *SGuestTemplateManager) validateData(
|
||||
copy := jsonutils.DeepCopy(content).(*jsonutils.JSONDict)
|
||||
input, err := gtm.validateContent(ctx, userCred, ownerId, query, copy)
|
||||
if err != nil {
|
||||
return cinput, httperrors.NewInputParameterError(err.Error())
|
||||
return cinput, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
log.Debugf("data: %#v", input)
|
||||
// fill field
|
||||
@@ -582,16 +582,22 @@ func (gt *SGuestTemplate) PerformPublic(
|
||||
}
|
||||
|
||||
func (gt *SGuestTemplate) genForbiddenError(resourceName, resourceStr, scope string) error {
|
||||
var msg string
|
||||
if len(resourceStr) == 0 {
|
||||
msg = fmt.Sprintf("the %s in guest template is not a public resource", resourceName)
|
||||
var (
|
||||
msgFmt string
|
||||
msgArgs []interface{}
|
||||
)
|
||||
if resourceStr == "" {
|
||||
msgFmt = "the %s in guest template is not a public resource"
|
||||
msgArgs = []interface{}{resourceName}
|
||||
} else {
|
||||
msg = fmt.Sprintf("the %s '%s' in guest template is not a public resource", resourceName, resourceStr)
|
||||
msgFmt = "the %s %q in guest template is not a public resource"
|
||||
msgArgs = []interface{}{resourceName, resourceStr}
|
||||
}
|
||||
if len(scope) > 0 {
|
||||
msg += fmt.Sprintf(" in %s scope", scope)
|
||||
if scope != "" {
|
||||
msgFmt += " in %s scope"
|
||||
msgArgs = append(msgArgs, scope)
|
||||
}
|
||||
return httperrors.NewForbiddenError(msg)
|
||||
return httperrors.NewForbiddenError(msgFmt, msgArgs...)
|
||||
}
|
||||
|
||||
func (gt *SGuestTemplate) ValidateDeleteCondition(ctx context.Context) error {
|
||||
|
||||
@@ -939,7 +939,7 @@ func (self *SGuest) ValidateUpdateData(ctx context.Context, userCred mcclient.To
|
||||
if vcpuCount > 0 || vmemSize > 0 {
|
||||
quota, err := self.checkUpdateQuota(ctx, userCred, vcpuCount, vmemSize)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewOutOfQuotaError(err.Error())
|
||||
return nil, httperrors.NewOutOfQuotaError("%v", err)
|
||||
}
|
||||
if !quota.IsEmpty() {
|
||||
data.Add(jsonutils.Marshal(quota), "pending_usage")
|
||||
@@ -3553,7 +3553,7 @@ func (self *SGuest) LeaveAllGroups(ctx context.Context, userCred mcclient.TokenC
|
||||
q := GroupguestManager.Query()
|
||||
err := q.Filter(sqlchemy.Equals(q.Field("guest_id"), self.Id)).All(&groupGuests)
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
log.Errorf("query by guest_id %s: %v", self.Id, err)
|
||||
return
|
||||
}
|
||||
for _, gg := range groupGuests {
|
||||
@@ -3563,7 +3563,7 @@ func (self *SGuest) LeaveAllGroups(ctx context.Context, userCred mcclient.TokenC
|
||||
gq := GroupManager.Query()
|
||||
err := gq.Filter(sqlchemy.Equals(gq.Field("id"), gg.GroupId)).First(&group)
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
log.Errorf("get by group id %s: %v", gg.GroupId, err)
|
||||
return
|
||||
}
|
||||
group.SetModelManager(GroupManager, &group)
|
||||
|
||||
@@ -73,7 +73,7 @@ func (self *SGuest) PerformPrepaidRecycle(ctx context.Context, userCred mcclient
|
||||
}
|
||||
err := self.CanPerformPrepaidRecycle()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInvalidStatusError(err.Error())
|
||||
return nil, httperrors.NewInvalidStatusError("%v", err)
|
||||
}
|
||||
|
||||
return self.DoPerformPrepaidRecycle(ctx, userCred, jsonutils.QueryBoolean(data, "auto_delete", false))
|
||||
|
||||
@@ -2856,7 +2856,7 @@ func (self *SHost) PostCreate(
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
log.Errorf("save updates: %v", err)
|
||||
} else if len(ipmiInfo.IpAddr) > 0 {
|
||||
self.setIpmiIp(userCred, ipmiInfo.IpAddr)
|
||||
}
|
||||
@@ -3977,13 +3977,13 @@ func (self *SHost) addNetif(ctx context.Context, userCred mcclient.TokenCredenti
|
||||
if netif.NicType == api.NIC_TYPE_ADMIN {
|
||||
err := self.setAccessMac(userCred, netif.Mac)
|
||||
if err != nil {
|
||||
return httperrors.NewBadRequestError(err.Error())
|
||||
return httperrors.NewBadRequestError("%v", err)
|
||||
}
|
||||
}
|
||||
if len(ipAddr) > 0 {
|
||||
err = self.EnableNetif(ctx, userCred, netif, "", ipAddr, "", "", reserve, requireDesignatedIp)
|
||||
if err != nil {
|
||||
return httperrors.NewBadRequestError(err.Error())
|
||||
return httperrors.NewBadRequestError("%v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -4014,7 +4014,7 @@ func (self *SHost) PerformEnableNetif(ctx context.Context, userCred mcclient.Tok
|
||||
requireDesignatedIp := jsonutils.QueryBoolean(data, "require_designated_ip", false)
|
||||
err := self.EnableNetif(ctx, userCred, netif, network, ipAddr, allocDir, netType, reserve, requireDesignatedIp)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewBadRequestError(err.Error())
|
||||
return nil, httperrors.NewBadRequestError("%v", err)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -4121,7 +4121,7 @@ func (self *SHost) PerformDisableNetif(ctx context.Context, userCred mcclient.To
|
||||
reserve := jsonutils.QueryBoolean(data, "reserve", false)
|
||||
err := self.DisableNetif(ctx, userCred, netif, reserve)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewBadRequestError(err.Error())
|
||||
return nil, httperrors.NewBadRequestError("%v", err)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -4510,7 +4510,7 @@ func (self *SHost) PerformUndoConvert(ctx context.Context, userCred mcclient.Tok
|
||||
}
|
||||
err := driver.PrepareUnconvert(self)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewNotAcceptableError(err.Error())
|
||||
return nil, httperrors.NewNotAcceptableError("%v", err)
|
||||
}
|
||||
guests := self.GetGuests()
|
||||
if len(guests) > 1 {
|
||||
|
||||
@@ -141,7 +141,7 @@ func (man *SNatDEntryManager) ValidateCreateData(ctx context.Context, userCred m
|
||||
// check ip + port
|
||||
eip, err := man.checkIPPort(input)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
|
||||
// check that eip is suitable
|
||||
|
||||
@@ -168,7 +168,7 @@ func (man *SNatSEntryManager) ValidateCreateData(ctx context.Context, userCred m
|
||||
//check sourceCidr and convert to netutils.IPV4Range
|
||||
sourceIPV4Range, err := newIPv4RangeFromCIDR(input.SourceCidr)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
// get natgateway
|
||||
model, err := man.FetchById(input.NatgatewayId)
|
||||
@@ -194,7 +194,7 @@ func (man *SNatSEntryManager) ValidateCreateData(ctx context.Context, userCred m
|
||||
} else {
|
||||
network, err := man.checkNetWorkId(input.NetworkId)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
data.Add(jsonutils.NewString(network.GetExternalId()), "network_ext_id")
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ func (spm *SScalingPolicyManager) ValidateCreateData(ctx context.Context, userCr
|
||||
}
|
||||
input, err = trigger.ValidateCreateData(input)
|
||||
if err != nil {
|
||||
return input, httperrors.NewInputParameterError(err.Error())
|
||||
return input, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
return input, err
|
||||
}
|
||||
|
||||
@@ -620,13 +620,13 @@ func (self *SSecurityGroup) PerformAddRule(ctx context.Context, userCred mcclien
|
||||
PortEnd: -1,
|
||||
}
|
||||
if err := rule.ParsePorts(secgrouprule.Ports); err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
if err := rule.ValidateRule(); err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
if err := SecurityGroupRuleManager.TableSpec().Insert(ctx, secgrouprule); err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
self.DoSync(ctx, userCred)
|
||||
return nil, nil
|
||||
|
||||
@@ -363,12 +363,12 @@ func (self *SServerSkuManager) ValidateCreateData(ctx context.Context, userCred
|
||||
// 格式 ecs.g1.c1m1
|
||||
input.Name, err = genInstanceType(input.InstanceTypeFamily, input.CpuCoreCount, input.MemorySizeMB)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
q := self.Query().Equals("name", input.Name)
|
||||
count, err := q.CountWithError()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewGeneralError(fmt.Errorf("checkout server sku name duplicate error: %v", err))
|
||||
return nil, httperrors.NewInternalServerError("checkout server sku name duplicate error: %v", err)
|
||||
}
|
||||
if count > 0 {
|
||||
return nil, httperrors.NewDuplicateResourceError("Duplicate sku %s", input.Name)
|
||||
|
||||
@@ -192,7 +192,7 @@ func (manager *SSnapshotPolicyManager) ValidateCreateData(ctx context.Context, u
|
||||
}
|
||||
input.RepeatWeekdays, err = validate.DaysCheck(input.RepeatWeekdays, 1, 7)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
|
||||
if len(input.TimePoints) == 0 {
|
||||
@@ -203,7 +203,7 @@ func (manager *SSnapshotPolicyManager) ValidateCreateData(ctx context.Context, u
|
||||
}
|
||||
input.TimePoints, err = validate.DaysCheck(input.TimePoints, 0, 23)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
|
||||
internalInput := manager.sSnapshotPolicyCreateInputToInternal(input)
|
||||
@@ -275,7 +275,7 @@ func (sp *SSnapshotPolicy) UpdateParamCheck(input *api.SSnapshotPolicyCreateInpu
|
||||
if input.RepeatWeekdays != nil && len(input.RepeatWeekdays) != 0 {
|
||||
input.RepeatWeekdays, err = validate.DaysCheck(input.RepeatWeekdays, 1, 7)
|
||||
if err != nil {
|
||||
return httperrors.NewInputParameterError(err.Error())
|
||||
return httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
if sp.RepeatWeekdays != SnapshotPolicyManager.RepeatWeekdaysParseIntArray(input.RepeatWeekdays) {
|
||||
updateNum++
|
||||
@@ -285,7 +285,7 @@ func (sp *SSnapshotPolicy) UpdateParamCheck(input *api.SSnapshotPolicyCreateInpu
|
||||
if input.TimePoints != nil && len(input.TimePoints) != 0 {
|
||||
input.TimePoints, err = validate.DaysCheck(input.TimePoints, 0, 23)
|
||||
if err != nil {
|
||||
return httperrors.NewInputParameterError(err.Error())
|
||||
return httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
if sp.TimePoints != SnapshotPolicyManager.TimePointsParseIntArray(input.TimePoints) {
|
||||
updateNum++
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
errMappedIpExhausted = errors.Error("mapped ip exhaused")
|
||||
errMappedIpExhausted = errors.Error("mapped ip exhausted")
|
||||
|
||||
LOCK_CLASS_guestnetworks_mapped_addr = "guestnetworks-mapped-addr"
|
||||
LOCK_OBJ_guestnetworks_mapped_addr = "the-addr"
|
||||
|
||||
@@ -767,7 +767,7 @@ func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx cont
|
||||
supportRegions = append(supportRegions, "Aliyun/"+region)
|
||||
}
|
||||
if !utils.IsInStringArray(cloudregion.ExternalId, supportRegions) {
|
||||
return nil, httperrors.NewUnsupportOperationError("cloudregion %s(%d) not support %s scheduler", cloudregion.Name, cloudregion.Id, scheduler)
|
||||
return nil, httperrors.NewUnsupportOperationError("cloudregion %s(%s) not support %s scheduler", cloudregion.Name, cloudregion.Id, scheduler)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1055,7 +1055,7 @@ func (self *SAliyunRegionDriver) ValidateCreateDBInstanceData(ctx context.Contex
|
||||
return input, httperrors.NewInputParameterError("SQL Server cannot have more than seven read-only dbinstances")
|
||||
}
|
||||
default:
|
||||
return input, httperrors.NewInputParameterError("Not support create readonly dbinstance which master dbinstance engine is", master.Engine)
|
||||
return input, httperrors.NewInputParameterError("Not support create readonly dbinstance with master dbinstance engine %s", master.Engine)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1074,7 +1074,7 @@ func (self *SAliyunRegionDriver) ValidateCreateDBInstanceData(ctx context.Contex
|
||||
return input, httperrors.NewGeneralError(err)
|
||||
}
|
||||
if count < 2 {
|
||||
return input, httperrors.NewInputParameterError("At least two networks are required under vpc %s(%s) whith aliyun %s(%s)", vpc.Name, vpc.Id, input.Engine, input.Category)
|
||||
return input, httperrors.NewInputParameterError("At least two networks are required under vpc %s(%s) with aliyun %s(%s)", vpc.Name, vpc.Id, input.Engine, input.Category)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,7 +570,7 @@ func (self *SAwsRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx context
|
||||
ownerId := lblis.GetOwnerId()
|
||||
lb := lblis.GetLoadbalancer()
|
||||
if lb == nil {
|
||||
return nil, httperrors.NewResourceNotFoundError("loadbalancer listener %s related listener %s not found", lblis.Id, lblis.LoadbalancerId)
|
||||
return nil, httperrors.NewResourceNotFoundError("loadbalancer listener %s related loadbalancer %s not found", lblis.Id, lblis.LoadbalancerId)
|
||||
}
|
||||
|
||||
if lb.LoadbalancerSpec == api.LB_AWS_SPEC_APPLICATION {
|
||||
|
||||
@@ -61,7 +61,7 @@ func processFilter(handleFunc specHandleFunc) appsrv.FilterHandler {
|
||||
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
params := appctx.AppContextParams(ctx)
|
||||
@@ -70,7 +70,7 @@ func processFilter(handleFunc specHandleFunc) appsrv.FilterHandler {
|
||||
}
|
||||
spec, err := handleFunc(ctx, userCred, query.(*jsonutils.JSONDict))
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
ret := jsonutils.NewDict()
|
||||
|
||||
@@ -47,22 +47,22 @@ func adminSshKeysHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
params := appctx.AppContextParams(ctx)
|
||||
projectId := params["<tenant_id>"]
|
||||
if len(projectId) == 0 {
|
||||
httperrors.InputParameterError(w, "empty project_id/tenant_id")
|
||||
httperrors.InputParameterError(ctx, w, "empty project_id/tenant_id")
|
||||
return
|
||||
}
|
||||
tenant, err := db.TenantCacheManager.FetchTenantByIdOrName(ctx, projectId)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
httperrors.ResourceNotFoundError(w, "tenant/project %s not found", projectId)
|
||||
httperrors.ResourceNotFoundError(ctx, w, "tenant/project %s not found", projectId)
|
||||
return
|
||||
} else {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
isAdmin := jsonutils.QueryBoolean(query, "admin", false)
|
||||
@@ -74,7 +74,7 @@ func sshKeysHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
isAdmin := jsonutils.QueryBoolean(query, "admin", false)
|
||||
|
||||
@@ -97,12 +97,12 @@ func rangeObjHandler(
|
||||
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
|
||||
obj, err := getRangeObj(ctx, manager, userCred)
|
||||
if err != nil {
|
||||
httperrors.NotFoundError(w, err.Error())
|
||||
httperrors.NotFoundError(ctx, w, "%v", err)
|
||||
return
|
||||
}
|
||||
ownerId, scope, err := db.FetchUsageOwnerScope(ctx, userCred, getQuery(r))
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
isOwner := false
|
||||
@@ -123,7 +123,7 @@ func rangeObjHandler(
|
||||
}
|
||||
usage, err := reporter(scope, ownerId, isOwner, rangeObjs, hostTypes, providers, brands, cloudEnv, includeSystem)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
response(w, usage)
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ func performImageCache(
|
||||
|
||||
disk, err := body.Get("disk")
|
||||
if err != nil {
|
||||
httperrors.MissingParameterError(w, "disk")
|
||||
httperrors.MissingParameterError(ctx, w, "disk")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ func InitHandlers(app *appsrv.Application) {
|
||||
}
|
||||
|
||||
var defaultHandler = func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
httperrors.NotImplementedError(w, "")
|
||||
httperrors.NotImplementedError(ctx, w, "")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func uploadHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
_, _, body := appsrv.FetchEnv(ctx, w, r)
|
||||
disk, err := body.Get("disk")
|
||||
if err != nil {
|
||||
httperrors.MissingParameterError(w, "miss disk")
|
||||
httperrors.MissingParameterError(ctx, w, "miss disk")
|
||||
return
|
||||
}
|
||||
hostutils.DelayTask(ctx, esxi.EsxiAgent.AgentStorage.SaveToGlance, disk)
|
||||
@@ -84,7 +84,7 @@ func deployHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
_, _, body := appsrv.FetchEnv(ctx, w, r)
|
||||
disk, err := body.Get("disk")
|
||||
if err != nil {
|
||||
httperrors.MissingParameterError(w, "miss disk")
|
||||
httperrors.MissingParameterError(ctx, w, "miss disk")
|
||||
return
|
||||
}
|
||||
hostutils.DelayTask(ctx, esxi.EsxiAgent.AgentStorage.AgentDeployGuest, disk)
|
||||
@@ -99,7 +99,7 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
if disk != nil {
|
||||
_, err := disk.Delete(ctx, nil)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
hostutils.ResponseOk(ctx, w)
|
||||
@@ -113,7 +113,7 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
func createHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
disk, diskInfo, err := diskAndDiskInfo(ctx, w, r)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
hostutils.DelayTask(ctx, esxi.EsxiAgent.AgentStorage.CreateDiskByDiskInfo,
|
||||
@@ -125,7 +125,7 @@ func savePrepareHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
taskId := ctx.Value(appctx.APP_CONTEXT_KEY_TASK_ID).(string)
|
||||
disk, diskInfo, err := diskAndDiskInfo(ctx, w, r)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
hostutils.DelayTask(ctx, disk.PrepareSaveToGlance, storageman.PrepareSaveToGlanceParams{
|
||||
@@ -138,7 +138,7 @@ func savePrepareHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
func resizeHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
disk, diskInfo, err := diskAndDiskInfo(ctx, w, r)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
hostutils.DelayTask(ctx, disk.Resize, diskInfo)
|
||||
@@ -151,17 +151,17 @@ func fetchHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
diskId := params["<disk_id>"]
|
||||
disk := esxi.EsxiAgent.AgentStorage.GetDiskById(diskId)
|
||||
if disk != nil {
|
||||
httperrors.GeneralServerError(w, httperrors.NewDuplicateResourceError("disk '%s'", diskId))
|
||||
httperrors.GeneralServerError(ctx, w, httperrors.NewDuplicateResourceError("disk '%s'", diskId))
|
||||
return
|
||||
}
|
||||
disk := esxi.EsxiAgent.AgentStorage.CreateDisk(diskId)
|
||||
diskInfo, err := body.Get("disk")
|
||||
if err != nil {
|
||||
httperrors.InputParameterError(w, "miss disk")
|
||||
httperrors.InputParameterError(ctx, w, "miss disk")
|
||||
}
|
||||
url, err := diskInfo.GetString("url")
|
||||
if err != nil {
|
||||
httperrors.InputParameterError(w, "miss disk.url")
|
||||
httperrors.InputParameterError(ctx, w, "miss disk.url")
|
||||
}
|
||||
hostutils.DelayTask(ctx, disk.CreateFromUrl)
|
||||
hostutils.ResponseOk(ctx, w)
|
||||
|
||||
@@ -150,7 +150,7 @@ func parseRange(reqRange string) (int64, int64, error) {
|
||||
func closeImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
imagePath, err := inputCheck(ctx)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ func closeImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
err = f.Load(imagePath, true)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
f.Close()
|
||||
@@ -172,7 +172,7 @@ func closeImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
func getImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
imagePath, err := inputCheck(ctx)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ func getImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
if err = f.Open(imagePath, true); err != nil {
|
||||
log.Errorf("Open image error: %s", err)
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
@@ -198,7 +198,7 @@ func getImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
startPos, endPos, err = parseRange(reqRange)
|
||||
if err != nil {
|
||||
log.Errorf("Parse range error: %s", err)
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func getImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
rateLimit, err = strconv.ParseInt(strRateLimit, 10, 0)
|
||||
if err != nil {
|
||||
log.Errorf("Parse ratelimit error: %s", err)
|
||||
httperrors.InvalidInputError(w, "Invaild rate limit header")
|
||||
httperrors.InvalidInputError(ctx, w, "Invaild rate limit header")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -270,7 +270,7 @@ fail:
|
||||
func getImageMeta(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
imagePath, err := inputCheck(ctx)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ func getImageMeta(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
f = &SQcow2Image{}
|
||||
}
|
||||
if err = f.Open(imagePath, true); err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ func download(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
case "images":
|
||||
hand := NewImageCacheDownloadProvider(w, compress, rateLimit, id)
|
||||
if !fileutils2.Exists(hand.downloadFilePath()) {
|
||||
httperrors.NotFoundError(w, "Image cache %s not found", id)
|
||||
httperrors.NotFoundError(ctx, w, "Image cache %s not found", id)
|
||||
} else {
|
||||
if err := hand.Start(); err != nil {
|
||||
hostutils.Response(ctx, w, err)
|
||||
@@ -94,7 +94,7 @@ func download(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
case "servers":
|
||||
hand := NewGuestDownloadProvider(w, compress, rateLimit, id)
|
||||
if !fileutils2.Exists(hand.fullPath()) {
|
||||
httperrors.NotFoundError(w, "Guest %s not found", id)
|
||||
httperrors.NotFoundError(ctx, w, "Guest %s not found", id)
|
||||
} else {
|
||||
if err := hand.Start(); err != nil {
|
||||
hostutils.Response(ctx, w, err)
|
||||
|
||||
@@ -153,7 +153,7 @@ func Response(ctx context.Context, w http.ResponseWriter, res interface{}) {
|
||||
case jsonutils.JSONObject:
|
||||
appsrv.SendJSON(w, res.(jsonutils.JSONObject))
|
||||
case error:
|
||||
httperrors.GeneralServerError(w, res.(error))
|
||||
httperrors.GeneralServerError(ctx, w, res.(error))
|
||||
default:
|
||||
appsrv.SendStruct(w, res)
|
||||
}
|
||||
|
||||
@@ -93,17 +93,17 @@ func performImageCache(
|
||||
|
||||
disk, err := body.Get("disk")
|
||||
if err != nil {
|
||||
httperrors.MissingParameterError(w, "disk")
|
||||
httperrors.MissingParameterError(ctx, w, "disk")
|
||||
return
|
||||
}
|
||||
scId, err := disk.GetString("storagecache_id")
|
||||
if err != nil {
|
||||
httperrors.MissingParameterError(w, "disk")
|
||||
httperrors.MissingParameterError(ctx, w, "disk")
|
||||
return
|
||||
}
|
||||
storagecache := storageman.GetManager().GetStoragecacheById(scId)
|
||||
if storagecache == nil {
|
||||
httperrors.NotFoundError(w, "Storagecache %s not found", scId)
|
||||
httperrors.NotFoundError(ctx, w, "Storagecache %s not found", scId)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -15,15 +15,43 @@
|
||||
package httperrors
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/httputils"
|
||||
)
|
||||
|
||||
type ctxLang uintptr
|
||||
|
||||
const ctxLangKey = ctxLang(0)
|
||||
|
||||
func WithLangTag(ctx context.Context, tag language.Tag) context.Context {
|
||||
return context.WithValue(ctx, ctxLangKey, tag)
|
||||
}
|
||||
func WithLang(ctx context.Context, lang string) context.Context {
|
||||
tag, err := language.Parse(lang)
|
||||
if err != nil {
|
||||
tag = language.English
|
||||
}
|
||||
return WithLangTag(ctx, tag)
|
||||
}
|
||||
|
||||
func WithRequestLang(ctx context.Context, req *http.Request) context.Context {
|
||||
if cookie, err := req.Cookie("lang"); err == nil {
|
||||
return WithLang(ctx, cookie.Value)
|
||||
}
|
||||
if val := req.URL.Query().Get("lang"); val != "" {
|
||||
return WithLang(ctx, val)
|
||||
}
|
||||
return WithLangTag(ctx, language.English)
|
||||
}
|
||||
|
||||
func SendHTTPErrorHeader(w http.ResponseWriter, statusCode int) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(statusCode)
|
||||
@@ -33,7 +61,7 @@ func SetHTTPRedirectLocationHeader(w http.ResponseWriter, location string) {
|
||||
w.Header().Set("Location", location)
|
||||
}
|
||||
|
||||
func HTTPError(w http.ResponseWriter, msg string, statusCode int, class string, error httputils.Error) {
|
||||
func HTTPError(ctx context.Context, w http.ResponseWriter, msg string, statusCode int, class string, err httputils.Error) {
|
||||
if statusCode >= 300 && statusCode <= 400 {
|
||||
SetHTTPRedirectLocationHeader(w, msg)
|
||||
}
|
||||
@@ -41,110 +69,121 @@ func HTTPError(w http.ResponseWriter, msg string, statusCode int, class string,
|
||||
// 需要在调用w.WriteHeader方法之前,设置header才能生效
|
||||
SendHTTPErrorHeader(w, statusCode)
|
||||
|
||||
var (
|
||||
langv = ctx.Value(ctxLangKey)
|
||||
lang language.Tag
|
||||
details string
|
||||
)
|
||||
if langv != nil {
|
||||
lang = langv.(language.Tag)
|
||||
} else {
|
||||
lang = language.English
|
||||
}
|
||||
a := make([]interface{}, len(err.Fields))
|
||||
for i := range err.Fields {
|
||||
a[i] = err.Fields[i]
|
||||
}
|
||||
details = P(lang, err.Id, a...)
|
||||
body := jsonutils.NewDict()
|
||||
body.Add(jsonutils.NewInt(int64(statusCode)), "code")
|
||||
body.Add(jsonutils.NewString(msg), "details")
|
||||
body.Add(jsonutils.NewString(class), "class")
|
||||
err := jsonutils.NewDict()
|
||||
err.Add(jsonutils.NewString(error.Id), "id")
|
||||
err.Add(jsonutils.NewStringArray(error.Fields), "fields")
|
||||
body.Add(err, "data")
|
||||
body.Add(jsonutils.NewString(details), "details")
|
||||
w.Write([]byte(body.String()))
|
||||
log.Errorf("Send error %s", err)
|
||||
log.Errorf("Send error %s", details)
|
||||
if statusCode >= 500 {
|
||||
debug.PrintStack()
|
||||
}
|
||||
}
|
||||
|
||||
func JsonClientError(w http.ResponseWriter, e *httputils.JSONClientError) {
|
||||
HTTPError(w, e.Details, e.Code, e.Class, e.Data)
|
||||
func JsonClientError(ctx context.Context, w http.ResponseWriter, e *httputils.JSONClientError) {
|
||||
HTTPError(ctx, w, e.Details, e.Code, e.Class, e.Data)
|
||||
}
|
||||
|
||||
func GeneralServerError(w http.ResponseWriter, e error) {
|
||||
func GeneralServerError(ctx context.Context, w http.ResponseWriter, e error) {
|
||||
je := NewGeneralError(e)
|
||||
JsonClientError(w, je)
|
||||
JsonClientError(ctx, w, je)
|
||||
}
|
||||
|
||||
func BadRequestError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewBadRequestError(msg, params...))
|
||||
func BadRequestError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewBadRequestError(msg, params...))
|
||||
}
|
||||
|
||||
func PaymentError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewPaymentError(msg, params...))
|
||||
func PaymentError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewPaymentError(msg, params...))
|
||||
}
|
||||
|
||||
func UnauthorizedError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewUnauthorizedError(msg, params...))
|
||||
func UnauthorizedError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewUnauthorizedError(msg, params...))
|
||||
}
|
||||
|
||||
func InvalidCredentialError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewInvalidCredentialError(msg, params...))
|
||||
func InvalidCredentialError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewInvalidCredentialError(msg, params...))
|
||||
}
|
||||
|
||||
func ForbiddenError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewForbiddenError(msg, params...))
|
||||
func ForbiddenError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewForbiddenError(msg, params...))
|
||||
}
|
||||
|
||||
func NotFoundError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewNotFoundError(msg, params...))
|
||||
func NotFoundError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewNotFoundError(msg, params...))
|
||||
}
|
||||
|
||||
func NotImplementedError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewNotImplementedError(msg, params...))
|
||||
func NotImplementedError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewNotImplementedError(msg, params...))
|
||||
}
|
||||
|
||||
func NotAcceptableError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewNotAcceptableError(msg, params...))
|
||||
func NotAcceptableError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewNotAcceptableError(msg, params...))
|
||||
}
|
||||
|
||||
func InvalidInputError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewInputParameterError(msg, params...))
|
||||
func InvalidInputError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewInputParameterError(msg, params...))
|
||||
}
|
||||
|
||||
func InputParameterError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewInputParameterError(msg, params...))
|
||||
func InputParameterError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewInputParameterError(msg, params...))
|
||||
}
|
||||
|
||||
func MissingParameterError(w http.ResponseWriter, param string) {
|
||||
JsonClientError(w, NewMissingParameterError(param))
|
||||
func MissingParameterError(ctx context.Context, w http.ResponseWriter, param string) {
|
||||
JsonClientError(ctx, w, NewMissingParameterError(param))
|
||||
}
|
||||
|
||||
func ConflictError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewConflictError(msg, params...))
|
||||
func ConflictError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewConflictError(msg, params...))
|
||||
}
|
||||
|
||||
func InternalServerError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewInternalServerError(msg, params...))
|
||||
func InternalServerError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewInternalServerError(msg, params...))
|
||||
}
|
||||
|
||||
func BadGatewayError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewBadGatewayError(msg, params...))
|
||||
func BadGatewayError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewBadGatewayError(msg, params...))
|
||||
}
|
||||
|
||||
func TenantNotFoundError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewTenantNotFoundError(msg, params...))
|
||||
func TenantNotFoundError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewTenantNotFoundError(msg, params...))
|
||||
}
|
||||
|
||||
func OutOfQuotaError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewOutOfQuotaError(msg, params...))
|
||||
func OutOfQuotaError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewOutOfQuotaError(msg, params...))
|
||||
}
|
||||
|
||||
func NotSufficientPrivilegeError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewNotSufficientPrivilegeError(msg, params...))
|
||||
func NotSufficientPrivilegeError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewNotSufficientPrivilegeError(msg, params...))
|
||||
}
|
||||
|
||||
func ResourceNotFoundError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewResourceNotFoundError(msg, params...))
|
||||
func ResourceNotFoundError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewResourceNotFoundError(msg, params...))
|
||||
}
|
||||
|
||||
func TimeoutError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewTimeoutError(msg, params...))
|
||||
func TimeoutError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewTimeoutError(msg, params...))
|
||||
}
|
||||
|
||||
func ProtectedResourceError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewProtectedResourceError(msg, params...))
|
||||
func ProtectedResourceError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewProtectedResourceError(msg, params...))
|
||||
}
|
||||
|
||||
func NoProjectError(w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(w, NewNoProjectError(msg, params...))
|
||||
func NoProjectError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
|
||||
JsonClientError(ctx, w, NewNoProjectError(msg, params...))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package httperrors
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
|
||||
"yunion.io/x/onecloud/locales"
|
||||
)
|
||||
|
||||
func P(tag language.Tag, id string, a ...interface{}) string {
|
||||
p := message.NewPrinter(tag, message.Catalog(locales.Catalog))
|
||||
return p.Sprintf(id, a...)
|
||||
}
|
||||
@@ -41,7 +41,7 @@ func ReportGeneralUsage(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
|
||||
ownerId, scope, err := db.FetchUsageOwnerScope(ctx, userCred, query)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -445,7 +445,7 @@ func roleAssignmentHandler(ctx context.Context, w http.ResponseWriter, r *http.R
|
||||
|
||||
results, total, err := AssignmentManager.FetchAll(userId, groupId, roleId, domainId, projectId, includeNames, effective, includeSub, includeSystem, includePolicies, int(limit), int(offset))
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
body := jsonutils.NewDict()
|
||||
|
||||
@@ -511,7 +511,7 @@ func (project *SProject) PerformJoin(
|
||||
) (jsonutils.JSONObject, error) {
|
||||
err := input.Validate()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
|
||||
roleNames := make([]string, 0)
|
||||
@@ -597,7 +597,7 @@ func (project *SProject) PerformLeave(
|
||||
) (jsonutils.JSONObject, error) {
|
||||
err := input.Validate()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
return nil, httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
|
||||
for i := range input.UserRoles {
|
||||
|
||||
@@ -951,7 +951,7 @@ func (user *SUser) PerformJoin(
|
||||
func joinProjects(ident db.IModel, isUser bool, ctx context.Context, userCred mcclient.TokenCredential, input api.SJoinProjectsInput) error {
|
||||
err := input.Validate()
|
||||
if err != nil {
|
||||
return httperrors.NewInputParameterError(err.Error())
|
||||
return httperrors.NewInputParameterError("%v", err)
|
||||
}
|
||||
|
||||
projects := make([]*SProject, 0)
|
||||
|
||||
@@ -55,13 +55,13 @@ func authenticateTokensV2(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
input := mcclient.SAuthenticationInputV2{}
|
||||
err := body.Unmarshal(&input)
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w, "unrecognized input %s", err)
|
||||
httperrors.InvalidInputError(ctx, w, "unrecognized input %s", err)
|
||||
return
|
||||
}
|
||||
input.Auth.Context = FetchAuthContext(input.Auth.Context, r)
|
||||
token, err := AuthenticateV2(ctx, input)
|
||||
if token == nil {
|
||||
httperrors.UnauthorizedError(w, "unauthorized %s", err)
|
||||
httperrors.UnauthorizedError(ctx, w, "unauthorized %s", err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, jsonutils.Marshal(token))
|
||||
@@ -72,13 +72,13 @@ func authenticateTokensV2(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
func authenticateTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
_, _, body := appsrv.FetchEnv(ctx, w, r)
|
||||
if body == nil {
|
||||
httperrors.InvalidInputError(w, "fail to decode request body")
|
||||
httperrors.InvalidInputError(ctx, w, "fail to decode request body")
|
||||
return
|
||||
}
|
||||
input := mcclient.SAuthenticationInputV3{}
|
||||
err := body.Unmarshal(&input)
|
||||
if err != nil {
|
||||
httperrors.InvalidInputError(w, "unrecognized input %s", err)
|
||||
httperrors.InvalidInputError(ctx, w, "unrecognized input %s", err)
|
||||
return
|
||||
}
|
||||
input.Auth.Context = FetchAuthContext(input.Auth.Context, r)
|
||||
@@ -86,16 +86,16 @@ func authenticateTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
if err != nil {
|
||||
switch errors.Cause(err) {
|
||||
case sqlchemy.ErrDuplicateEntry:
|
||||
httperrors.ConflictError(w, "duplicate username")
|
||||
httperrors.ConflictError(ctx, w, "duplicate username")
|
||||
case httperrors.ErrTooManyAttempts, httperrors.ErrUserNotFound:
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
default:
|
||||
httperrors.UnauthorizedError(w, "unauthorized %s", err)
|
||||
httperrors.UnauthorizedError(ctx, w, "unauthorized %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if token == nil {
|
||||
httperrors.UnauthorizedError(w, "user not found or not enabled")
|
||||
httperrors.UnauthorizedError(ctx, w, "user not found or not enabled")
|
||||
return
|
||||
}
|
||||
w.Header().Set(api.AUTH_SUBJECT_TOKEN_HEADER, token.Id)
|
||||
@@ -126,27 +126,27 @@ func verifyTokensV2(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
tokenStr := params["<token>"]
|
||||
token, err := verifyCommon(ctx, w, tokenStr)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
user, err := models.UserManager.FetchUserExtended(token.UserId, "", "", "")
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "invalid user")
|
||||
httperrors.InvalidCredentialError(ctx, w, "invalid user")
|
||||
return
|
||||
}
|
||||
project, err := models.ProjectManager.FetchProject(token.ProjectId, "", "", "")
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "invalid project")
|
||||
httperrors.InvalidCredentialError(ctx, w, "invalid project")
|
||||
return
|
||||
}
|
||||
projExt, err := project.FetchExtend()
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "invalid project")
|
||||
httperrors.InvalidCredentialError(ctx, w, "invalid project")
|
||||
return
|
||||
}
|
||||
v2token, err := token.getTokenV2(ctx, user, projExt)
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(w, "internal server error %s", err)
|
||||
httperrors.InternalServerError(ctx, w, "internal server error %s", err)
|
||||
return
|
||||
}
|
||||
ret := jsonutils.NewDict()
|
||||
@@ -174,13 +174,13 @@ func verifyTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
tokenStr := r.Header.Get(api.AUTH_SUBJECT_TOKEN_HEADER)
|
||||
token, err := verifyCommon(ctx, w, tokenStr)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := models.UserManager.FetchUserExtended(token.UserId, "", "", "")
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "invalid user")
|
||||
httperrors.InvalidCredentialError(ctx, w, "invalid user")
|
||||
return
|
||||
}
|
||||
var projExt *models.SProjectExtended
|
||||
@@ -188,25 +188,25 @@ func verifyTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
if len(token.ProjectId) > 0 {
|
||||
project, err := models.ProjectManager.FetchProject(token.ProjectId, "", "", "")
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "invalid project")
|
||||
httperrors.InvalidCredentialError(ctx, w, "invalid project")
|
||||
return
|
||||
}
|
||||
projExt, err = project.FetchExtend()
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "invalid project")
|
||||
httperrors.InvalidCredentialError(ctx, w, "invalid project")
|
||||
return
|
||||
}
|
||||
} else if len(token.DomainId) > 0 {
|
||||
domain, err = models.DomainManager.FetchDomainById(token.DomainId)
|
||||
if err != nil {
|
||||
httperrors.InvalidCredentialError(w, "invalid domain")
|
||||
httperrors.InvalidCredentialError(ctx, w, "invalid domain")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
v3token, err := token.getTokenV3(ctx, user, projExt, domain, api.SAccessKeySecretInfo{})
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(w, "internal server error %s", err)
|
||||
httperrors.InternalServerError(ctx, w, "internal server error %s", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set(api.AUTH_SUBJECT_TOKEN_HEADER, v3token.Id)
|
||||
|
||||
@@ -74,7 +74,7 @@ func ReportGeneralUsage(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
|
||||
// if !isAdmin && !isProject {
|
||||
if !isAdmin {
|
||||
httperrors.ForbiddenError(w, "not allow to get usage")
|
||||
httperrors.ForbiddenError(ctx, w, "not allow to get usage")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ func AuthenticateWithDelayDecision(f appsrv.FilterHandler, delayDecision bool) a
|
||||
if len(tokenStr) == 0 {
|
||||
log.Errorf("no auth_token found! delayDecision=%v", delayDecision)
|
||||
if !delayDecision {
|
||||
httperrors.UnauthorizedError(w, "Unauthorized")
|
||||
httperrors.UnauthorizedError(ctx, w, "Unauthorized")
|
||||
return
|
||||
}
|
||||
token = &GuestToken
|
||||
@@ -62,7 +62,7 @@ func AuthenticateWithDelayDecision(f appsrv.FilterHandler, delayDecision bool) a
|
||||
if err != nil {
|
||||
log.Errorf("Verify token failed: %s", err)
|
||||
if !delayDecision {
|
||||
httperrors.UnauthorizedError(w, "InvalidToken")
|
||||
httperrors.UnauthorizedError(ctx, w, "InvalidToken")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,8 +88,7 @@ func (this *HostManager) GetIpmiInfo(s *mcclient.ClientSession, id string, param
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func parseHosts(titles []string, data string) ([]*jsonutils.JSONDict, string) {
|
||||
msg := ""
|
||||
func parseHosts(titles []string, data string) []*jsonutils.JSONDict {
|
||||
hosts := strings.Split(data, "\n")
|
||||
ret := []*jsonutils.JSONDict{}
|
||||
for i, host := range hosts {
|
||||
@@ -114,7 +113,7 @@ func parseHosts(titles []string, data string) ([]*jsonutils.JSONDict, string) {
|
||||
ret = append(ret, params)
|
||||
}
|
||||
|
||||
return ret, msg
|
||||
return ret
|
||||
}
|
||||
|
||||
func (this *HostManager) BatchRegister(s *mcclient.ClientSession, titles []string, params jsonutils.JSONObject) ([]modulebase.SubmitResult, error) {
|
||||
@@ -125,10 +124,7 @@ func (this *HostManager) BatchRegister(s *mcclient.ClientSession, titles []strin
|
||||
input := params.(*jsonutils.JSONDict)
|
||||
input.Remove("hosts")
|
||||
|
||||
hosts, msg := parseHosts(titles, data)
|
||||
if len(msg) > 0 {
|
||||
return nil, httperrors.NewInputParameterError(msg)
|
||||
}
|
||||
hosts := parseHosts(titles, data)
|
||||
|
||||
results := make(chan modulebase.SubmitResult, len(hosts))
|
||||
for _, host := range hosts {
|
||||
|
||||
@@ -42,7 +42,7 @@ func emailConfigDeleteHandler(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
}
|
||||
err := manager.DeleteConfig(ctx, params)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func emailConfigGetHandler(ctx context.Context, w http.ResponseWriter, r *http.R
|
||||
}
|
||||
ret, err := manager.GetConfig(ctx, params, query)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
data, _ := ret.Get("config")
|
||||
dataDict := data.(*jsonutils.JSONDict)
|
||||
@@ -70,7 +70,7 @@ func emailConfigUpdateHandler(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
newBody.Add(body, EMAIL)
|
||||
err := manager.UpdateConfig(ctx, newBody)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
data := jsonutils.NewDict()
|
||||
data.Add(jsonutils.NewInt(200), "code")
|
||||
@@ -89,7 +89,7 @@ func smsConfigDeleteHandler(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
}
|
||||
err := manager.DeleteConfig(ctx, params)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ func smsConfigGetHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
ret, err := manager.GetConfig(ctx, params, query)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
// modify
|
||||
data, _ := ret.Get("config")
|
||||
@@ -116,7 +116,7 @@ func smsConfigUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
newBody.Add(body, SMS)
|
||||
err := manager.UpdateConfig(ctx, newBody)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
data := jsonutils.NewDict()
|
||||
data.Add(jsonutils.NewInt(200), "code")
|
||||
|
||||
@@ -545,21 +545,23 @@ func (self *NotifyModelDispatcher) UpdateContacts(ctx context.Context, idstr str
|
||||
|
||||
// keep the return value same as this of the GET interface
|
||||
ret := jsonutils.NewDict()
|
||||
contact, err := models.ContactManager.FetchByUIDs(ctx, []string{idstr}, false)
|
||||
contacts, err := models.ContactManager.FetchByUIDs(ctx, []string{idstr}, false)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
log.Errorf("fetch contact %s: %v", idstr, err)
|
||||
return ret, nil
|
||||
}
|
||||
if len(contact) == 0 {
|
||||
if len(contacts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
outDetails, err := contact[0].GetExtraDetails(ctx, userCred, ret, false)
|
||||
contact := contacts[0]
|
||||
outDetails, err := contact.GetExtraDetails(ctx, userCred, ret, false)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
log.Errorf("fetch contact details %s(%s): %v",
|
||||
contact.GetName(), contact.GetId(), err)
|
||||
return ret, nil
|
||||
}
|
||||
out := jsonutils.Marshal(outDetails)
|
||||
out.(*jsonutils.JSONDict).Set("created_at", jsonutils.NewString(contact[0].CreatedAt.String()))
|
||||
out.(*jsonutils.JSONDict).Set("created_at", jsonutils.NewString(contact.CreatedAt.String()))
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -684,7 +686,7 @@ func DeleteItem(model db.IModel, ctx context.Context, userCred mcclient.TokenCre
|
||||
err = db.CustomizeDelete(model, ctx, userCred, query, data)
|
||||
if err != nil {
|
||||
log.Errorf("customize delete error: %s", err)
|
||||
return httperrors.NewNotAcceptableError(err.Error())
|
||||
return httperrors.NewNotAcceptableError("%v", err)
|
||||
}
|
||||
model.PreDelete(ctx, userCred)
|
||||
err = model.Delete(ctx, userCred)
|
||||
|
||||
+26
-26
@@ -65,7 +65,7 @@ func middleware(f appsrv.FilterHandler) appsrv.FilterHandler {
|
||||
if uid, ok := params["<uid>"]; ok {
|
||||
userDetail, err := utils.GetUserByIDOrName(ctx, uid)
|
||||
if err != nil {
|
||||
httperrors.NotFoundError(w, "Uid or Uname Not Found")
|
||||
httperrors.NotFoundError(ctx, w, "Uid or Uname Not Found")
|
||||
return
|
||||
}
|
||||
log.Debugf("find userDetail, id: %s, name: %s", userDetail.Id, userDetail.Name)
|
||||
@@ -197,31 +197,31 @@ func templateUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.R
|
||||
manager, params, query, body := fetchEnv(ctx, w, r)
|
||||
data, err := body.GetArray(manager.Keyword(), manager.KeywordPlural())
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, httperrors.NewInputParameterError("need %s and %s",
|
||||
httperrors.GeneralServerError(ctx, w, httperrors.NewInputParameterError("need %s and %s",
|
||||
manager.Keyword(), manager.KeywordPlural()))
|
||||
return
|
||||
}
|
||||
ctype := params["<ctype>"]
|
||||
if len(ctype) == 0 {
|
||||
httperrors.InputParameterError(w, "ctype of template should not be empty")
|
||||
httperrors.InputParameterError(ctx, w, "ctype of template should not be empty")
|
||||
}
|
||||
err = manager.UpdateTemplate(ctx, ctype, mergeQueryParams(params, query), data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteTemplateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
manager, _, query, body := fetchEnv(ctx, w, r)
|
||||
if !body.Contains("contact_type") {
|
||||
httperrors.InputParameterError(w, "miss contact_type")
|
||||
httperrors.InputParameterError(ctx, w, "miss contact_type")
|
||||
return
|
||||
}
|
||||
ctype, _ := body.GetString("contact_type")
|
||||
topic, _ := body.GetString("topic")
|
||||
err := manager.DeleteTemplate(ctx, query, ctype, topic)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ func configDeleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
manager, params, _, _ := fetchEnv(ctx, w, r)
|
||||
err := manager.DeleteConfig(ctx, params)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ func configGetHandler(ctx context.Context, w http.ResponseWriter, r *http.Reques
|
||||
manager, params, query, _ := fetchEnv(ctx, w, r)
|
||||
ret, err := manager.GetConfig(ctx, params, query)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, ret)
|
||||
@@ -247,12 +247,12 @@ func configUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
manager, _, _, body := fetchEnv(ctx, w, r)
|
||||
body, err := body.Get(models.ConfigManager.Keyword())
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, httperrors.NewInputParameterError("need config or configs"))
|
||||
httperrors.GeneralServerError(ctx, w, httperrors.NewInputParameterError("need config or configs"))
|
||||
return
|
||||
}
|
||||
err = manager.UpdateConfig(ctx, body)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,12 +260,12 @@ func configValidateHandler(ctx context.Context, w http.ResponseWriter, r *http.R
|
||||
manager, params, _, body := fetchEnv(ctx, w, r)
|
||||
body, err := body.Get(models.ConfigManager.Keyword())
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, httperrors.NewInputParameterError("need config"))
|
||||
httperrors.GeneralServerError(ctx, w, httperrors.NewInputParameterError("need config"))
|
||||
}
|
||||
ctype := params["<type>"]
|
||||
err = manager.ValidateConfig(ctx, ctype, body)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -274,16 +274,16 @@ func notificationHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
manager, _, _, body := fetchEnv(ctx, w, r)
|
||||
data, err := body.Get(manager.Keyword())
|
||||
if err != nil {
|
||||
httperrors.BadRequestError(w, "request body should contain %s", manager.Keyword())
|
||||
httperrors.BadRequestError(ctx, w, "request body should contain %s", manager.Keyword())
|
||||
return
|
||||
}
|
||||
if !data.Contains("gid") && !data.Contains("uid") {
|
||||
httperrors.MissingParameterError(w, "gid | uid")
|
||||
httperrors.MissingParameterError(ctx, w, "gid | uid")
|
||||
return
|
||||
}
|
||||
_, err = manager.CreateNotification(ctx, data)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -293,7 +293,7 @@ func verifyHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
manager, params, query, _ := fetchEnv(ctx, w, r)
|
||||
err := manager.Verify(ctx, params, query)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ func contactUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
data, err := body.GetArray(manager.Keyword(), manager.KeywordPlural())
|
||||
if err != nil {
|
||||
log.Errorf("body: %s, err: %s\n", body.String(), err)
|
||||
httperrors.GeneralServerError(w, httperrors.NewInputParameterError("need %s and %s",
|
||||
httperrors.GeneralServerError(ctx, w, httperrors.NewInputParameterError("need %s and %s",
|
||||
manager.Keyword(), manager.KeywordPlural()))
|
||||
return
|
||||
}
|
||||
@@ -317,7 +317,7 @@ func contactUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
out, err := manager.UpdateContacts(ctx, uid, mergeQueryParams(params, query), data, pullCtypes, nil)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
httperrors.BadRequestError(w, "")
|
||||
httperrors.BadRequestError(ctx, w, "")
|
||||
return
|
||||
}
|
||||
if out == nil {
|
||||
@@ -335,7 +335,7 @@ func deleteContactHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
if body != nil {
|
||||
data, err = body.GetArray(manager.KeywordPlural())
|
||||
if err != nil {
|
||||
httperrors.BadRequestError(w, "request body should have %s", manager.KeywordPlural())
|
||||
httperrors.BadRequestError(ctx, w, "request body should have %s", manager.KeywordPlural())
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -343,7 +343,7 @@ func deleteContactHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("delete contact of %s failed, error: %s", data, err)
|
||||
httperrors.GeneralServerError(w, errors.Error("delete failed"))
|
||||
httperrors.GeneralServerError(ctx, w, errors.Error("delete failed"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,13 +352,13 @@ func verifyTriggerHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
manager, params, _, body := fetchEnv(ctx, w, r)
|
||||
data, err := body.Get(models.ContactManager.Keyword())
|
||||
if err != nil {
|
||||
httperrors.BadRequestError(w, "request body should have %s", manager.Keyword())
|
||||
httperrors.BadRequestError(ctx, w, "request body should have %s", manager.Keyword())
|
||||
return
|
||||
}
|
||||
ret, err := manager.VerifyTrigger(ctx, params, data)
|
||||
if err != nil {
|
||||
log.Errorf("verifyTrigger failed beacause %s", err)
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, ret)
|
||||
@@ -369,7 +369,7 @@ func listHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
manager, params, query, _ := fetchEnv(ctx, w, r)
|
||||
listResult, err := manager.List(ctx, mergeQueryParams(params, query), nil)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, modulebase.ListResult2JSONWithKey(listResult, manager.KeywordPlural()))
|
||||
@@ -379,7 +379,7 @@ func getHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
manager, params, query, _ := fetchEnv(ctx, w, r)
|
||||
listResult, err := manager.List(ctx, mergeQueryParams(params, query), nil)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
var data jsonutils.JSONObject
|
||||
@@ -407,14 +407,14 @@ func keyStoneUserListHandler(ctx context.Context, w http.ResponseWriter, r *http
|
||||
users, err := modules.UsersV3.List(s, query)
|
||||
if err != nil {
|
||||
log.Errorf("keystone list error: %s", err)
|
||||
httperrors.InternalServerError(w, err.Error())
|
||||
httperrors.InternalServerError(ctx, w, err.Error())
|
||||
return
|
||||
}
|
||||
q := models.ContactManager.Query("uid").GroupBy("uid")
|
||||
row, err := q.Rows()
|
||||
if err != nil {
|
||||
log.Errorf("get contact's uid error: %s", err)
|
||||
httperrors.InternalServerError(w, err.Error())
|
||||
httperrors.InternalServerError(ctx, w, err.Error())
|
||||
return
|
||||
}
|
||||
defer row.Close()
|
||||
|
||||
+3
-3
@@ -56,12 +56,12 @@ func NewHTTPReverseProxy(ef *SEndpointFactory, m RequestManipulator) *SReversePr
|
||||
func (p *SReverseProxy) ServeHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
endpoint, err := p.generator(ctx, r)
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(w, err.Error())
|
||||
httperrors.InternalServerError(httperrors.WithRequestLang(ctx, r), w, "%v", err)
|
||||
return
|
||||
}
|
||||
remoteUrl, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(w, "failed parsing url %q: %v", endpoint, err)
|
||||
httperrors.InternalServerError(httperrors.WithRequestLang(ctx, r), w, "failed parsing url %q: %v", endpoint, err)
|
||||
return
|
||||
}
|
||||
log.Debugf("Forwarding to servie: %q, url: %q", p.serviceName, remoteUrl.String())
|
||||
@@ -73,7 +73,7 @@ func (p *SReverseProxy) ServeHTTP(ctx context.Context, w http.ResponseWriter, r
|
||||
}
|
||||
r, err = p.manipulator(ctx, r)
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(w, err.Error())
|
||||
httperrors.InternalServerError(httperrors.WithRequestLang(ctx, r), w, "%v", err)
|
||||
return
|
||||
}
|
||||
proxy.ServeHTTP(w, r)
|
||||
|
||||
@@ -92,9 +92,9 @@ func OutOfRangeError(ctx context.Context, msg string) s3cli.ErrorResponse {
|
||||
func SendGeneralError(ctx context.Context, w http.ResponseWriter, err error) {
|
||||
switch e := err.(type) {
|
||||
case s3cli.ErrorResponse:
|
||||
SendError(w, e)
|
||||
SendError(ctx, w, e)
|
||||
case *s3cli.ErrorResponse:
|
||||
SendError(w, *e)
|
||||
SendError(ctx, w, *e)
|
||||
default:
|
||||
var eresp s3cli.ErrorResponse
|
||||
cause := errors.Cause(err)
|
||||
@@ -124,11 +124,11 @@ func SendGeneralError(ctx context.Context, w http.ResponseWriter, err error) {
|
||||
default:
|
||||
eresp = ServerError(ctx, err.Error())
|
||||
}
|
||||
SendError(w, eresp)
|
||||
SendError(ctx, w, eresp)
|
||||
}
|
||||
}
|
||||
|
||||
func SendError(w http.ResponseWriter, resp s3cli.ErrorResponse) {
|
||||
func SendError(ctx context.Context, w http.ResponseWriter, resp s3cli.ErrorResponse) {
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
|
||||
log.Errorf("SendError: %s", resp)
|
||||
|
||||
@@ -144,7 +144,7 @@ func headHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
SendError(w, NotSupported(ctx, "method not supported"))
|
||||
SendError(ctx, w, NotSupported(ctx, "method not supported"))
|
||||
}
|
||||
|
||||
func readBucket(ctx context.Context, userCred mcclient.TokenCredential, bucketName string, query jsonutils.JSONObject, r *http.Request) (interface{}, http.Header, error) {
|
||||
@@ -302,13 +302,13 @@ func readHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
// service
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
SendError(w, BadRequest(ctx, err.Error()))
|
||||
SendError(ctx, w, BadRequest(ctx, err.Error()))
|
||||
return
|
||||
}
|
||||
input := s3cli.ListBucketsInput{}
|
||||
err = query.Unmarshal(&input)
|
||||
if err != nil {
|
||||
SendError(w, BadRequest(ctx, err.Error()))
|
||||
SendError(ctx, w, BadRequest(ctx, err.Error()))
|
||||
} else {
|
||||
resp, err := listService(ctx, userCred, input)
|
||||
if err != nil {
|
||||
@@ -321,7 +321,7 @@ func readHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
// bucket get
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
SendError(w, BadRequest(ctx, err.Error()))
|
||||
SendError(ctx, w, BadRequest(ctx, err.Error()))
|
||||
return
|
||||
}
|
||||
resp, respHdr, err := readBucket(ctx, userCred, o.Bucket, query, r)
|
||||
@@ -342,7 +342,7 @@ func readHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
SendError(w, BadRequest(ctx, err.Error()))
|
||||
SendError(ctx, w, BadRequest(ctx, err.Error()))
|
||||
return
|
||||
}
|
||||
resp, respHdr, err := readObject(ctx, userCred, o.Bucket, o.Key, query, r)
|
||||
@@ -394,7 +394,7 @@ func postHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
// object post
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
SendError(w, BadRequest(ctx, err.Error()))
|
||||
SendError(ctx, w, BadRequest(ctx, err.Error()))
|
||||
return
|
||||
}
|
||||
resp, respHdr, err := postObject(ctx, userCred, o.Bucket, o.Key, query, r)
|
||||
@@ -405,7 +405,7 @@ func postHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
appsrv.SendXml(w, respHdr, resp)
|
||||
return
|
||||
}
|
||||
SendError(w, NotSupported(ctx, "method not supported"))
|
||||
SendError(ctx, w, NotSupported(ctx, "method not supported"))
|
||||
}
|
||||
|
||||
func putBucket(ctx context.Context, userCred mcclient.TokenCredential, bucket string, query jsonutils.JSONObject, r *http.Request) (interface{}, http.Header, error) {
|
||||
@@ -489,7 +489,7 @@ func putHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
// bucket put
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
SendError(w, BadRequest(ctx, err.Error()))
|
||||
SendError(ctx, w, BadRequest(ctx, err.Error()))
|
||||
return
|
||||
}
|
||||
resp, respHdr, err := putBucket(ctx, userCred, o.Bucket, query, r)
|
||||
@@ -503,7 +503,7 @@ func putHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
// object put
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
SendError(w, BadRequest(ctx, err.Error()))
|
||||
SendError(ctx, w, BadRequest(ctx, err.Error()))
|
||||
return
|
||||
}
|
||||
resp, respHdr, err := putObject(ctx, userCred, o.Bucket, o.Key, query, r)
|
||||
@@ -514,7 +514,7 @@ func putHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
appsrv.SendXml(w, respHdr, resp)
|
||||
return
|
||||
}
|
||||
SendError(w, NotSupported(ctx, "method not supported"))
|
||||
SendError(ctx, w, NotSupported(ctx, "method not supported"))
|
||||
}
|
||||
|
||||
func deleteBucket(ctx context.Context, userCred mcclient.TokenCredential, bucket string, query jsonutils.JSONObject) (interface{}, error) {
|
||||
@@ -573,7 +573,7 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
// bucket delete
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
SendError(w, BadRequest(ctx, err.Error()))
|
||||
SendError(ctx, w, BadRequest(ctx, err.Error()))
|
||||
return
|
||||
}
|
||||
resp, err := deleteBucket(ctx, userCred, o.Bucket, query)
|
||||
@@ -587,7 +587,7 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
// object delete
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
SendError(w, BadRequest(ctx, err.Error()))
|
||||
SendError(ctx, w, BadRequest(ctx, err.Error()))
|
||||
return
|
||||
}
|
||||
resp, err := deleteObject(ctx, userCred, o.Bucket, o.Key, query)
|
||||
@@ -598,5 +598,5 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
return
|
||||
}
|
||||
SendError(w, NotSupported(ctx, "method not supported"))
|
||||
SendError(ctx, w, NotSupported(ctx, "method not supported"))
|
||||
}
|
||||
|
||||
@@ -36,13 +36,13 @@ func s3authenticate(f appsrv.FilterHandler) appsrv.FilterHandler {
|
||||
|
||||
o, err := getObjectRequest(r)
|
||||
if err != nil {
|
||||
SendError(w, BadRequest(ctx, err.Error()))
|
||||
SendError(ctx, w, BadRequest(ctx, err.Error()))
|
||||
return
|
||||
}
|
||||
ctx = context.WithValue(ctx, S3_OBJECT_REQUEST, o)
|
||||
userCred, err := auth.VerifyRequest(*r, o.VirtualHost)
|
||||
if err != nil {
|
||||
SendError(w, Unauthenticated(ctx, err.Error()))
|
||||
SendError(ctx, w, Unauthenticated(ctx, err.Error()))
|
||||
return
|
||||
}
|
||||
ctx = context.WithValue(ctx, appctx.APP_CONTEXT_KEY_AUTH_TOKEN, userCred)
|
||||
|
||||
@@ -36,7 +36,7 @@ func errorMessage(msgFmt string, params ...interface{}) (string, Error) {
|
||||
}
|
||||
|
||||
err := Error{
|
||||
Id: msgFmtToTmpl(msgFmt),
|
||||
Id: msgFmt,
|
||||
Fields: fields,
|
||||
}
|
||||
|
||||
|
||||
@@ -151,13 +151,13 @@ func (idp *SSAMLIdpInstance) redirectLoginHandler(ctx context.Context, w http.Re
|
||||
input := samlutils.SIdpRedirectLoginInput{}
|
||||
err := query.Unmarshal(&input)
|
||||
if err != nil {
|
||||
httperrors.InputParameterError(w, "query.Unmarshal error %s", err)
|
||||
httperrors.InputParameterError(ctx, w, "query.Unmarshal error %s", err)
|
||||
return
|
||||
}
|
||||
log.Debugf("recv input %s", input)
|
||||
respHtml, err := idp.processLoginRequest(ctx, idpId, input)
|
||||
if err != nil {
|
||||
httperrors.InputParameterError(w, "parse parameter error %s", err)
|
||||
httperrors.InputParameterError(ctx, w, "parse parameter error %s", err)
|
||||
return
|
||||
}
|
||||
appsrv.SendHTML(w, respHtml)
|
||||
@@ -176,12 +176,12 @@ func (idp *SSAMLIdpInstance) idpInitiatedSSOHandler(ctx context.Context, w http.
|
||||
input := samlutils.SIdpInitiatedLoginInput{}
|
||||
err := query.Unmarshal(&input)
|
||||
if err != nil {
|
||||
httperrors.InputParameterError(w, "unmarshal input fail %s", err)
|
||||
httperrors.InputParameterError(ctx, w, "unmarshal input fail %s", err)
|
||||
return
|
||||
}
|
||||
respHtml, err := idp.processIdpInitiatedLogin(ctx, input)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendHTML(w, respHtml)
|
||||
|
||||
@@ -163,7 +163,7 @@ func (sp *SSAMLSpInstance) assertionConsumeHandler(ctx context.Context, w http.R
|
||||
|
||||
err := sp.processAssertionConsumer(ctx, w, samlResponse, relayState)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -173,12 +173,12 @@ func (sp *SSAMLSpInstance) spInitiatedSSOHandler(ctx context.Context, w http.Res
|
||||
input := samlutils.SSpInitiatedLoginInput{}
|
||||
err := query.Unmarshal(&input)
|
||||
if err != nil {
|
||||
httperrors.InputParameterError(w, "unmarshal input fail %s", err)
|
||||
httperrors.InputParameterError(ctx, w, "unmarshal input fail %s", err)
|
||||
return
|
||||
}
|
||||
redirectUrl, err := sp.ProcessSpInitiatedLogin(ctx, input)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendRedirect(w, redirectUrl)
|
||||
|
||||
+22
-22
@@ -134,12 +134,12 @@ func handleK8sCommand(
|
||||
) {
|
||||
env, err := fetchK8sEnv(ctx, w, r)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
cmd := cmdFactory(env)
|
||||
handleCommandSession(cmd, w)
|
||||
handleCommandSession(ctx, cmd, w)
|
||||
}
|
||||
|
||||
func handleK8sShell(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
@@ -154,86 +154,86 @@ func handleSshShell(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
||||
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
|
||||
env, err := fetchCloudEnv(ctx, w, r)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
cmd, err := command.NewSSHtoolSolCommand(ctx, userCred, env.Params["<ip>"], env.Body)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
handleCommandSession(cmd, w)
|
||||
handleCommandSession(ctx, cmd, w)
|
||||
}
|
||||
|
||||
func handleBaremetalShell(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
env, err := fetchCloudEnv(ctx, w, r)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
hostId := env.Params["<id>"]
|
||||
ret, err := modules.Hosts.GetSpecific(env.ClientSessin, hostId, "ipmi", nil)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
info := command.IpmiInfo{}
|
||||
err = ret.Unmarshal(&info)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
cmd, err := command.NewIpmitoolSolCommand(&info)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
handleCommandSession(cmd, w)
|
||||
handleCommandSession(ctx, cmd, w)
|
||||
}
|
||||
|
||||
func handleServerRemoteConsole(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
env, err := fetchCloudEnv(ctx, w, r)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
srvId := env.Params["<id>"]
|
||||
info, err := session.NewRemoteConsoleInfoByCloud(env.ClientSessin, srvId)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
switch info.Protocol {
|
||||
case session.ALIYUN, session.QCLOUD, session.OPENSTACK, session.VMRC, session.ZSTACK, session.CTYUN:
|
||||
responsePublicCloudConsole(info, w)
|
||||
responsePublicCloudConsole(ctx, info, w)
|
||||
case session.VNC, session.SPICE, session.WMKS:
|
||||
handleDataSession(info, w, url.Values{"password": {info.GetPassword()}}, true)
|
||||
handleDataSession(ctx, info, w, url.Values{"password": {info.GetPassword()}}, true)
|
||||
default:
|
||||
httperrors.NotAcceptableError(w, "Unspported remote console protocol: %s", info.Protocol)
|
||||
httperrors.NotAcceptableError(ctx, w, "Unspported remote console protocol: %s", info.Protocol)
|
||||
}
|
||||
}
|
||||
|
||||
func responsePublicCloudConsole(info *session.RemoteConsoleInfo, w http.ResponseWriter) {
|
||||
func responsePublicCloudConsole(ctx context.Context, info *session.RemoteConsoleInfo, w http.ResponseWriter) {
|
||||
data := jsonutils.NewDict()
|
||||
params, err := info.GetConnectParams()
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
data.Add(jsonutils.NewString(params), "connect_params")
|
||||
sendJSON(w, data)
|
||||
}
|
||||
|
||||
func handleDataSession(sData session.ISessionData, w http.ResponseWriter, connParams url.Values, b64Encode bool) {
|
||||
func handleDataSession(ctx context.Context, sData session.ISessionData, w http.ResponseWriter, connParams url.Values, b64Encode bool) {
|
||||
s, err := session.Manager.Save(sData)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
data := jsonutils.NewDict()
|
||||
params, err := s.GetConnectParams(connParams)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
if b64Encode {
|
||||
@@ -244,8 +244,8 @@ func handleDataSession(sData session.ISessionData, w http.ResponseWriter, connPa
|
||||
sendJSON(w, data)
|
||||
}
|
||||
|
||||
func handleCommandSession(cmd command.ICommand, w http.ResponseWriter) {
|
||||
handleDataSession(session.WrapCommandSession(cmd), w, nil, false)
|
||||
func handleCommandSession(ctx context.Context, cmd command.ICommand, w http.ResponseWriter) {
|
||||
handleDataSession(ctx, session.WrapCommandSession(cmd), w, nil, false)
|
||||
}
|
||||
|
||||
func sendJSON(w http.ResponseWriter, body jsonutils.JSONObject) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -32,20 +33,22 @@ func NewConnectionServer() *ConnectionServer {
|
||||
}
|
||||
|
||||
func (s *ConnectionServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
ctx := context.Background()
|
||||
ctx = httperrors.WithRequestLang(ctx, req)
|
||||
query, err := jsonutils.ParseQueryString(req.URL.RawQuery)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
log.Debugf("[connection] Get query: %v", query)
|
||||
accessToken, _ := query.GetString("access_token")
|
||||
if accessToken == "" {
|
||||
httperrors.BadRequestError(w, "Empty access_token")
|
||||
httperrors.BadRequestError(ctx, w, "Empty access_token")
|
||||
return
|
||||
}
|
||||
sessionObj, ok := session.Manager.Get(accessToken)
|
||||
if !ok {
|
||||
httperrors.NotFoundError(w, "session not found")
|
||||
httperrors.NotFoundError(ctx, w, "session not found")
|
||||
return
|
||||
}
|
||||
var srv http.Handler
|
||||
@@ -59,7 +62,7 @@ func (s *ConnectionServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
srv, err = NewTTYServer(sessionObj)
|
||||
}
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
srv.ServeHTTP(w, req)
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
package plural
|
||||
|
||||
// Form defines a plural form.
|
||||
//
|
||||
// Not all languages support all forms. Also, the meaning of each form varies
|
||||
// per language. It is important to note that the name of a form does not
|
||||
// necessarily correspond one-to-one with the set of numbers. For instance,
|
||||
// for Croation, One matches not only 1, but also 11, 21, etc.
|
||||
//
|
||||
// Each language must at least support the form "other".
|
||||
type Form byte
|
||||
|
||||
const (
|
||||
Other Form = iota
|
||||
Zero
|
||||
One
|
||||
Two
|
||||
Few
|
||||
Many
|
||||
)
|
||||
|
||||
var countMap = map[string]Form{
|
||||
"other": Other,
|
||||
"zero": Zero,
|
||||
"one": One,
|
||||
"two": Two,
|
||||
"few": Few,
|
||||
"many": Many,
|
||||
}
|
||||
|
||||
type pluralCheck struct {
|
||||
// category:
|
||||
// 3..7: opID
|
||||
// 0..2: category
|
||||
cat byte
|
||||
setID byte
|
||||
}
|
||||
|
||||
// opID identifies the type of operand in the plural rule, being i, n or f.
|
||||
// (v, w, and t are treated as filters in our implementation.)
|
||||
type opID byte
|
||||
|
||||
const (
|
||||
opMod opID = 0x1 // is '%' used?
|
||||
opNotEqual opID = 0x2 // using "!=" to compare
|
||||
opI opID = 0 << 2 // integers after taking the absolute value
|
||||
opN opID = 1 << 2 // full number (must be integer)
|
||||
opF opID = 2 << 2 // fraction
|
||||
opV opID = 3 << 2 // number of visible digits
|
||||
opW opID = 4 << 2 // number of visible digits without trailing zeros
|
||||
opBretonM opID = 5 << 2 // hard-wired rule for Breton
|
||||
opItalian800 opID = 6 << 2 // hard-wired rule for Italian
|
||||
opAzerbaijan00s opID = 7 << 2 // hard-wired rule for Azerbaijan
|
||||
)
|
||||
const (
|
||||
// Use this plural form to indicate the next rule needs to match as well.
|
||||
// The last condition in the list will have the correct plural form.
|
||||
andNext = 0x7
|
||||
formMask = 0x7
|
||||
|
||||
opShift = 3
|
||||
|
||||
// numN indicates the maximum integer, or maximum mod value, for which we
|
||||
// have inclusion masks.
|
||||
numN = 100
|
||||
// The common denominator of the modulo that is taken.
|
||||
maxMod = 100
|
||||
)
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package plural
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/text/internal/catmsg"
|
||||
"golang.org/x/text/internal/number"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message/catalog"
|
||||
)
|
||||
|
||||
// TODO: consider deleting this interface. Maybe VisibleDigits is always
|
||||
// sufficient and practical.
|
||||
|
||||
// Interface is used for types that can determine their own plural form.
|
||||
type Interface interface {
|
||||
// PluralForm reports the plural form for the given language of the
|
||||
// underlying value. It also returns the integer value. If the integer value
|
||||
// is larger than fits in n, PluralForm may return a value modulo
|
||||
// 10,000,000.
|
||||
PluralForm(t language.Tag, scale int) (f Form, n int)
|
||||
}
|
||||
|
||||
// Selectf returns the first case for which its selector is a match for the
|
||||
// arg-th substitution argument to a formatting call, formatting it as indicated
|
||||
// by format.
|
||||
//
|
||||
// The cases argument are pairs of selectors and messages. Selectors are of type
|
||||
// string or Form. Messages are of type string or catalog.Message. A selector
|
||||
// matches an argument if:
|
||||
// - it is "other" or Other
|
||||
// - it matches the plural form of the argument: "zero", "one", "two", "few",
|
||||
// or "many", or the equivalent Form
|
||||
// - it is of the form "=x" where x is an integer that matches the value of
|
||||
// the argument.
|
||||
// - it is of the form "<x" where x is an integer that is larger than the
|
||||
// argument.
|
||||
//
|
||||
// The format argument determines the formatting parameters for which to
|
||||
// determine the plural form. This is especially relevant for non-integer
|
||||
// values.
|
||||
//
|
||||
// The format string may be "", in which case a best-effort attempt is made to
|
||||
// find a reasonable representation on which to base the plural form. Examples
|
||||
// of format strings are:
|
||||
// - %.2f decimal with scale 2
|
||||
// - %.2e scientific notation with precision 3 (scale + 1)
|
||||
// - %d integer
|
||||
func Selectf(arg int, format string, cases ...interface{}) catalog.Message {
|
||||
var p parser
|
||||
// Intercept the formatting parameters of format by doing a dummy print.
|
||||
fmt.Fprintf(ioutil.Discard, format, &p)
|
||||
m := &message{arg, kindDefault, 0, cases}
|
||||
switch p.verb {
|
||||
case 'g':
|
||||
m.kind = kindPrecision
|
||||
m.scale = p.scale
|
||||
case 'f':
|
||||
m.kind = kindScale
|
||||
m.scale = p.scale
|
||||
case 'e':
|
||||
m.kind = kindScientific
|
||||
m.scale = p.scale
|
||||
case 'd':
|
||||
m.kind = kindScale
|
||||
m.scale = 0
|
||||
default:
|
||||
// TODO: do we need to handle errors?
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type parser struct {
|
||||
verb rune
|
||||
scale int
|
||||
}
|
||||
|
||||
func (p *parser) Format(s fmt.State, verb rune) {
|
||||
p.verb = verb
|
||||
p.scale = -1
|
||||
if prec, ok := s.Precision(); ok {
|
||||
p.scale = prec
|
||||
}
|
||||
}
|
||||
|
||||
type message struct {
|
||||
arg int
|
||||
kind int
|
||||
scale int
|
||||
cases []interface{}
|
||||
}
|
||||
|
||||
const (
|
||||
// Start with non-ASCII to allow skipping values.
|
||||
kindDefault = 0x80 + iota
|
||||
kindScale // verb f, number of fraction digits follows
|
||||
kindScientific // verb e, number of fraction digits follows
|
||||
kindPrecision // verb g, number of significant digits follows
|
||||
)
|
||||
|
||||
var handle = catmsg.Register("golang.org/x/text/feature/plural:plural", execute)
|
||||
|
||||
func (m *message) Compile(e *catmsg.Encoder) error {
|
||||
e.EncodeMessageType(handle)
|
||||
|
||||
e.EncodeUint(uint64(m.arg))
|
||||
|
||||
e.EncodeUint(uint64(m.kind))
|
||||
if m.kind > kindDefault {
|
||||
e.EncodeUint(uint64(m.scale))
|
||||
}
|
||||
|
||||
forms := validForms(cardinal, e.Language())
|
||||
|
||||
for i := 0; i < len(m.cases); {
|
||||
if err := compileSelector(e, forms, m.cases[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
if i++; i >= len(m.cases) {
|
||||
return fmt.Errorf("plural: no message defined for selector %v", m.cases[i-1])
|
||||
}
|
||||
var msg catalog.Message
|
||||
switch x := m.cases[i].(type) {
|
||||
case string:
|
||||
msg = catalog.String(x)
|
||||
case catalog.Message:
|
||||
msg = x
|
||||
default:
|
||||
return fmt.Errorf("plural: message of type %T; must be string or catalog.Message", x)
|
||||
}
|
||||
if err := e.EncodeMessage(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
i++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func compileSelector(e *catmsg.Encoder, valid []Form, selector interface{}) error {
|
||||
form := Other
|
||||
switch x := selector.(type) {
|
||||
case string:
|
||||
if x == "" {
|
||||
return fmt.Errorf("plural: empty selector")
|
||||
}
|
||||
if c := x[0]; c == '=' || c == '<' {
|
||||
val, err := strconv.ParseUint(x[1:], 10, 16)
|
||||
if err != nil {
|
||||
return fmt.Errorf("plural: invalid number in selector %q: %v", selector, err)
|
||||
}
|
||||
e.EncodeUint(uint64(c))
|
||||
e.EncodeUint(val)
|
||||
return nil
|
||||
}
|
||||
var ok bool
|
||||
form, ok = countMap[x]
|
||||
if !ok {
|
||||
return fmt.Errorf("plural: invalid plural form %q", selector)
|
||||
}
|
||||
case Form:
|
||||
form = x
|
||||
default:
|
||||
return fmt.Errorf("plural: selector of type %T; want string or Form", selector)
|
||||
}
|
||||
|
||||
ok := false
|
||||
for _, f := range valid {
|
||||
if f == form {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("plural: form %q not supported for language %q", selector, e.Language())
|
||||
}
|
||||
e.EncodeUint(uint64(form))
|
||||
return nil
|
||||
}
|
||||
|
||||
func execute(d *catmsg.Decoder) bool {
|
||||
lang := d.Language()
|
||||
argN := int(d.DecodeUint())
|
||||
kind := int(d.DecodeUint())
|
||||
scale := -1 // default
|
||||
if kind > kindDefault {
|
||||
scale = int(d.DecodeUint())
|
||||
}
|
||||
form := Other
|
||||
n := -1
|
||||
if arg := d.Arg(argN); arg == nil {
|
||||
// Default to Other.
|
||||
} else if x, ok := arg.(number.VisibleDigits); ok {
|
||||
d := x.Digits(nil, lang, scale)
|
||||
form, n = cardinal.matchDisplayDigits(lang, &d)
|
||||
} else if x, ok := arg.(Interface); ok {
|
||||
// This covers lists and formatters from the number package.
|
||||
form, n = x.PluralForm(lang, scale)
|
||||
} else {
|
||||
var f number.Formatter
|
||||
switch kind {
|
||||
case kindScale:
|
||||
f.InitDecimal(lang)
|
||||
f.SetScale(scale)
|
||||
case kindScientific:
|
||||
f.InitScientific(lang)
|
||||
f.SetScale(scale)
|
||||
case kindPrecision:
|
||||
f.InitDecimal(lang)
|
||||
f.SetPrecision(scale)
|
||||
case kindDefault:
|
||||
// sensible default
|
||||
f.InitDecimal(lang)
|
||||
if k := reflect.TypeOf(arg).Kind(); reflect.Int <= k && k <= reflect.Uintptr {
|
||||
f.SetScale(0)
|
||||
} else {
|
||||
f.SetScale(2)
|
||||
}
|
||||
}
|
||||
var dec number.Decimal // TODO: buffer in Printer
|
||||
dec.Convert(f.RoundingContext, arg)
|
||||
v := number.FormatDigits(&dec, f.RoundingContext)
|
||||
if !v.NaN && !v.Inf {
|
||||
form, n = cardinal.matchDisplayDigits(d.Language(), &v)
|
||||
}
|
||||
}
|
||||
for !d.Done() {
|
||||
f := d.DecodeUint()
|
||||
if (f == '=' && n == int(d.DecodeUint())) ||
|
||||
(f == '<' && 0 <= n && n < int(d.DecodeUint())) ||
|
||||
form == Form(f) ||
|
||||
Other == Form(f) {
|
||||
return d.ExecuteMessage()
|
||||
}
|
||||
d.SkipMessage()
|
||||
}
|
||||
return false
|
||||
}
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen.go gen_common.go
|
||||
|
||||
// Package plural provides utilities for handling linguistic plurals in text.
|
||||
//
|
||||
// The definitions in this package are based on the plural rule handling defined
|
||||
// in CLDR. See
|
||||
// https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules for
|
||||
// details.
|
||||
package plural
|
||||
|
||||
import (
|
||||
"golang.org/x/text/internal/language/compact"
|
||||
"golang.org/x/text/internal/number"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// Rules defines the plural rules for all languages for a certain plural type.
|
||||
//
|
||||
//
|
||||
// This package is UNDER CONSTRUCTION and its API may change.
|
||||
type Rules struct {
|
||||
rules []pluralCheck
|
||||
index []byte
|
||||
langToIndex []byte
|
||||
inclusionMasks []uint64
|
||||
}
|
||||
|
||||
var (
|
||||
// Cardinal defines the plural rules for numbers indicating quantities.
|
||||
Cardinal *Rules = cardinal
|
||||
|
||||
// Ordinal defines the plural rules for numbers indicating position
|
||||
// (first, second, etc.).
|
||||
Ordinal *Rules = ordinal
|
||||
|
||||
ordinal = &Rules{
|
||||
ordinalRules,
|
||||
ordinalIndex,
|
||||
ordinalLangToIndex,
|
||||
ordinalInclusionMasks[:],
|
||||
}
|
||||
|
||||
cardinal = &Rules{
|
||||
cardinalRules,
|
||||
cardinalIndex,
|
||||
cardinalLangToIndex,
|
||||
cardinalInclusionMasks[:],
|
||||
}
|
||||
)
|
||||
|
||||
// getIntApprox converts the digits in slice digits[start:end] to an integer
|
||||
// according to the following rules:
|
||||
// - Let i be asInt(digits[start:end]), where out-of-range digits are assumed
|
||||
// to be zero.
|
||||
// - Result n is big if i / 10^nMod > 1.
|
||||
// - Otherwise the result is i % 10^nMod.
|
||||
//
|
||||
// For example, if digits is {1, 2, 3} and start:end is 0:5, then the result
|
||||
// for various values of nMod is:
|
||||
// - when nMod == 2, n == big
|
||||
// - when nMod == 3, n == big
|
||||
// - when nMod == 4, n == big
|
||||
// - when nMod == 5, n == 12300
|
||||
// - when nMod == 6, n == 12300
|
||||
// - when nMod == 7, n == 12300
|
||||
func getIntApprox(digits []byte, start, end, nMod, big int) (n int) {
|
||||
// Leading 0 digits just result in 0.
|
||||
p := start
|
||||
if p < 0 {
|
||||
p = 0
|
||||
}
|
||||
// Range only over the part for which we have digits.
|
||||
mid := end
|
||||
if mid >= len(digits) {
|
||||
mid = len(digits)
|
||||
}
|
||||
// Check digits more significant that nMod.
|
||||
if q := end - nMod; q > 0 {
|
||||
if q > mid {
|
||||
q = mid
|
||||
}
|
||||
for ; p < q; p++ {
|
||||
if digits[p] != 0 {
|
||||
return big
|
||||
}
|
||||
}
|
||||
}
|
||||
for ; p < mid; p++ {
|
||||
n = 10*n + int(digits[p])
|
||||
}
|
||||
// Multiply for trailing zeros.
|
||||
for ; p < end; p++ {
|
||||
n *= 10
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// MatchDigits computes the plural form for the given language and the given
|
||||
// decimal floating point digits. The digits are stored in big-endian order and
|
||||
// are of value byte(0) - byte(9). The floating point position is indicated by
|
||||
// exp and the number of visible decimals is scale. All leading and trailing
|
||||
// zeros may be omitted from digits.
|
||||
//
|
||||
// The following table contains examples of possible arguments to represent
|
||||
// the given numbers.
|
||||
// decimal digits exp scale
|
||||
// 123 []byte{1, 2, 3} 3 0
|
||||
// 123.4 []byte{1, 2, 3, 4} 3 1
|
||||
// 123.40 []byte{1, 2, 3, 4} 3 2
|
||||
// 100000 []byte{1} 6 0
|
||||
// 100000.00 []byte{1} 6 3
|
||||
func (p *Rules) MatchDigits(t language.Tag, digits []byte, exp, scale int) Form {
|
||||
index := tagToID(t)
|
||||
|
||||
// Differentiate up to including mod 1000000 for the integer part.
|
||||
n := getIntApprox(digits, 0, exp, 6, 1000000)
|
||||
|
||||
// Differentiate up to including mod 100 for the fractional part.
|
||||
f := getIntApprox(digits, exp, exp+scale, 2, 100)
|
||||
|
||||
return matchPlural(p, index, n, f, scale)
|
||||
}
|
||||
|
||||
func (p *Rules) matchDisplayDigits(t language.Tag, d *number.Digits) (Form, int) {
|
||||
n := getIntApprox(d.Digits, 0, int(d.Exp), 6, 1000000)
|
||||
return p.MatchDigits(t, d.Digits, int(d.Exp), d.NumFracDigits()), n
|
||||
}
|
||||
|
||||
func validForms(p *Rules, t language.Tag) (forms []Form) {
|
||||
offset := p.langToIndex[tagToID(t)]
|
||||
rules := p.rules[p.index[offset]:p.index[offset+1]]
|
||||
|
||||
forms = append(forms, Other)
|
||||
last := Other
|
||||
for _, r := range rules {
|
||||
if cat := Form(r.cat & formMask); cat != andNext && last != cat {
|
||||
forms = append(forms, cat)
|
||||
last = cat
|
||||
}
|
||||
}
|
||||
return forms
|
||||
}
|
||||
|
||||
func (p *Rules) matchComponents(t language.Tag, n, f, scale int) Form {
|
||||
return matchPlural(p, tagToID(t), n, f, scale)
|
||||
}
|
||||
|
||||
// MatchPlural returns the plural form for the given language and plural
|
||||
// operands (as defined in
|
||||
// https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules):
|
||||
// where
|
||||
// n absolute value of the source number (integer and decimals)
|
||||
// input
|
||||
// i integer digits of n.
|
||||
// v number of visible fraction digits in n, with trailing zeros.
|
||||
// w number of visible fraction digits in n, without trailing zeros.
|
||||
// f visible fractional digits in n, with trailing zeros (f = t * 10^(v-w))
|
||||
// t visible fractional digits in n, without trailing zeros.
|
||||
//
|
||||
// If any of the operand values is too large to fit in an int, it is okay to
|
||||
// pass the value modulo 10,000,000.
|
||||
func (p *Rules) MatchPlural(lang language.Tag, i, v, w, f, t int) Form {
|
||||
return matchPlural(p, tagToID(lang), i, f, v)
|
||||
}
|
||||
|
||||
func matchPlural(p *Rules, index compact.ID, n, f, v int) Form {
|
||||
nMask := p.inclusionMasks[n%maxMod]
|
||||
// Compute the fMask inline in the rules below, as it is relatively rare.
|
||||
// fMask := p.inclusionMasks[f%maxMod]
|
||||
vMask := p.inclusionMasks[v%maxMod]
|
||||
|
||||
// Do the matching
|
||||
offset := p.langToIndex[index]
|
||||
rules := p.rules[p.index[offset]:p.index[offset+1]]
|
||||
for i := 0; i < len(rules); i++ {
|
||||
rule := rules[i]
|
||||
setBit := uint64(1 << rule.setID)
|
||||
var skip bool
|
||||
switch op := opID(rule.cat >> opShift); op {
|
||||
case opI: // i = x
|
||||
skip = n >= numN || nMask&setBit == 0
|
||||
|
||||
case opI | opNotEqual: // i != x
|
||||
skip = n < numN && nMask&setBit != 0
|
||||
|
||||
case opI | opMod: // i % m = x
|
||||
skip = nMask&setBit == 0
|
||||
|
||||
case opI | opMod | opNotEqual: // i % m != x
|
||||
skip = nMask&setBit != 0
|
||||
|
||||
case opN: // n = x
|
||||
skip = f != 0 || n >= numN || nMask&setBit == 0
|
||||
|
||||
case opN | opNotEqual: // n != x
|
||||
skip = f == 0 && n < numN && nMask&setBit != 0
|
||||
|
||||
case opN | opMod: // n % m = x
|
||||
skip = f != 0 || nMask&setBit == 0
|
||||
|
||||
case opN | opMod | opNotEqual: // n % m != x
|
||||
skip = f == 0 && nMask&setBit != 0
|
||||
|
||||
case opF: // f = x
|
||||
skip = f >= numN || p.inclusionMasks[f%maxMod]&setBit == 0
|
||||
|
||||
case opF | opNotEqual: // f != x
|
||||
skip = f < numN && p.inclusionMasks[f%maxMod]&setBit != 0
|
||||
|
||||
case opF | opMod: // f % m = x
|
||||
skip = p.inclusionMasks[f%maxMod]&setBit == 0
|
||||
|
||||
case opF | opMod | opNotEqual: // f % m != x
|
||||
skip = p.inclusionMasks[f%maxMod]&setBit != 0
|
||||
|
||||
case opV: // v = x
|
||||
skip = v < numN && vMask&setBit == 0
|
||||
|
||||
case opV | opNotEqual: // v != x
|
||||
skip = v < numN && vMask&setBit != 0
|
||||
|
||||
case opW: // w == 0
|
||||
skip = f != 0
|
||||
|
||||
case opW | opNotEqual: // w != 0
|
||||
skip = f == 0
|
||||
|
||||
// Hard-wired rules that cannot be handled by our algorithm.
|
||||
|
||||
case opBretonM:
|
||||
skip = f != 0 || n == 0 || n%1000000 != 0
|
||||
|
||||
case opAzerbaijan00s:
|
||||
// 100,200,300,400,500,600,700,800,900
|
||||
skip = n == 0 || n >= 1000 || n%100 != 0
|
||||
|
||||
case opItalian800:
|
||||
skip = (f != 0 || n >= numN || nMask&setBit == 0) && n != 800
|
||||
}
|
||||
if skip {
|
||||
// advance over AND entries.
|
||||
for ; i < len(rules) && rules[i].cat&formMask == andNext; i++ {
|
||||
}
|
||||
continue
|
||||
}
|
||||
// return if we have a final entry.
|
||||
if cat := rule.cat & formMask; cat != andNext {
|
||||
return Form(cat)
|
||||
}
|
||||
}
|
||||
return Other
|
||||
}
|
||||
|
||||
func tagToID(t language.Tag) compact.ID {
|
||||
id, _ := compact.RegionalID(compact.Tag(t))
|
||||
return id
|
||||
}
|
||||
+552
@@ -0,0 +1,552 @@
|
||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
package plural
|
||||
|
||||
// CLDRVersion is the CLDR version from which the tables in this package are derived.
|
||||
const CLDRVersion = "32"
|
||||
|
||||
var ordinalRules = []pluralCheck{ // 64 elements
|
||||
0: {cat: 0x2f, setID: 0x4},
|
||||
1: {cat: 0x3a, setID: 0x5},
|
||||
2: {cat: 0x22, setID: 0x1},
|
||||
3: {cat: 0x22, setID: 0x6},
|
||||
4: {cat: 0x22, setID: 0x7},
|
||||
5: {cat: 0x2f, setID: 0x8},
|
||||
6: {cat: 0x3c, setID: 0x9},
|
||||
7: {cat: 0x2f, setID: 0xa},
|
||||
8: {cat: 0x3c, setID: 0xb},
|
||||
9: {cat: 0x2c, setID: 0xc},
|
||||
10: {cat: 0x24, setID: 0xd},
|
||||
11: {cat: 0x2d, setID: 0xe},
|
||||
12: {cat: 0x2d, setID: 0xf},
|
||||
13: {cat: 0x2f, setID: 0x10},
|
||||
14: {cat: 0x35, setID: 0x3},
|
||||
15: {cat: 0xc5, setID: 0x11},
|
||||
16: {cat: 0x2, setID: 0x1},
|
||||
17: {cat: 0x5, setID: 0x3},
|
||||
18: {cat: 0xd, setID: 0x12},
|
||||
19: {cat: 0x22, setID: 0x1},
|
||||
20: {cat: 0x2f, setID: 0x13},
|
||||
21: {cat: 0x3d, setID: 0x14},
|
||||
22: {cat: 0x2f, setID: 0x15},
|
||||
23: {cat: 0x3a, setID: 0x16},
|
||||
24: {cat: 0x2f, setID: 0x17},
|
||||
25: {cat: 0x3b, setID: 0x18},
|
||||
26: {cat: 0x2f, setID: 0xa},
|
||||
27: {cat: 0x3c, setID: 0xb},
|
||||
28: {cat: 0x22, setID: 0x1},
|
||||
29: {cat: 0x23, setID: 0x19},
|
||||
30: {cat: 0x24, setID: 0x1a},
|
||||
31: {cat: 0x22, setID: 0x1b},
|
||||
32: {cat: 0x23, setID: 0x2},
|
||||
33: {cat: 0x24, setID: 0x1a},
|
||||
34: {cat: 0xf, setID: 0x15},
|
||||
35: {cat: 0x1a, setID: 0x16},
|
||||
36: {cat: 0xf, setID: 0x17},
|
||||
37: {cat: 0x1b, setID: 0x18},
|
||||
38: {cat: 0xf, setID: 0x1c},
|
||||
39: {cat: 0x1d, setID: 0x1d},
|
||||
40: {cat: 0xa, setID: 0x1e},
|
||||
41: {cat: 0xa, setID: 0x1f},
|
||||
42: {cat: 0xc, setID: 0x20},
|
||||
43: {cat: 0xe4, setID: 0x0},
|
||||
44: {cat: 0x5, setID: 0x3},
|
||||
45: {cat: 0xd, setID: 0xe},
|
||||
46: {cat: 0xd, setID: 0x21},
|
||||
47: {cat: 0x22, setID: 0x1},
|
||||
48: {cat: 0x23, setID: 0x19},
|
||||
49: {cat: 0x24, setID: 0x1a},
|
||||
50: {cat: 0x25, setID: 0x22},
|
||||
51: {cat: 0x22, setID: 0x23},
|
||||
52: {cat: 0x23, setID: 0x19},
|
||||
53: {cat: 0x24, setID: 0x1a},
|
||||
54: {cat: 0x25, setID: 0x22},
|
||||
55: {cat: 0x22, setID: 0x24},
|
||||
56: {cat: 0x23, setID: 0x19},
|
||||
57: {cat: 0x24, setID: 0x1a},
|
||||
58: {cat: 0x25, setID: 0x22},
|
||||
59: {cat: 0x21, setID: 0x25},
|
||||
60: {cat: 0x22, setID: 0x1},
|
||||
61: {cat: 0x23, setID: 0x2},
|
||||
62: {cat: 0x24, setID: 0x26},
|
||||
63: {cat: 0x25, setID: 0x27},
|
||||
} // Size: 152 bytes
|
||||
|
||||
var ordinalIndex = []uint8{ // 22 elements
|
||||
0x00, 0x00, 0x02, 0x03, 0x04, 0x05, 0x07, 0x09,
|
||||
0x0b, 0x0f, 0x10, 0x13, 0x16, 0x1c, 0x1f, 0x22,
|
||||
0x28, 0x2f, 0x33, 0x37, 0x3b, 0x40,
|
||||
} // Size: 46 bytes
|
||||
|
||||
var ordinalLangToIndex = []uint8{ // 775 elements
|
||||
// Entry 0 - 3F
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x00, 0x00, 0x05, 0x05, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 40 - 7F
|
||||
0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
|
||||
0x0e, 0x0e, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 80 - BF
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
// Entry C0 - FF
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 100 - 13F
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02,
|
||||
0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
// Entry 140 - 17F
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
|
||||
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
|
||||
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 180 - 1BF
|
||||
0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 1C0 - 1FF
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x0d, 0x0d, 0x02, 0x02, 0x02,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 200 - 23F
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 240 - 27F
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||||
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 280 - 2BF
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0b, 0x0b, 0x0b, 0x0b, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x07, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 2C0 - 2FF
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 300 - 33F
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x0c,
|
||||
} // Size: 799 bytes
|
||||
|
||||
var ordinalInclusionMasks = []uint64{ // 100 elements
|
||||
// Entry 0 - 1F
|
||||
0x0000002000010009, 0x00000018482000d3, 0x0000000042840195, 0x000000410a040581,
|
||||
0x00000041040c0081, 0x0000009840040041, 0x0000008400045001, 0x0000003850040001,
|
||||
0x0000003850060001, 0x0000003800049001, 0x0000000800052001, 0x0000000040660031,
|
||||
0x0000000041840331, 0x0000000100040f01, 0x00000001001c0001, 0x0000000040040001,
|
||||
0x0000000000045001, 0x0000000070040001, 0x0000000070040001, 0x0000000000049001,
|
||||
0x0000000080050001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
|
||||
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
|
||||
0x0000000050000001, 0x0000000000009001, 0x0000000000010001, 0x0000000040200011,
|
||||
// Entry 20 - 3F
|
||||
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
|
||||
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
|
||||
0x0000000200050001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
|
||||
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
|
||||
0x0000000050000001, 0x0000000000009001, 0x0000000080010001, 0x0000000040200011,
|
||||
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
|
||||
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
|
||||
0x0000000200050001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
|
||||
// Entry 40 - 5F
|
||||
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
|
||||
0x0000000050000001, 0x0000000000009001, 0x0000000080010001, 0x0000000040200011,
|
||||
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
|
||||
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
|
||||
0x0000000080070001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
|
||||
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
|
||||
0x0000000050000001, 0x0000000000009001, 0x0000000200010001, 0x0000000040200011,
|
||||
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
|
||||
// Entry 60 - 7F
|
||||
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
|
||||
} // Size: 824 bytes
|
||||
|
||||
// Slots used for ordinal: 40 of 0xFF rules; 16 of 0xFF indexes; 40 of 64 sets
|
||||
|
||||
var cardinalRules = []pluralCheck{ // 166 elements
|
||||
0: {cat: 0x2, setID: 0x3},
|
||||
1: {cat: 0x22, setID: 0x1},
|
||||
2: {cat: 0x2, setID: 0x4},
|
||||
3: {cat: 0x2, setID: 0x4},
|
||||
4: {cat: 0x7, setID: 0x1},
|
||||
5: {cat: 0x62, setID: 0x3},
|
||||
6: {cat: 0x22, setID: 0x4},
|
||||
7: {cat: 0x7, setID: 0x3},
|
||||
8: {cat: 0x42, setID: 0x1},
|
||||
9: {cat: 0x22, setID: 0x4},
|
||||
10: {cat: 0x22, setID: 0x4},
|
||||
11: {cat: 0x22, setID: 0x5},
|
||||
12: {cat: 0x22, setID: 0x1},
|
||||
13: {cat: 0x22, setID: 0x1},
|
||||
14: {cat: 0x7, setID: 0x4},
|
||||
15: {cat: 0x92, setID: 0x3},
|
||||
16: {cat: 0xf, setID: 0x6},
|
||||
17: {cat: 0x1f, setID: 0x7},
|
||||
18: {cat: 0x82, setID: 0x3},
|
||||
19: {cat: 0x92, setID: 0x3},
|
||||
20: {cat: 0xf, setID: 0x6},
|
||||
21: {cat: 0x62, setID: 0x3},
|
||||
22: {cat: 0x4a, setID: 0x6},
|
||||
23: {cat: 0x7, setID: 0x8},
|
||||
24: {cat: 0x62, setID: 0x3},
|
||||
25: {cat: 0x1f, setID: 0x9},
|
||||
26: {cat: 0x62, setID: 0x3},
|
||||
27: {cat: 0x5f, setID: 0x9},
|
||||
28: {cat: 0x72, setID: 0x3},
|
||||
29: {cat: 0x29, setID: 0xa},
|
||||
30: {cat: 0x29, setID: 0xb},
|
||||
31: {cat: 0x4f, setID: 0xb},
|
||||
32: {cat: 0x61, setID: 0x2},
|
||||
33: {cat: 0x2f, setID: 0x6},
|
||||
34: {cat: 0x3a, setID: 0x7},
|
||||
35: {cat: 0x4f, setID: 0x6},
|
||||
36: {cat: 0x5f, setID: 0x7},
|
||||
37: {cat: 0x62, setID: 0x2},
|
||||
38: {cat: 0x4f, setID: 0x6},
|
||||
39: {cat: 0x72, setID: 0x2},
|
||||
40: {cat: 0x21, setID: 0x3},
|
||||
41: {cat: 0x7, setID: 0x4},
|
||||
42: {cat: 0x32, setID: 0x3},
|
||||
43: {cat: 0x21, setID: 0x3},
|
||||
44: {cat: 0x22, setID: 0x1},
|
||||
45: {cat: 0x22, setID: 0x1},
|
||||
46: {cat: 0x23, setID: 0x2},
|
||||
47: {cat: 0x2, setID: 0x3},
|
||||
48: {cat: 0x22, setID: 0x1},
|
||||
49: {cat: 0x24, setID: 0xc},
|
||||
50: {cat: 0x7, setID: 0x1},
|
||||
51: {cat: 0x62, setID: 0x3},
|
||||
52: {cat: 0x74, setID: 0x3},
|
||||
53: {cat: 0x24, setID: 0x3},
|
||||
54: {cat: 0x2f, setID: 0xd},
|
||||
55: {cat: 0x34, setID: 0x1},
|
||||
56: {cat: 0xf, setID: 0x6},
|
||||
57: {cat: 0x1f, setID: 0x7},
|
||||
58: {cat: 0x62, setID: 0x3},
|
||||
59: {cat: 0x4f, setID: 0x6},
|
||||
60: {cat: 0x5a, setID: 0x7},
|
||||
61: {cat: 0xf, setID: 0xe},
|
||||
62: {cat: 0x1f, setID: 0xf},
|
||||
63: {cat: 0x64, setID: 0x3},
|
||||
64: {cat: 0x4f, setID: 0xe},
|
||||
65: {cat: 0x5c, setID: 0xf},
|
||||
66: {cat: 0x22, setID: 0x10},
|
||||
67: {cat: 0x23, setID: 0x11},
|
||||
68: {cat: 0x24, setID: 0x12},
|
||||
69: {cat: 0xf, setID: 0x1},
|
||||
70: {cat: 0x62, setID: 0x3},
|
||||
71: {cat: 0xf, setID: 0x2},
|
||||
72: {cat: 0x63, setID: 0x3},
|
||||
73: {cat: 0xf, setID: 0x13},
|
||||
74: {cat: 0x64, setID: 0x3},
|
||||
75: {cat: 0x74, setID: 0x3},
|
||||
76: {cat: 0xf, setID: 0x1},
|
||||
77: {cat: 0x62, setID: 0x3},
|
||||
78: {cat: 0x4a, setID: 0x1},
|
||||
79: {cat: 0xf, setID: 0x2},
|
||||
80: {cat: 0x63, setID: 0x3},
|
||||
81: {cat: 0x4b, setID: 0x2},
|
||||
82: {cat: 0xf, setID: 0x13},
|
||||
83: {cat: 0x64, setID: 0x3},
|
||||
84: {cat: 0x4c, setID: 0x13},
|
||||
85: {cat: 0x7, setID: 0x1},
|
||||
86: {cat: 0x62, setID: 0x3},
|
||||
87: {cat: 0x7, setID: 0x2},
|
||||
88: {cat: 0x63, setID: 0x3},
|
||||
89: {cat: 0x2f, setID: 0xa},
|
||||
90: {cat: 0x37, setID: 0x14},
|
||||
91: {cat: 0x65, setID: 0x3},
|
||||
92: {cat: 0x7, setID: 0x1},
|
||||
93: {cat: 0x62, setID: 0x3},
|
||||
94: {cat: 0x7, setID: 0x15},
|
||||
95: {cat: 0x64, setID: 0x3},
|
||||
96: {cat: 0x75, setID: 0x3},
|
||||
97: {cat: 0x7, setID: 0x1},
|
||||
98: {cat: 0x62, setID: 0x3},
|
||||
99: {cat: 0xf, setID: 0xe},
|
||||
100: {cat: 0x1f, setID: 0xf},
|
||||
101: {cat: 0x64, setID: 0x3},
|
||||
102: {cat: 0xf, setID: 0x16},
|
||||
103: {cat: 0x17, setID: 0x1},
|
||||
104: {cat: 0x65, setID: 0x3},
|
||||
105: {cat: 0xf, setID: 0x17},
|
||||
106: {cat: 0x65, setID: 0x3},
|
||||
107: {cat: 0xf, setID: 0xf},
|
||||
108: {cat: 0x65, setID: 0x3},
|
||||
109: {cat: 0x2f, setID: 0x6},
|
||||
110: {cat: 0x3a, setID: 0x7},
|
||||
111: {cat: 0x2f, setID: 0xe},
|
||||
112: {cat: 0x3c, setID: 0xf},
|
||||
113: {cat: 0x2d, setID: 0xa},
|
||||
114: {cat: 0x2d, setID: 0x17},
|
||||
115: {cat: 0x2d, setID: 0x18},
|
||||
116: {cat: 0x2f, setID: 0x6},
|
||||
117: {cat: 0x3a, setID: 0xb},
|
||||
118: {cat: 0x2f, setID: 0x19},
|
||||
119: {cat: 0x3c, setID: 0xb},
|
||||
120: {cat: 0x55, setID: 0x3},
|
||||
121: {cat: 0x22, setID: 0x1},
|
||||
122: {cat: 0x24, setID: 0x3},
|
||||
123: {cat: 0x2c, setID: 0xc},
|
||||
124: {cat: 0x2d, setID: 0xb},
|
||||
125: {cat: 0xf, setID: 0x6},
|
||||
126: {cat: 0x1f, setID: 0x7},
|
||||
127: {cat: 0x62, setID: 0x3},
|
||||
128: {cat: 0xf, setID: 0xe},
|
||||
129: {cat: 0x1f, setID: 0xf},
|
||||
130: {cat: 0x64, setID: 0x3},
|
||||
131: {cat: 0xf, setID: 0xa},
|
||||
132: {cat: 0x65, setID: 0x3},
|
||||
133: {cat: 0xf, setID: 0x17},
|
||||
134: {cat: 0x65, setID: 0x3},
|
||||
135: {cat: 0xf, setID: 0x18},
|
||||
136: {cat: 0x65, setID: 0x3},
|
||||
137: {cat: 0x2f, setID: 0x6},
|
||||
138: {cat: 0x3a, setID: 0x1a},
|
||||
139: {cat: 0x2f, setID: 0x1b},
|
||||
140: {cat: 0x3b, setID: 0x1c},
|
||||
141: {cat: 0x2f, setID: 0x1d},
|
||||
142: {cat: 0x3c, setID: 0x1e},
|
||||
143: {cat: 0x37, setID: 0x3},
|
||||
144: {cat: 0xa5, setID: 0x0},
|
||||
145: {cat: 0x22, setID: 0x1},
|
||||
146: {cat: 0x23, setID: 0x2},
|
||||
147: {cat: 0x24, setID: 0x1f},
|
||||
148: {cat: 0x25, setID: 0x20},
|
||||
149: {cat: 0xf, setID: 0x6},
|
||||
150: {cat: 0x62, setID: 0x3},
|
||||
151: {cat: 0xf, setID: 0x1b},
|
||||
152: {cat: 0x63, setID: 0x3},
|
||||
153: {cat: 0xf, setID: 0x21},
|
||||
154: {cat: 0x64, setID: 0x3},
|
||||
155: {cat: 0x75, setID: 0x3},
|
||||
156: {cat: 0x21, setID: 0x3},
|
||||
157: {cat: 0x22, setID: 0x1},
|
||||
158: {cat: 0x23, setID: 0x2},
|
||||
159: {cat: 0x2c, setID: 0x22},
|
||||
160: {cat: 0x2d, setID: 0x5},
|
||||
161: {cat: 0x21, setID: 0x3},
|
||||
162: {cat: 0x22, setID: 0x1},
|
||||
163: {cat: 0x23, setID: 0x2},
|
||||
164: {cat: 0x24, setID: 0x23},
|
||||
165: {cat: 0x25, setID: 0x24},
|
||||
} // Size: 356 bytes
|
||||
|
||||
var cardinalIndex = []uint8{ // 36 elements
|
||||
0x00, 0x00, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0a,
|
||||
0x0c, 0x0d, 0x10, 0x14, 0x17, 0x1d, 0x28, 0x2b,
|
||||
0x2d, 0x2f, 0x32, 0x38, 0x42, 0x45, 0x4c, 0x55,
|
||||
0x5c, 0x61, 0x6d, 0x74, 0x79, 0x7d, 0x89, 0x91,
|
||||
0x95, 0x9c, 0xa1, 0xa6,
|
||||
} // Size: 60 bytes
|
||||
|
||||
var cardinalLangToIndex = []uint8{ // 775 elements
|
||||
// Entry 0 - 3F
|
||||
0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x06, 0x06,
|
||||
0x01, 0x01, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
|
||||
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
|
||||
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
|
||||
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
|
||||
0x01, 0x01, 0x08, 0x08, 0x04, 0x04, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x00, 0x00, 0x1a, 0x1a, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x06, 0x00, 0x00,
|
||||
// Entry 40 - 7F
|
||||
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x1e,
|
||||
0x08, 0x08, 0x13, 0x13, 0x13, 0x13, 0x13, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x18, 0x18, 0x00, 0x00, 0x22, 0x22, 0x09, 0x09,
|
||||
0x09, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x00, 0x00, 0x16, 0x16, 0x00,
|
||||
0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 80 - BF
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
// Entry C0 - FF
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
// Entry 100 - 13F
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04,
|
||||
0x08, 0x08, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x0c, 0x0c,
|
||||
0x08, 0x08, 0x08, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
// Entry 140 - 17F
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x08, 0x08, 0x04, 0x04, 0x1f, 0x1f,
|
||||
0x14, 0x14, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08,
|
||||
0x01, 0x01, 0x06, 0x00, 0x00, 0x20, 0x20, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x17, 0x17, 0x01,
|
||||
0x01, 0x13, 0x13, 0x13, 0x16, 0x16, 0x08, 0x08,
|
||||
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 180 - 1BF
|
||||
0x00, 0x04, 0x0a, 0x0a, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x10, 0x17, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x04, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x02,
|
||||
0x02, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x08, 0x08, 0x00, 0x00, 0x0f, 0x0f, 0x08, 0x10,
|
||||
// Entry 1C0 - 1FF
|
||||
0x10, 0x08, 0x08, 0x0e, 0x0e, 0x08, 0x08, 0x08,
|
||||
0x08, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0d, 0x08,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
|
||||
0x00, 0x00, 0x08, 0x08, 0x0b, 0x0b, 0x08, 0x08,
|
||||
0x08, 0x08, 0x12, 0x01, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 200 - 23F
|
||||
0x00, 0x08, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00,
|
||||
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08,
|
||||
0x06, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x08, 0x19, 0x19, 0x0d, 0x0d,
|
||||
0x08, 0x08, 0x03, 0x04, 0x03, 0x04, 0x04, 0x04,
|
||||
// Entry 240 - 27F
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x12,
|
||||
0x12, 0x12, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x1d,
|
||||
0x1d, 0x1d, 0x1d, 0x00, 0x00, 0x08, 0x08, 0x00,
|
||||
0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x08,
|
||||
0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x05, 0x05, 0x18, 0x18, 0x15, 0x15, 0x10, 0x10,
|
||||
// Entry 280 - 2BF
|
||||
0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x13,
|
||||
0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
|
||||
0x13, 0x13, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06,
|
||||
0x08, 0x08, 0x08, 0x0c, 0x08, 0x00, 0x00, 0x08,
|
||||
// Entry 2C0 - 2FF
|
||||
0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0x07, 0x08, 0x08, 0x1d, 0x1d, 0x04, 0x04, 0x04,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08,
|
||||
0x08, 0x08, 0x08, 0x06, 0x08, 0x08, 0x00, 0x00,
|
||||
0x08, 0x08, 0x08, 0x00, 0x00, 0x04, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 300 - 33F
|
||||
0x00, 0x00, 0x00, 0x01, 0x01, 0x04, 0x04,
|
||||
} // Size: 799 bytes
|
||||
|
||||
var cardinalInclusionMasks = []uint64{ // 100 elements
|
||||
// Entry 0 - 1F
|
||||
0x0000000200500419, 0x0000000000512153, 0x000000000a327105, 0x0000000ca23c7101,
|
||||
0x00000004a23c7201, 0x0000000482943001, 0x0000001482943201, 0x0000000502943001,
|
||||
0x0000000502943001, 0x0000000522943201, 0x0000000540543401, 0x00000000454128e1,
|
||||
0x000000005b02e821, 0x000000006304e821, 0x000000006304ea21, 0x0000000042842821,
|
||||
0x0000000042842a21, 0x0000000042842821, 0x0000000042842821, 0x0000000062842a21,
|
||||
0x0000000200400421, 0x0000000000400061, 0x000000000a004021, 0x0000000022004021,
|
||||
0x0000000022004221, 0x0000000002800021, 0x0000000002800221, 0x0000000002800021,
|
||||
0x0000000002800021, 0x0000000022800221, 0x0000000000400421, 0x0000000000400061,
|
||||
// Entry 20 - 3F
|
||||
0x000000000a004021, 0x0000000022004021, 0x0000000022004221, 0x0000000002800021,
|
||||
0x0000000002800221, 0x0000000002800021, 0x0000000002800021, 0x0000000022800221,
|
||||
0x0000000200400421, 0x0000000000400061, 0x000000000a004021, 0x0000000022004021,
|
||||
0x0000000022004221, 0x0000000002800021, 0x0000000002800221, 0x0000000002800021,
|
||||
0x0000000002800021, 0x0000000022800221, 0x0000000000400421, 0x0000000000400061,
|
||||
0x000000000a004021, 0x0000000022004021, 0x0000000022004221, 0x0000000002800021,
|
||||
0x0000000002800221, 0x0000000002800021, 0x0000000002800021, 0x0000000022800221,
|
||||
0x0000000200400421, 0x0000000000400061, 0x000000000a004021, 0x0000000022004021,
|
||||
// Entry 40 - 5F
|
||||
0x0000000022004221, 0x0000000002800021, 0x0000000002800221, 0x0000000002800021,
|
||||
0x0000000002800021, 0x0000000022800221, 0x0000000040400421, 0x0000000044400061,
|
||||
0x000000005a004021, 0x0000000062004021, 0x0000000062004221, 0x0000000042800021,
|
||||
0x0000000042800221, 0x0000000042800021, 0x0000000042800021, 0x0000000062800221,
|
||||
0x0000000200400421, 0x0000000000400061, 0x000000000a004021, 0x0000000022004021,
|
||||
0x0000000022004221, 0x0000000002800021, 0x0000000002800221, 0x0000000002800021,
|
||||
0x0000000002800021, 0x0000000022800221, 0x0000000040400421, 0x0000000044400061,
|
||||
0x000000005a004021, 0x0000000062004021, 0x0000000062004221, 0x0000000042800021,
|
||||
// Entry 60 - 7F
|
||||
0x0000000042800221, 0x0000000042800021, 0x0000000042800021, 0x0000000062800221,
|
||||
} // Size: 824 bytes
|
||||
|
||||
// Slots used for cardinal: A6 of 0xFF rules; 24 of 0xFF indexes; 37 of 64 sets
|
||||
|
||||
// Total table size 3860 bytes (3KiB); checksum: 4E56F7B1
|
||||
+415
@@ -0,0 +1,415 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package catmsg contains support types for package x/text/message/catalog.
|
||||
//
|
||||
// This package contains the low-level implementations of Message used by the
|
||||
// catalog package and provides primitives for other packages to implement their
|
||||
// own. For instance, the plural package provides functionality for selecting
|
||||
// translation strings based on the plural category of substitution arguments.
|
||||
//
|
||||
//
|
||||
// Encoding and Decoding
|
||||
//
|
||||
// Catalogs store Messages encoded as a single string. Compiling a message into
|
||||
// a string both results in compacter representation and speeds up evaluation.
|
||||
//
|
||||
// A Message must implement a Compile method to convert its arbitrary
|
||||
// representation to a string. The Compile method takes an Encoder which
|
||||
// facilitates serializing the message. Encoders also provide more context of
|
||||
// the messages's creation (such as for which language the message is intended),
|
||||
// which may not be known at the time of the creation of the message.
|
||||
//
|
||||
// Each message type must also have an accompanying decoder registered to decode
|
||||
// the message. This decoder takes a Decoder argument which provides the
|
||||
// counterparts for the decoding.
|
||||
//
|
||||
//
|
||||
// Renderers
|
||||
//
|
||||
// A Decoder must be initialized with a Renderer implementation. These
|
||||
// implementations must be provided by packages that use Catalogs, typically
|
||||
// formatting packages such as x/text/message. A typical user will not need to
|
||||
// worry about this type; it is only relevant to packages that do string
|
||||
// formatting and want to use the catalog package to handle localized strings.
|
||||
//
|
||||
// A package that uses catalogs for selecting strings receives selection results
|
||||
// as sequence of substrings passed to the Renderer. The following snippet shows
|
||||
// how to express the above example using the message package.
|
||||
//
|
||||
// message.Set(language.English, "You are %d minute(s) late.",
|
||||
// catalog.Var("minutes", plural.Select(1, "one", "minute")),
|
||||
// catalog.String("You are %[1]d ${minutes} late."))
|
||||
//
|
||||
// p := message.NewPrinter(language.English)
|
||||
// p.Printf("You are %d minute(s) late.", 5) // always 5 minutes late.
|
||||
//
|
||||
// To evaluate the Printf, package message wraps the arguments in a Renderer
|
||||
// that is passed to the catalog for message decoding. The call sequence that
|
||||
// results from evaluating the above message, assuming the person is rather
|
||||
// tardy, is:
|
||||
//
|
||||
// Render("You are %[1]d ")
|
||||
// Arg(1)
|
||||
// Render("minutes")
|
||||
// Render(" late.")
|
||||
//
|
||||
// The calls to Arg is caused by the plural.Select execution, which evaluates
|
||||
// the argument to determine whether the singular or plural message form should
|
||||
// be selected. The calls to Render reports the partial results to the message
|
||||
// package for further evaluation.
|
||||
package catmsg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// A Handle refers to a registered message type.
|
||||
type Handle int
|
||||
|
||||
// A Handler decodes and evaluates data compiled by a Message and sends the
|
||||
// result to the Decoder. The output may depend on the value of the substitution
|
||||
// arguments, accessible by the Decoder's Arg method. The Handler returns false
|
||||
// if there is no translation for the given substitution arguments.
|
||||
type Handler func(d *Decoder) bool
|
||||
|
||||
// Register records the existence of a message type and returns a Handle that
|
||||
// can be used in the Encoder's EncodeMessageType method to create such
|
||||
// messages. The prefix of the name should be the package path followed by
|
||||
// an optional disambiguating string.
|
||||
// Register will panic if a handle for the same name was already registered.
|
||||
func Register(name string, handler Handler) Handle {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if _, ok := names[name]; ok {
|
||||
panic(fmt.Errorf("catmsg: handler for %q already exists", name))
|
||||
}
|
||||
h := Handle(len(handlers))
|
||||
names[name] = h
|
||||
handlers = append(handlers, handler)
|
||||
return h
|
||||
}
|
||||
|
||||
// These handlers require fixed positions in the handlers slice.
|
||||
const (
|
||||
msgVars Handle = iota
|
||||
msgFirst
|
||||
msgRaw
|
||||
msgString
|
||||
msgAffix
|
||||
// Leave some arbitrary room for future expansion: 20 should suffice.
|
||||
numInternal = 20
|
||||
)
|
||||
|
||||
const prefix = "golang.org/x/text/internal/catmsg."
|
||||
|
||||
var (
|
||||
// TODO: find a more stable way to link handles to message types.
|
||||
mutex sync.Mutex
|
||||
names = map[string]Handle{
|
||||
prefix + "Vars": msgVars,
|
||||
prefix + "First": msgFirst,
|
||||
prefix + "Raw": msgRaw,
|
||||
prefix + "String": msgString,
|
||||
prefix + "Affix": msgAffix,
|
||||
}
|
||||
handlers = make([]Handler, numInternal)
|
||||
)
|
||||
|
||||
func init() {
|
||||
// This handler is a message type wrapper that initializes a decoder
|
||||
// with a variable block. This message type, if present, is always at the
|
||||
// start of an encoded message.
|
||||
handlers[msgVars] = func(d *Decoder) bool {
|
||||
blockSize := int(d.DecodeUint())
|
||||
d.vars = d.data[:blockSize]
|
||||
d.data = d.data[blockSize:]
|
||||
return d.executeMessage()
|
||||
}
|
||||
|
||||
// First takes the first message in a sequence that results in a match for
|
||||
// the given substitution arguments.
|
||||
handlers[msgFirst] = func(d *Decoder) bool {
|
||||
for !d.Done() {
|
||||
if d.ExecuteMessage() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
handlers[msgRaw] = func(d *Decoder) bool {
|
||||
d.Render(d.data)
|
||||
return true
|
||||
}
|
||||
|
||||
// A String message alternates between a string constant and a variable
|
||||
// substitution.
|
||||
handlers[msgString] = func(d *Decoder) bool {
|
||||
for !d.Done() {
|
||||
if str := d.DecodeString(); str != "" {
|
||||
d.Render(str)
|
||||
}
|
||||
if d.Done() {
|
||||
break
|
||||
}
|
||||
d.ExecuteSubstitution()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
handlers[msgAffix] = func(d *Decoder) bool {
|
||||
// TODO: use an alternative method for common cases.
|
||||
prefix := d.DecodeString()
|
||||
suffix := d.DecodeString()
|
||||
if prefix != "" {
|
||||
d.Render(prefix)
|
||||
}
|
||||
ret := d.ExecuteMessage()
|
||||
if suffix != "" {
|
||||
d.Render(suffix)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrIncomplete indicates a compiled message does not define translations
|
||||
// for all possible argument values. If this message is returned, evaluating
|
||||
// a message may result in the ErrNoMatch error.
|
||||
ErrIncomplete = errors.New("catmsg: incomplete message; may not give result for all inputs")
|
||||
|
||||
// ErrNoMatch indicates no translation message matched the given input
|
||||
// parameters when evaluating a message.
|
||||
ErrNoMatch = errors.New("catmsg: no translation for inputs")
|
||||
)
|
||||
|
||||
// A Message holds a collection of translations for the same phrase that may
|
||||
// vary based on the values of substitution arguments.
|
||||
type Message interface {
|
||||
// Compile encodes the format string(s) of the message as a string for later
|
||||
// evaluation.
|
||||
//
|
||||
// The first call Compile makes on the encoder must be EncodeMessageType.
|
||||
// The handle passed to this call may either be a handle returned by
|
||||
// Register to encode a single custom message, or HandleFirst followed by
|
||||
// a sequence of calls to EncodeMessage.
|
||||
//
|
||||
// Compile must return ErrIncomplete if it is possible for evaluation to
|
||||
// not match any translation for a given set of formatting parameters.
|
||||
// For example, selecting a translation based on plural form may not yield
|
||||
// a match if the form "Other" is not one of the selectors.
|
||||
//
|
||||
// Compile may return any other application-specific error. For backwards
|
||||
// compatibility with package like fmt, which often do not do sanity
|
||||
// checking of format strings ahead of time, Compile should still make an
|
||||
// effort to have some sensible fallback in case of an error.
|
||||
Compile(e *Encoder) error
|
||||
}
|
||||
|
||||
// Compile converts a Message to a data string that can be stored in a Catalog.
|
||||
// The resulting string can subsequently be decoded by passing to the Execute
|
||||
// method of a Decoder.
|
||||
func Compile(tag language.Tag, macros Dictionary, m Message) (data string, err error) {
|
||||
// TODO: pass macros so they can be used for validation.
|
||||
v := &Encoder{inBody: true} // encoder for variables
|
||||
v.root = v
|
||||
e := &Encoder{root: v, parent: v, tag: tag} // encoder for messages
|
||||
err = m.Compile(e)
|
||||
// This package serves te message package, which in turn is meant to be a
|
||||
// drop-in replacement for fmt. With the fmt package, format strings are
|
||||
// evaluated lazily and errors are handled by substituting strings in the
|
||||
// result, rather then returning an error. Dealing with multiple languages
|
||||
// makes it more important to check errors ahead of time. We chose to be
|
||||
// consistent and compatible and allow graceful degradation in case of
|
||||
// errors.
|
||||
buf := e.buf[stripPrefix(e.buf):]
|
||||
if len(v.buf) > 0 {
|
||||
// Prepend variable block.
|
||||
b := make([]byte, 1+maxVarintBytes+len(v.buf)+len(buf))
|
||||
b[0] = byte(msgVars)
|
||||
b = b[:1+encodeUint(b[1:], uint64(len(v.buf)))]
|
||||
b = append(b, v.buf...)
|
||||
b = append(b, buf...)
|
||||
buf = b
|
||||
}
|
||||
if err == nil {
|
||||
err = v.err
|
||||
}
|
||||
return string(buf), err
|
||||
}
|
||||
|
||||
// FirstOf is a message type that prints the first message in the sequence that
|
||||
// resolves to a match for the given substitution arguments.
|
||||
type FirstOf []Message
|
||||
|
||||
// Compile implements Message.
|
||||
func (s FirstOf) Compile(e *Encoder) error {
|
||||
e.EncodeMessageType(msgFirst)
|
||||
err := ErrIncomplete
|
||||
for i, m := range s {
|
||||
if err == nil {
|
||||
return fmt.Errorf("catalog: message argument %d is complete and blocks subsequent messages", i-1)
|
||||
}
|
||||
err = e.EncodeMessage(m)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Var defines a message that can be substituted for a placeholder of the same
|
||||
// name. If an expression does not result in a string after evaluation, Name is
|
||||
// used as the substitution. For example:
|
||||
// Var{
|
||||
// Name: "minutes",
|
||||
// Message: plural.Select(1, "one", "minute"),
|
||||
// }
|
||||
// will resolve to minute for singular and minutes for plural forms.
|
||||
type Var struct {
|
||||
Name string
|
||||
Message Message
|
||||
}
|
||||
|
||||
var errIsVar = errors.New("catmsg: variable used as message")
|
||||
|
||||
// Compile implements Message.
|
||||
//
|
||||
// Note that this method merely registers a variable; it does not create an
|
||||
// encoded message.
|
||||
func (v *Var) Compile(e *Encoder) error {
|
||||
if err := e.addVar(v.Name, v.Message); err != nil {
|
||||
return err
|
||||
}
|
||||
// Using a Var by itself is an error. If it is in a sequence followed by
|
||||
// other messages referring to it, this error will be ignored.
|
||||
return errIsVar
|
||||
}
|
||||
|
||||
// Raw is a message consisting of a single format string that is passed as is
|
||||
// to the Renderer.
|
||||
//
|
||||
// Note that a Renderer may still do its own variable substitution.
|
||||
type Raw string
|
||||
|
||||
// Compile implements Message.
|
||||
func (r Raw) Compile(e *Encoder) (err error) {
|
||||
e.EncodeMessageType(msgRaw)
|
||||
// Special case: raw strings don't have a size encoding and so don't use
|
||||
// EncodeString.
|
||||
e.buf = append(e.buf, r...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String is a message consisting of a single format string which contains
|
||||
// placeholders that may be substituted with variables.
|
||||
//
|
||||
// Variable substitutions are marked with placeholders and a variable name of
|
||||
// the form ${name}. Any other substitutions such as Go templates or
|
||||
// printf-style substitutions are left to be done by the Renderer.
|
||||
//
|
||||
// When evaluation a string interpolation, a Renderer will receive separate
|
||||
// calls for each placeholder and interstitial string. For example, for the
|
||||
// message: "%[1]v ${invites} %[2]v to ${their} party." The sequence of calls
|
||||
// is:
|
||||
// d.Render("%[1]v ")
|
||||
// d.Arg(1)
|
||||
// d.Render(resultOfInvites)
|
||||
// d.Render(" %[2]v to ")
|
||||
// d.Arg(2)
|
||||
// d.Render(resultOfTheir)
|
||||
// d.Render(" party.")
|
||||
// where the messages for "invites" and "their" both use a plural.Select
|
||||
// referring to the first argument.
|
||||
//
|
||||
// Strings may also invoke macros. Macros are essentially variables that can be
|
||||
// reused. Macros may, for instance, be used to make selections between
|
||||
// different conjugations of a verb. See the catalog package description for an
|
||||
// overview of macros.
|
||||
type String string
|
||||
|
||||
// Compile implements Message. It parses the placeholder formats and returns
|
||||
// any error.
|
||||
func (s String) Compile(e *Encoder) (err error) {
|
||||
msg := string(s)
|
||||
const subStart = "${"
|
||||
hasHeader := false
|
||||
p := 0
|
||||
b := []byte{}
|
||||
for {
|
||||
i := strings.Index(msg[p:], subStart)
|
||||
if i == -1 {
|
||||
break
|
||||
}
|
||||
b = append(b, msg[p:p+i]...)
|
||||
p += i + len(subStart)
|
||||
if i = strings.IndexByte(msg[p:], '}'); i == -1 {
|
||||
b = append(b, "$!(MISSINGBRACE)"...)
|
||||
err = fmt.Errorf("catmsg: missing '}'")
|
||||
p = len(msg)
|
||||
break
|
||||
}
|
||||
name := strings.TrimSpace(msg[p : p+i])
|
||||
if q := strings.IndexByte(name, '('); q == -1 {
|
||||
if !hasHeader {
|
||||
hasHeader = true
|
||||
e.EncodeMessageType(msgString)
|
||||
}
|
||||
e.EncodeString(string(b))
|
||||
e.EncodeSubstitution(name)
|
||||
b = b[:0]
|
||||
} else if j := strings.IndexByte(name[q:], ')'); j == -1 {
|
||||
// TODO: what should the error be?
|
||||
b = append(b, "$!(MISSINGPAREN)"...)
|
||||
err = fmt.Errorf("catmsg: missing ')'")
|
||||
} else if x, sErr := strconv.ParseUint(strings.TrimSpace(name[q+1:q+j]), 10, 32); sErr != nil {
|
||||
// TODO: handle more than one argument
|
||||
b = append(b, "$!(BADNUM)"...)
|
||||
err = fmt.Errorf("catmsg: invalid number %q", strings.TrimSpace(name[q+1:q+j]))
|
||||
} else {
|
||||
if !hasHeader {
|
||||
hasHeader = true
|
||||
e.EncodeMessageType(msgString)
|
||||
}
|
||||
e.EncodeString(string(b))
|
||||
e.EncodeSubstitution(name[:q], int(x))
|
||||
b = b[:0]
|
||||
}
|
||||
p += i + 1
|
||||
}
|
||||
b = append(b, msg[p:]...)
|
||||
if !hasHeader {
|
||||
// Simplify string to a raw string.
|
||||
Raw(string(b)).Compile(e)
|
||||
} else if len(b) > 0 {
|
||||
e.EncodeString(string(b))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Affix is a message that adds a prefix and suffix to another message.
|
||||
// This is mostly used add back whitespace to a translation that was stripped
|
||||
// before sending it out.
|
||||
type Affix struct {
|
||||
Message Message
|
||||
Prefix string
|
||||
Suffix string
|
||||
}
|
||||
|
||||
// Compile implements Message.
|
||||
func (a Affix) Compile(e *Encoder) (err error) {
|
||||
// TODO: consider adding a special message type that just adds a single
|
||||
// return. This is probably common enough to handle the majority of cases.
|
||||
// Get some stats first, though.
|
||||
e.EncodeMessageType(msgAffix)
|
||||
e.EncodeString(a.Prefix)
|
||||
e.EncodeString(a.Suffix)
|
||||
e.EncodeMessage(a.Message)
|
||||
return nil
|
||||
}
|
||||
+407
@@ -0,0 +1,407 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package catmsg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// A Renderer renders a Message.
|
||||
type Renderer interface {
|
||||
// Render renders the given string. The given string may be interpreted as a
|
||||
// format string, such as the one used by the fmt package or a template.
|
||||
Render(s string)
|
||||
|
||||
// Arg returns the i-th argument passed to format a message. This method
|
||||
// should return nil if there is no such argument. Messages need access to
|
||||
// arguments to allow selecting a message based on linguistic features of
|
||||
// those arguments.
|
||||
Arg(i int) interface{}
|
||||
}
|
||||
|
||||
// A Dictionary specifies a source of messages, including variables or macros.
|
||||
type Dictionary interface {
|
||||
// Lookup returns the message for the given key. It returns false for ok if
|
||||
// such a message could not be found.
|
||||
Lookup(key string) (data string, ok bool)
|
||||
|
||||
// TODO: consider returning an interface, instead of a string. This will
|
||||
// allow implementations to do their own message type decoding.
|
||||
}
|
||||
|
||||
// An Encoder serializes a Message to a string.
|
||||
type Encoder struct {
|
||||
// The root encoder is used for storing encoded variables.
|
||||
root *Encoder
|
||||
// The parent encoder provides the surrounding scopes for resolving variable
|
||||
// names.
|
||||
parent *Encoder
|
||||
|
||||
tag language.Tag
|
||||
|
||||
// buf holds the encoded message so far. After a message completes encoding,
|
||||
// the contents of buf, prefixed by the encoded length, are flushed to the
|
||||
// parent buffer.
|
||||
buf []byte
|
||||
|
||||
// vars is the lookup table of variables in the current scope.
|
||||
vars []keyVal
|
||||
|
||||
err error
|
||||
inBody bool // if false next call must be EncodeMessageType
|
||||
}
|
||||
|
||||
type keyVal struct {
|
||||
key string
|
||||
offset int
|
||||
}
|
||||
|
||||
// Language reports the language for which the encoded message will be stored
|
||||
// in the Catalog.
|
||||
func (e *Encoder) Language() language.Tag { return e.tag }
|
||||
|
||||
func (e *Encoder) setError(err error) {
|
||||
if e.root.err == nil {
|
||||
e.root.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeUint encodes x.
|
||||
func (e *Encoder) EncodeUint(x uint64) {
|
||||
e.checkInBody()
|
||||
var buf [maxVarintBytes]byte
|
||||
n := encodeUint(buf[:], x)
|
||||
e.buf = append(e.buf, buf[:n]...)
|
||||
}
|
||||
|
||||
// EncodeString encodes s.
|
||||
func (e *Encoder) EncodeString(s string) {
|
||||
e.checkInBody()
|
||||
e.EncodeUint(uint64(len(s)))
|
||||
e.buf = append(e.buf, s...)
|
||||
}
|
||||
|
||||
// EncodeMessageType marks the current message to be of type h.
|
||||
//
|
||||
// It must be the first call of a Message's Compile method.
|
||||
func (e *Encoder) EncodeMessageType(h Handle) {
|
||||
if e.inBody {
|
||||
panic("catmsg: EncodeMessageType not the first method called")
|
||||
}
|
||||
e.inBody = true
|
||||
e.EncodeUint(uint64(h))
|
||||
}
|
||||
|
||||
// EncodeMessage serializes the given message inline at the current position.
|
||||
func (e *Encoder) EncodeMessage(m Message) error {
|
||||
e = &Encoder{root: e.root, parent: e, tag: e.tag}
|
||||
err := m.Compile(e)
|
||||
if _, ok := m.(*Var); !ok {
|
||||
e.flushTo(e.parent)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Encoder) checkInBody() {
|
||||
if !e.inBody {
|
||||
panic("catmsg: expected prior call to EncodeMessageType")
|
||||
}
|
||||
}
|
||||
|
||||
// stripPrefix indicates the number of prefix bytes that must be stripped to
|
||||
// turn a single-element sequence into a message that is just this single member
|
||||
// without its size prefix. If the message can be stripped, b[1:n] contains the
|
||||
// size prefix.
|
||||
func stripPrefix(b []byte) (n int) {
|
||||
if len(b) > 0 && Handle(b[0]) == msgFirst {
|
||||
x, n, _ := decodeUint(b[1:])
|
||||
if 1+n+int(x) == len(b) {
|
||||
return 1 + n
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *Encoder) flushTo(dst *Encoder) {
|
||||
data := e.buf
|
||||
p := stripPrefix(data)
|
||||
if p > 0 {
|
||||
data = data[1:]
|
||||
} else {
|
||||
// Prefix the size.
|
||||
dst.EncodeUint(uint64(len(data)))
|
||||
}
|
||||
dst.buf = append(dst.buf, data...)
|
||||
}
|
||||
|
||||
func (e *Encoder) addVar(key string, m Message) error {
|
||||
for _, v := range e.parent.vars {
|
||||
if v.key == key {
|
||||
err := fmt.Errorf("catmsg: duplicate variable %q", key)
|
||||
e.setError(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
scope := e.parent
|
||||
// If a variable message is Incomplete, and does not evaluate to a message
|
||||
// during execution, we fall back to the variable name. We encode this by
|
||||
// appending the variable name if the message reports it's incomplete.
|
||||
|
||||
err := m.Compile(e)
|
||||
if err != ErrIncomplete {
|
||||
e.setError(err)
|
||||
}
|
||||
switch {
|
||||
case len(e.buf) == 1 && Handle(e.buf[0]) == msgFirst: // empty sequence
|
||||
e.buf = e.buf[:0]
|
||||
e.inBody = false
|
||||
fallthrough
|
||||
case len(e.buf) == 0:
|
||||
// Empty message.
|
||||
if err := String(key).Compile(e); err != nil {
|
||||
e.setError(err)
|
||||
}
|
||||
case err == ErrIncomplete:
|
||||
if Handle(e.buf[0]) != msgFirst {
|
||||
seq := &Encoder{root: e.root, parent: e}
|
||||
seq.EncodeMessageType(msgFirst)
|
||||
e.flushTo(seq)
|
||||
e = seq
|
||||
}
|
||||
// e contains a sequence; append the fallback string.
|
||||
e.EncodeMessage(String(key))
|
||||
}
|
||||
|
||||
// Flush result to variable heap.
|
||||
offset := len(e.root.buf)
|
||||
e.flushTo(e.root)
|
||||
e.buf = e.buf[:0]
|
||||
|
||||
// Record variable offset in current scope.
|
||||
scope.vars = append(scope.vars, keyVal{key: key, offset: offset})
|
||||
return err
|
||||
}
|
||||
|
||||
const (
|
||||
substituteVar = iota
|
||||
substituteMacro
|
||||
substituteError
|
||||
)
|
||||
|
||||
// EncodeSubstitution inserts a resolved reference to a variable or macro.
|
||||
//
|
||||
// This call must be matched with a call to ExecuteSubstitution at decoding
|
||||
// time.
|
||||
func (e *Encoder) EncodeSubstitution(name string, arguments ...int) {
|
||||
if arity := len(arguments); arity > 0 {
|
||||
// TODO: also resolve macros.
|
||||
e.EncodeUint(substituteMacro)
|
||||
e.EncodeString(name)
|
||||
for _, a := range arguments {
|
||||
e.EncodeUint(uint64(a))
|
||||
}
|
||||
return
|
||||
}
|
||||
for scope := e; scope != nil; scope = scope.parent {
|
||||
for _, v := range scope.vars {
|
||||
if v.key != name {
|
||||
continue
|
||||
}
|
||||
e.EncodeUint(substituteVar) // TODO: support arity > 0
|
||||
e.EncodeUint(uint64(v.offset))
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO: refer to dictionary-wide scoped variables.
|
||||
e.EncodeUint(substituteError)
|
||||
e.EncodeString(name)
|
||||
e.setError(fmt.Errorf("catmsg: unknown var %q", name))
|
||||
}
|
||||
|
||||
// A Decoder deserializes and evaluates messages that are encoded by an encoder.
|
||||
type Decoder struct {
|
||||
tag language.Tag
|
||||
dst Renderer
|
||||
macros Dictionary
|
||||
|
||||
err error
|
||||
vars string
|
||||
data string
|
||||
|
||||
macroArg int // TODO: allow more than one argument
|
||||
}
|
||||
|
||||
// NewDecoder returns a new Decoder.
|
||||
//
|
||||
// Decoders are designed to be reused for multiple invocations of Execute.
|
||||
// Only one goroutine may call Execute concurrently.
|
||||
func NewDecoder(tag language.Tag, r Renderer, macros Dictionary) *Decoder {
|
||||
return &Decoder{
|
||||
tag: tag,
|
||||
dst: r,
|
||||
macros: macros,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) setError(err error) {
|
||||
if d.err == nil {
|
||||
d.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// Language returns the language in which the message is being rendered.
|
||||
//
|
||||
// The destination language may be a child language of the language used for
|
||||
// encoding. For instance, a decoding language of "pt-PT"" is consistent with an
|
||||
// encoding language of "pt".
|
||||
func (d *Decoder) Language() language.Tag { return d.tag }
|
||||
|
||||
// Done reports whether there are more bytes to process in this message.
|
||||
func (d *Decoder) Done() bool { return len(d.data) == 0 }
|
||||
|
||||
// Render implements Renderer.
|
||||
func (d *Decoder) Render(s string) { d.dst.Render(s) }
|
||||
|
||||
// Arg implements Renderer.
|
||||
//
|
||||
// During evaluation of macros, the argument positions may be mapped to
|
||||
// arguments that differ from the original call.
|
||||
func (d *Decoder) Arg(i int) interface{} {
|
||||
if d.macroArg != 0 {
|
||||
if i != 1 {
|
||||
panic("catmsg: only macros with single argument supported")
|
||||
}
|
||||
i = d.macroArg
|
||||
}
|
||||
return d.dst.Arg(i)
|
||||
}
|
||||
|
||||
// DecodeUint decodes a number that was encoded with EncodeUint and advances the
|
||||
// position.
|
||||
func (d *Decoder) DecodeUint() uint64 {
|
||||
x, n, err := decodeUintString(d.data)
|
||||
d.data = d.data[n:]
|
||||
if err != nil {
|
||||
d.setError(err)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// DecodeString decodes a string that was encoded with EncodeString and advances
|
||||
// the position.
|
||||
func (d *Decoder) DecodeString() string {
|
||||
size := d.DecodeUint()
|
||||
s := d.data[:size]
|
||||
d.data = d.data[size:]
|
||||
return s
|
||||
}
|
||||
|
||||
// SkipMessage skips the message at the current location and advances the
|
||||
// position.
|
||||
func (d *Decoder) SkipMessage() {
|
||||
n := int(d.DecodeUint())
|
||||
d.data = d.data[n:]
|
||||
}
|
||||
|
||||
// Execute decodes and evaluates msg.
|
||||
//
|
||||
// Only one goroutine may call execute.
|
||||
func (d *Decoder) Execute(msg string) error {
|
||||
d.err = nil
|
||||
if !d.execute(msg) {
|
||||
return ErrNoMatch
|
||||
}
|
||||
return d.err
|
||||
}
|
||||
|
||||
func (d *Decoder) execute(msg string) bool {
|
||||
saved := d.data
|
||||
d.data = msg
|
||||
ok := d.executeMessage()
|
||||
d.data = saved
|
||||
return ok
|
||||
}
|
||||
|
||||
// executeMessageFromData is like execute, but also decodes a leading message
|
||||
// size and clips the given string accordingly.
|
||||
//
|
||||
// It reports the number of bytes consumed and whether a message was selected.
|
||||
func (d *Decoder) executeMessageFromData(s string) (n int, ok bool) {
|
||||
saved := d.data
|
||||
d.data = s
|
||||
size := int(d.DecodeUint())
|
||||
n = len(s) - len(d.data)
|
||||
// Sanitize the setting. This allows skipping a size argument for
|
||||
// RawString and method Done.
|
||||
d.data = d.data[:size]
|
||||
ok = d.executeMessage()
|
||||
n += size - len(d.data)
|
||||
d.data = saved
|
||||
return n, ok
|
||||
}
|
||||
|
||||
var errUnknownHandler = errors.New("catmsg: string contains unsupported handler")
|
||||
|
||||
// executeMessage reads the handle id, initializes the decoder and executes the
|
||||
// message. It is assumed that all of d.data[d.p:] is the single message.
|
||||
func (d *Decoder) executeMessage() bool {
|
||||
if d.Done() {
|
||||
// We interpret no data as a valid empty message.
|
||||
return true
|
||||
}
|
||||
handle := d.DecodeUint()
|
||||
|
||||
var fn Handler
|
||||
mutex.Lock()
|
||||
if int(handle) < len(handlers) {
|
||||
fn = handlers[handle]
|
||||
}
|
||||
mutex.Unlock()
|
||||
if fn == nil {
|
||||
d.setError(errUnknownHandler)
|
||||
d.execute(fmt.Sprintf("\x02$!(UNKNOWNMSGHANDLER=%#x)", handle))
|
||||
return true
|
||||
}
|
||||
return fn(d)
|
||||
}
|
||||
|
||||
// ExecuteMessage decodes and executes the message at the current position.
|
||||
func (d *Decoder) ExecuteMessage() bool {
|
||||
n, ok := d.executeMessageFromData(d.data)
|
||||
d.data = d.data[n:]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ExecuteSubstitution executes the message corresponding to the substitution
|
||||
// as encoded by EncodeSubstitution.
|
||||
func (d *Decoder) ExecuteSubstitution() {
|
||||
switch x := d.DecodeUint(); x {
|
||||
case substituteVar:
|
||||
offset := d.DecodeUint()
|
||||
d.executeMessageFromData(d.vars[offset:])
|
||||
case substituteMacro:
|
||||
name := d.DecodeString()
|
||||
data, ok := d.macros.Lookup(name)
|
||||
old := d.macroArg
|
||||
// TODO: support macros of arity other than 1.
|
||||
d.macroArg = int(d.DecodeUint())
|
||||
switch {
|
||||
case !ok:
|
||||
// TODO: detect this at creation time.
|
||||
d.setError(fmt.Errorf("catmsg: undefined macro %q", name))
|
||||
fallthrough
|
||||
case !d.execute(data):
|
||||
d.dst.Render(name) // fall back to macro name.
|
||||
}
|
||||
d.macroArg = old
|
||||
case substituteError:
|
||||
d.dst.Render(d.DecodeString())
|
||||
default:
|
||||
panic("catmsg: unreachable")
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package catmsg
|
||||
|
||||
// This file implements varint encoding analogous to the one in encoding/binary.
|
||||
// We need a string version of this function, so we add that here and then add
|
||||
// the rest for consistency.
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
errIllegalVarint = errors.New("catmsg: illegal varint")
|
||||
errVarintTooLarge = errors.New("catmsg: varint too large for uint64")
|
||||
)
|
||||
|
||||
const maxVarintBytes = 10 // maximum length of a varint
|
||||
|
||||
// encodeUint encodes x as a variable-sized integer into buf and returns the
|
||||
// number of bytes written. buf must be at least maxVarintBytes long
|
||||
func encodeUint(buf []byte, x uint64) (n int) {
|
||||
for ; x > 127; n++ {
|
||||
buf[n] = 0x80 | uint8(x&0x7F)
|
||||
x >>= 7
|
||||
}
|
||||
buf[n] = uint8(x)
|
||||
n++
|
||||
return n
|
||||
}
|
||||
|
||||
func decodeUintString(s string) (x uint64, size int, err error) {
|
||||
i := 0
|
||||
for shift := uint(0); shift < 64; shift += 7 {
|
||||
if i >= len(s) {
|
||||
return 0, i, errIllegalVarint
|
||||
}
|
||||
b := uint64(s[i])
|
||||
i++
|
||||
x |= (b & 0x7F) << shift
|
||||
if b&0x80 == 0 {
|
||||
return x, i, nil
|
||||
}
|
||||
}
|
||||
return 0, i, errVarintTooLarge
|
||||
}
|
||||
|
||||
func decodeUint(b []byte) (x uint64, size int, err error) {
|
||||
i := 0
|
||||
for shift := uint(0); shift < 64; shift += 7 {
|
||||
if i >= len(b) {
|
||||
return 0, i, errIllegalVarint
|
||||
}
|
||||
c := uint64(b[i])
|
||||
i++
|
||||
x |= (c & 0x7F) << shift
|
||||
if c&0x80 == 0 {
|
||||
return x, i, nil
|
||||
}
|
||||
}
|
||||
return 0, i, errVarintTooLarge
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package format contains types for defining language-specific formatting of
|
||||
// values.
|
||||
//
|
||||
// This package is internal now, but will eventually be exposed after the API
|
||||
// settles.
|
||||
package format // import "golang.org/x/text/internal/format"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// State represents the printer state passed to custom formatters. It provides
|
||||
// access to the fmt.State interface and the sentence and language-related
|
||||
// context.
|
||||
type State interface {
|
||||
fmt.State
|
||||
|
||||
// Language reports the requested language in which to render a message.
|
||||
Language() language.Tag
|
||||
|
||||
// TODO: consider this and removing rune from the Format method in the
|
||||
// Formatter interface.
|
||||
//
|
||||
// Verb returns the format variant to render, analogous to the types used
|
||||
// in fmt. Use 'v' for the default or only variant.
|
||||
// Verb() rune
|
||||
|
||||
// TODO: more info:
|
||||
// - sentence context such as linguistic features passed by the translator.
|
||||
}
|
||||
|
||||
// Formatter is analogous to fmt.Formatter.
|
||||
type Formatter interface {
|
||||
Format(state State, verb rune)
|
||||
}
|
||||
+358
@@ -0,0 +1,358 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package format
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// A Parser parses a format string. The result from the parse are set in the
|
||||
// struct fields.
|
||||
type Parser struct {
|
||||
Verb rune
|
||||
|
||||
WidthPresent bool
|
||||
PrecPresent bool
|
||||
Minus bool
|
||||
Plus bool
|
||||
Sharp bool
|
||||
Space bool
|
||||
Zero bool
|
||||
|
||||
// For the formats %+v %#v, we set the plusV/sharpV flags
|
||||
// and clear the plus/sharp flags since %+v and %#v are in effect
|
||||
// different, flagless formats set at the top level.
|
||||
PlusV bool
|
||||
SharpV bool
|
||||
|
||||
HasIndex bool
|
||||
|
||||
Width int
|
||||
Prec int // precision
|
||||
|
||||
// retain arguments across calls.
|
||||
Args []interface{}
|
||||
// retain current argument number across calls
|
||||
ArgNum int
|
||||
|
||||
// reordered records whether the format string used argument reordering.
|
||||
Reordered bool
|
||||
// goodArgNum records whether the most recent reordering directive was valid.
|
||||
goodArgNum bool
|
||||
|
||||
// position info
|
||||
format string
|
||||
startPos int
|
||||
endPos int
|
||||
Status Status
|
||||
}
|
||||
|
||||
// Reset initializes a parser to scan format strings for the given args.
|
||||
func (p *Parser) Reset(args []interface{}) {
|
||||
p.Args = args
|
||||
p.ArgNum = 0
|
||||
p.startPos = 0
|
||||
p.Reordered = false
|
||||
}
|
||||
|
||||
// Text returns the part of the format string that was parsed by the last call
|
||||
// to Scan. It returns the original substitution clause if the current scan
|
||||
// parsed a substitution.
|
||||
func (p *Parser) Text() string { return p.format[p.startPos:p.endPos] }
|
||||
|
||||
// SetFormat sets a new format string to parse. It does not reset the argument
|
||||
// count.
|
||||
func (p *Parser) SetFormat(format string) {
|
||||
p.format = format
|
||||
p.startPos = 0
|
||||
p.endPos = 0
|
||||
}
|
||||
|
||||
// Status indicates the result type of a call to Scan.
|
||||
type Status int
|
||||
|
||||
const (
|
||||
StatusText Status = iota
|
||||
StatusSubstitution
|
||||
StatusBadWidthSubstitution
|
||||
StatusBadPrecSubstitution
|
||||
StatusNoVerb
|
||||
StatusBadArgNum
|
||||
StatusMissingArg
|
||||
)
|
||||
|
||||
// ClearFlags reset the parser to default behavior.
|
||||
func (p *Parser) ClearFlags() {
|
||||
p.WidthPresent = false
|
||||
p.PrecPresent = false
|
||||
p.Minus = false
|
||||
p.Plus = false
|
||||
p.Sharp = false
|
||||
p.Space = false
|
||||
p.Zero = false
|
||||
|
||||
p.PlusV = false
|
||||
p.SharpV = false
|
||||
|
||||
p.HasIndex = false
|
||||
}
|
||||
|
||||
// Scan scans the next part of the format string and sets the status to
|
||||
// indicate whether it scanned a string literal, substitution or error.
|
||||
func (p *Parser) Scan() bool {
|
||||
p.Status = StatusText
|
||||
format := p.format
|
||||
end := len(format)
|
||||
if p.endPos >= end {
|
||||
return false
|
||||
}
|
||||
afterIndex := false // previous item in format was an index like [3].
|
||||
|
||||
p.startPos = p.endPos
|
||||
p.goodArgNum = true
|
||||
i := p.startPos
|
||||
for i < end && format[i] != '%' {
|
||||
i++
|
||||
}
|
||||
if i > p.startPos {
|
||||
p.endPos = i
|
||||
return true
|
||||
}
|
||||
// Process one verb
|
||||
i++
|
||||
|
||||
p.Status = StatusSubstitution
|
||||
|
||||
// Do we have flags?
|
||||
p.ClearFlags()
|
||||
|
||||
simpleFormat:
|
||||
for ; i < end; i++ {
|
||||
c := p.format[i]
|
||||
switch c {
|
||||
case '#':
|
||||
p.Sharp = true
|
||||
case '0':
|
||||
p.Zero = !p.Minus // Only allow zero padding to the left.
|
||||
case '+':
|
||||
p.Plus = true
|
||||
case '-':
|
||||
p.Minus = true
|
||||
p.Zero = false // Do not pad with zeros to the right.
|
||||
case ' ':
|
||||
p.Space = true
|
||||
default:
|
||||
// Fast path for common case of ascii lower case simple verbs
|
||||
// without precision or width or argument indices.
|
||||
if 'a' <= c && c <= 'z' && p.ArgNum < len(p.Args) {
|
||||
if c == 'v' {
|
||||
// Go syntax
|
||||
p.SharpV = p.Sharp
|
||||
p.Sharp = false
|
||||
// Struct-field syntax
|
||||
p.PlusV = p.Plus
|
||||
p.Plus = false
|
||||
}
|
||||
p.Verb = rune(c)
|
||||
p.ArgNum++
|
||||
p.endPos = i + 1
|
||||
return true
|
||||
}
|
||||
// Format is more complex than simple flags and a verb or is malformed.
|
||||
break simpleFormat
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have an explicit argument index?
|
||||
i, afterIndex = p.updateArgNumber(format, i)
|
||||
|
||||
// Do we have width?
|
||||
if i < end && format[i] == '*' {
|
||||
i++
|
||||
p.Width, p.WidthPresent = p.intFromArg()
|
||||
|
||||
if !p.WidthPresent {
|
||||
p.Status = StatusBadWidthSubstitution
|
||||
}
|
||||
|
||||
// We have a negative width, so take its value and ensure
|
||||
// that the minus flag is set
|
||||
if p.Width < 0 {
|
||||
p.Width = -p.Width
|
||||
p.Minus = true
|
||||
p.Zero = false // Do not pad with zeros to the right.
|
||||
}
|
||||
afterIndex = false
|
||||
} else {
|
||||
p.Width, p.WidthPresent, i = parsenum(format, i, end)
|
||||
if afterIndex && p.WidthPresent { // "%[3]2d"
|
||||
p.goodArgNum = false
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have precision?
|
||||
if i+1 < end && format[i] == '.' {
|
||||
i++
|
||||
if afterIndex { // "%[3].2d"
|
||||
p.goodArgNum = false
|
||||
}
|
||||
i, afterIndex = p.updateArgNumber(format, i)
|
||||
if i < end && format[i] == '*' {
|
||||
i++
|
||||
p.Prec, p.PrecPresent = p.intFromArg()
|
||||
// Negative precision arguments don't make sense
|
||||
if p.Prec < 0 {
|
||||
p.Prec = 0
|
||||
p.PrecPresent = false
|
||||
}
|
||||
if !p.PrecPresent {
|
||||
p.Status = StatusBadPrecSubstitution
|
||||
}
|
||||
afterIndex = false
|
||||
} else {
|
||||
p.Prec, p.PrecPresent, i = parsenum(format, i, end)
|
||||
if !p.PrecPresent {
|
||||
p.Prec = 0
|
||||
p.PrecPresent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !afterIndex {
|
||||
i, afterIndex = p.updateArgNumber(format, i)
|
||||
}
|
||||
p.HasIndex = afterIndex
|
||||
|
||||
if i >= end {
|
||||
p.endPos = i
|
||||
p.Status = StatusNoVerb
|
||||
return true
|
||||
}
|
||||
|
||||
verb, w := utf8.DecodeRuneInString(format[i:])
|
||||
p.endPos = i + w
|
||||
p.Verb = verb
|
||||
|
||||
switch {
|
||||
case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec.
|
||||
p.startPos = p.endPos - 1
|
||||
p.Status = StatusText
|
||||
case !p.goodArgNum:
|
||||
p.Status = StatusBadArgNum
|
||||
case p.ArgNum >= len(p.Args): // No argument left over to print for the current verb.
|
||||
p.Status = StatusMissingArg
|
||||
p.ArgNum++
|
||||
case verb == 'v':
|
||||
// Go syntax
|
||||
p.SharpV = p.Sharp
|
||||
p.Sharp = false
|
||||
// Struct-field syntax
|
||||
p.PlusV = p.Plus
|
||||
p.Plus = false
|
||||
fallthrough
|
||||
default:
|
||||
p.ArgNum++
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// intFromArg gets the ArgNumth element of Args. On return, isInt reports
|
||||
// whether the argument has integer type.
|
||||
func (p *Parser) intFromArg() (num int, isInt bool) {
|
||||
if p.ArgNum < len(p.Args) {
|
||||
arg := p.Args[p.ArgNum]
|
||||
num, isInt = arg.(int) // Almost always OK.
|
||||
if !isInt {
|
||||
// Work harder.
|
||||
switch v := reflect.ValueOf(arg); v.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n := v.Int()
|
||||
if int64(int(n)) == n {
|
||||
num = int(n)
|
||||
isInt = true
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n := v.Uint()
|
||||
if int64(n) >= 0 && uint64(int(n)) == n {
|
||||
num = int(n)
|
||||
isInt = true
|
||||
}
|
||||
default:
|
||||
// Already 0, false.
|
||||
}
|
||||
}
|
||||
p.ArgNum++
|
||||
if tooLarge(num) {
|
||||
num = 0
|
||||
isInt = false
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// parseArgNumber returns the value of the bracketed number, minus 1
|
||||
// (explicit argument numbers are one-indexed but we want zero-indexed).
|
||||
// The opening bracket is known to be present at format[0].
|
||||
// The returned values are the index, the number of bytes to consume
|
||||
// up to the closing paren, if present, and whether the number parsed
|
||||
// ok. The bytes to consume will be 1 if no closing paren is present.
|
||||
func parseArgNumber(format string) (index int, wid int, ok bool) {
|
||||
// There must be at least 3 bytes: [n].
|
||||
if len(format) < 3 {
|
||||
return 0, 1, false
|
||||
}
|
||||
|
||||
// Find closing bracket.
|
||||
for i := 1; i < len(format); i++ {
|
||||
if format[i] == ']' {
|
||||
width, ok, newi := parsenum(format, 1, i)
|
||||
if !ok || newi != i {
|
||||
return 0, i + 1, false
|
||||
}
|
||||
return width - 1, i + 1, true // arg numbers are one-indexed and skip paren.
|
||||
}
|
||||
}
|
||||
return 0, 1, false
|
||||
}
|
||||
|
||||
// updateArgNumber returns the next argument to evaluate, which is either the value of the passed-in
|
||||
// argNum or the value of the bracketed integer that begins format[i:]. It also returns
|
||||
// the new value of i, that is, the index of the next byte of the format to process.
|
||||
func (p *Parser) updateArgNumber(format string, i int) (newi int, found bool) {
|
||||
if len(format) <= i || format[i] != '[' {
|
||||
return i, false
|
||||
}
|
||||
p.Reordered = true
|
||||
index, wid, ok := parseArgNumber(format[i:])
|
||||
if ok && 0 <= index && index < len(p.Args) {
|
||||
p.ArgNum = index
|
||||
return i + wid, true
|
||||
}
|
||||
p.goodArgNum = false
|
||||
return i + wid, ok
|
||||
}
|
||||
|
||||
// tooLarge reports whether the magnitude of the integer is
|
||||
// too large to be used as a formatting width or precision.
|
||||
func tooLarge(x int) bool {
|
||||
const max int = 1e6
|
||||
return x > max || x < -max
|
||||
}
|
||||
|
||||
// parsenum converts ASCII to integer. num is 0 (and isnum is false) if no number present.
|
||||
func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
|
||||
if start >= end {
|
||||
return 0, false, end
|
||||
}
|
||||
for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
|
||||
if tooLarge(num) {
|
||||
return 0, false, end // Overflow; crazy long number most likely.
|
||||
}
|
||||
num = num*10 + int(s[newi]-'0')
|
||||
isnum = true
|
||||
}
|
||||
return
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package internal contains non-exported functionality that are used by
|
||||
// packages in the text repository.
|
||||
package internal // import "golang.org/x/text/internal"
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// SortTags sorts tags in place.
|
||||
func SortTags(tags []language.Tag) {
|
||||
sort.Sort(sorter(tags))
|
||||
}
|
||||
|
||||
type sorter []language.Tag
|
||||
|
||||
func (s sorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s sorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s sorter) Less(i, j int) bool {
|
||||
return s[i].String() < s[j].String()
|
||||
}
|
||||
|
||||
// UniqueTags sorts and filters duplicate tags in place and returns a slice with
|
||||
// only unique tags.
|
||||
func UniqueTags(tags []language.Tag) []language.Tag {
|
||||
if len(tags) <= 1 {
|
||||
return tags
|
||||
}
|
||||
SortTags(tags)
|
||||
k := 0
|
||||
for i := 1; i < len(tags); i++ {
|
||||
if tags[k].String() < tags[i].String() {
|
||||
k++
|
||||
tags[k] = tags[i]
|
||||
}
|
||||
}
|
||||
return tags[:k+1]
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
package language
|
||||
|
||||
// This file contains code common to the maketables.go and the package code.
|
||||
|
||||
// AliasType is the type of an alias in AliasMap.
|
||||
type AliasType int8
|
||||
|
||||
const (
|
||||
Deprecated AliasType = iota
|
||||
Macro
|
||||
Legacy
|
||||
|
||||
AliasTypeUnknown AliasType = -1
|
||||
)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package language
|
||||
|
||||
// CompactCoreInfo is a compact integer with the three core tags encoded.
|
||||
type CompactCoreInfo uint32
|
||||
|
||||
// GetCompactCore generates a uint32 value that is guaranteed to be unique for
|
||||
// different language, region, and script values.
|
||||
func GetCompactCore(t Tag) (cci CompactCoreInfo, ok bool) {
|
||||
if t.LangID > langNoIndexOffset {
|
||||
return 0, false
|
||||
}
|
||||
cci |= CompactCoreInfo(t.LangID) << (8 + 12)
|
||||
cci |= CompactCoreInfo(t.ScriptID) << 12
|
||||
cci |= CompactCoreInfo(t.RegionID)
|
||||
return cci, true
|
||||
}
|
||||
|
||||
// Tag generates a tag from c.
|
||||
func (c CompactCoreInfo) Tag() Tag {
|
||||
return Tag{
|
||||
LangID: Language(c >> 20),
|
||||
RegionID: Region(c & 0x3ff),
|
||||
ScriptID: Script(c>>12) & 0xff,
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package compact defines a compact representation of language tags.
|
||||
//
|
||||
// Common language tags (at least all for which locale information is defined
|
||||
// in CLDR) are assigned a unique index. Each Tag is associated with such an
|
||||
// ID for selecting language-related resources (such as translations) as well
|
||||
// as one for selecting regional defaults (currency, number formatting, etc.)
|
||||
//
|
||||
// It may want to export this functionality at some point, but at this point
|
||||
// this is only available for use within x/text.
|
||||
package compact // import "golang.org/x/text/internal/language/compact"
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/internal/language"
|
||||
)
|
||||
|
||||
// ID is an integer identifying a single tag.
|
||||
type ID uint16
|
||||
|
||||
func getCoreIndex(t language.Tag) (id ID, ok bool) {
|
||||
cci, ok := language.GetCompactCore(t)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
i := sort.Search(len(coreTags), func(i int) bool {
|
||||
return cci <= coreTags[i]
|
||||
})
|
||||
if i == len(coreTags) || coreTags[i] != cci {
|
||||
return 0, false
|
||||
}
|
||||
return ID(i), true
|
||||
}
|
||||
|
||||
// Parent returns the ID of the parent or the root ID if id is already the root.
|
||||
func (id ID) Parent() ID {
|
||||
return parents[id]
|
||||
}
|
||||
|
||||
// Tag converts id to an internal language Tag.
|
||||
func (id ID) Tag() language.Tag {
|
||||
if int(id) >= len(coreTags) {
|
||||
return specialTags[int(id)-len(coreTags)]
|
||||
}
|
||||
return coreTags[id].Tag()
|
||||
}
|
||||
|
||||
var specialTags []language.Tag
|
||||
|
||||
func init() {
|
||||
tags := strings.Split(specialTagsStr, " ")
|
||||
specialTags = make([]language.Tag, len(tags))
|
||||
for i, t := range tags {
|
||||
specialTags[i] = language.MustParse(t)
|
||||
}
|
||||
}
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen.go gen_index.go -output tables.go
|
||||
//go:generate go run gen_parents.go
|
||||
|
||||
package compact
|
||||
|
||||
// TODO: Remove above NOTE after:
|
||||
// - verifying that tables are dropped correctly (most notably matcher tables).
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/internal/language"
|
||||
)
|
||||
|
||||
// Tag represents a BCP 47 language tag. It is used to specify an instance of a
|
||||
// specific language or locale. All language tag values are guaranteed to be
|
||||
// well-formed.
|
||||
type Tag struct {
|
||||
// NOTE: exported tags will become part of the public API.
|
||||
language ID
|
||||
locale ID
|
||||
full fullTag // always a language.Tag for now.
|
||||
}
|
||||
|
||||
const _und = 0
|
||||
|
||||
type fullTag interface {
|
||||
IsRoot() bool
|
||||
Parent() language.Tag
|
||||
}
|
||||
|
||||
// Make a compact Tag from a fully specified internal language Tag.
|
||||
func Make(t language.Tag) (tag Tag) {
|
||||
if region := t.TypeForKey("rg"); len(region) == 6 && region[2:] == "zzzz" {
|
||||
if r, err := language.ParseRegion(region[:2]); err == nil {
|
||||
tFull := t
|
||||
t, _ = t.SetTypeForKey("rg", "")
|
||||
// TODO: should we not consider "va" for the language tag?
|
||||
var exact1, exact2 bool
|
||||
tag.language, exact1 = FromTag(t)
|
||||
t.RegionID = r
|
||||
tag.locale, exact2 = FromTag(t)
|
||||
if !exact1 || !exact2 {
|
||||
tag.full = tFull
|
||||
}
|
||||
return tag
|
||||
}
|
||||
}
|
||||
lang, ok := FromTag(t)
|
||||
tag.language = lang
|
||||
tag.locale = lang
|
||||
if !ok {
|
||||
tag.full = t
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
// Tag returns an internal language Tag version of this tag.
|
||||
func (t Tag) Tag() language.Tag {
|
||||
if t.full != nil {
|
||||
return t.full.(language.Tag)
|
||||
}
|
||||
tag := t.language.Tag()
|
||||
if t.language != t.locale {
|
||||
loc := t.locale.Tag()
|
||||
tag, _ = tag.SetTypeForKey("rg", strings.ToLower(loc.RegionID.String())+"zzzz")
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
// IsCompact reports whether this tag is fully defined in terms of ID.
|
||||
func (t *Tag) IsCompact() bool {
|
||||
return t.full == nil
|
||||
}
|
||||
|
||||
// MayHaveVariants reports whether a tag may have variants. If it returns false
|
||||
// it is guaranteed the tag does not have variants.
|
||||
func (t Tag) MayHaveVariants() bool {
|
||||
return t.full != nil || int(t.language) >= len(coreTags)
|
||||
}
|
||||
|
||||
// MayHaveExtensions reports whether a tag may have extensions. If it returns
|
||||
// false it is guaranteed the tag does not have them.
|
||||
func (t Tag) MayHaveExtensions() bool {
|
||||
return t.full != nil ||
|
||||
int(t.language) >= len(coreTags) ||
|
||||
t.language != t.locale
|
||||
}
|
||||
|
||||
// IsRoot returns true if t is equal to language "und".
|
||||
func (t Tag) IsRoot() bool {
|
||||
if t.full != nil {
|
||||
return t.full.IsRoot()
|
||||
}
|
||||
return t.language == _und
|
||||
}
|
||||
|
||||
// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
|
||||
// specific language are substituted with fields from the parent language.
|
||||
// The parent for a language may change for newer versions of CLDR.
|
||||
func (t Tag) Parent() Tag {
|
||||
if t.full != nil {
|
||||
return Make(t.full.Parent())
|
||||
}
|
||||
if t.language != t.locale {
|
||||
// Simulate stripping -u-rg-xxxxxx
|
||||
return Tag{language: t.language, locale: t.language}
|
||||
}
|
||||
// TODO: use parent lookup table once cycle from internal package is
|
||||
// removed. Probably by internalizing the table and declaring this fast
|
||||
// enough.
|
||||
// lang := compactID(internal.Parent(uint16(t.language)))
|
||||
lang, _ := FromTag(t.language.Tag().Parent())
|
||||
return Tag{language: lang, locale: lang}
|
||||
}
|
||||
|
||||
// returns token t and the rest of the string.
|
||||
func nextToken(s string) (t, tail string) {
|
||||
p := strings.Index(s[1:], "-")
|
||||
if p == -1 {
|
||||
return s[1:], ""
|
||||
}
|
||||
p++
|
||||
return s[1:p], s[p:]
|
||||
}
|
||||
|
||||
// LanguageID returns an index, where 0 <= index < NumCompactTags, for tags
|
||||
// for which data exists in the text repository.The index will change over time
|
||||
// and should not be stored in persistent storage. If t does not match a compact
|
||||
// index, exact will be false and the compact index will be returned for the
|
||||
// first match after repeatedly taking the Parent of t.
|
||||
func LanguageID(t Tag) (id ID, exact bool) {
|
||||
return t.language, t.full == nil
|
||||
}
|
||||
|
||||
// RegionalID returns the ID for the regional variant of this tag. This index is
|
||||
// used to indicate region-specific overrides, such as default currency, default
|
||||
// calendar and week data, default time cycle, and default measurement system
|
||||
// and unit preferences.
|
||||
//
|
||||
// For instance, the tag en-GB-u-rg-uszzzz specifies British English with US
|
||||
// settings for currency, number formatting, etc. The CompactIndex for this tag
|
||||
// will be that for en-GB, while the RegionalID will be the one corresponding to
|
||||
// en-US.
|
||||
func RegionalID(t Tag) (id ID, exact bool) {
|
||||
return t.locale, t.full == nil
|
||||
}
|
||||
|
||||
// LanguageTag returns t stripped of regional variant indicators.
|
||||
//
|
||||
// At the moment this means it is stripped of a regional and variant subtag "rg"
|
||||
// and "va" in the "u" extension.
|
||||
func (t Tag) LanguageTag() Tag {
|
||||
if t.full == nil {
|
||||
return Tag{language: t.language, locale: t.language}
|
||||
}
|
||||
tt := t.Tag()
|
||||
tt.SetTypeForKey("rg", "")
|
||||
tt.SetTypeForKey("va", "")
|
||||
return Make(tt)
|
||||
}
|
||||
|
||||
// RegionalTag returns the regional variant of the tag.
|
||||
//
|
||||
// At the moment this means that the region is set from the regional subtag
|
||||
// "rg" in the "u" extension.
|
||||
func (t Tag) RegionalTag() Tag {
|
||||
rt := Tag{language: t.locale, locale: t.locale}
|
||||
if t.full == nil {
|
||||
return rt
|
||||
}
|
||||
b := language.Builder{}
|
||||
tag := t.Tag()
|
||||
// tag, _ = tag.SetTypeForKey("rg", "")
|
||||
b.SetTag(t.locale.Tag())
|
||||
if v := tag.Variants(); v != "" {
|
||||
for _, v := range strings.Split(v, "-") {
|
||||
b.AddVariant(v)
|
||||
}
|
||||
}
|
||||
for _, e := range tag.Extensions() {
|
||||
b.AddExt(e)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// FromTag reports closest matching ID for an internal language Tag.
|
||||
func FromTag(t language.Tag) (id ID, exact bool) {
|
||||
// TODO: perhaps give more frequent tags a lower index.
|
||||
// TODO: we could make the indexes stable. This will excluded some
|
||||
// possibilities for optimization, so don't do this quite yet.
|
||||
exact = true
|
||||
|
||||
b, s, r := t.Raw()
|
||||
if t.HasString() {
|
||||
if t.IsPrivateUse() {
|
||||
// We have no entries for user-defined tags.
|
||||
return 0, false
|
||||
}
|
||||
hasExtra := false
|
||||
if t.HasVariants() {
|
||||
if t.HasExtensions() {
|
||||
build := language.Builder{}
|
||||
build.SetTag(language.Tag{LangID: b, ScriptID: s, RegionID: r})
|
||||
build.AddVariant(t.Variants())
|
||||
exact = false
|
||||
t = build.Make()
|
||||
}
|
||||
hasExtra = true
|
||||
} else if _, ok := t.Extension('u'); ok {
|
||||
// TODO: va may mean something else. Consider not considering it.
|
||||
// Strip all but the 'va' entry.
|
||||
old := t
|
||||
variant := t.TypeForKey("va")
|
||||
t = language.Tag{LangID: b, ScriptID: s, RegionID: r}
|
||||
if variant != "" {
|
||||
t, _ = t.SetTypeForKey("va", variant)
|
||||
hasExtra = true
|
||||
}
|
||||
exact = old == t
|
||||
} else {
|
||||
exact = false
|
||||
}
|
||||
if hasExtra {
|
||||
// We have some variants.
|
||||
for i, s := range specialTags {
|
||||
if s == t {
|
||||
return ID(i + len(coreTags)), exact
|
||||
}
|
||||
}
|
||||
exact = false
|
||||
}
|
||||
}
|
||||
if x, ok := getCoreIndex(t); ok {
|
||||
return x, exact
|
||||
}
|
||||
exact = false
|
||||
if r != 0 && s == 0 {
|
||||
// Deal with cases where an extra script is inserted for the region.
|
||||
t, _ := t.Maximize()
|
||||
if x, ok := getCoreIndex(t); ok {
|
||||
return x, exact
|
||||
}
|
||||
}
|
||||
for t = t.Parent(); t != root; t = t.Parent() {
|
||||
// No variants specified: just compare core components.
|
||||
// The key has the form lllssrrr, where l, s, and r are nibbles for
|
||||
// respectively the langID, scriptID, and regionID.
|
||||
if x, ok := getCoreIndex(t); ok {
|
||||
return x, exact
|
||||
}
|
||||
}
|
||||
return 0, exact
|
||||
}
|
||||
|
||||
var root = language.Tag{}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
package compact
|
||||
|
||||
// parents maps a compact index of a tag to the compact index of the parent of
|
||||
// this tag.
|
||||
var parents = []ID{ // 775 elements
|
||||
// Entry 0 - 3F
|
||||
0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0004, 0x0000, 0x0006,
|
||||
0x0000, 0x0008, 0x0000, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
|
||||
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
|
||||
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
|
||||
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x0000,
|
||||
0x0000, 0x0028, 0x0000, 0x002a, 0x0000, 0x002c, 0x0000, 0x0000,
|
||||
0x002f, 0x002e, 0x002e, 0x0000, 0x0033, 0x0000, 0x0035, 0x0000,
|
||||
0x0037, 0x0000, 0x0039, 0x0000, 0x003b, 0x0000, 0x0000, 0x003e,
|
||||
// Entry 40 - 7F
|
||||
0x0000, 0x0040, 0x0040, 0x0000, 0x0043, 0x0043, 0x0000, 0x0046,
|
||||
0x0000, 0x0048, 0x0000, 0x0000, 0x004b, 0x004a, 0x004a, 0x0000,
|
||||
0x004f, 0x004f, 0x004f, 0x004f, 0x0000, 0x0054, 0x0054, 0x0000,
|
||||
0x0057, 0x0000, 0x0059, 0x0000, 0x005b, 0x0000, 0x005d, 0x005d,
|
||||
0x0000, 0x0060, 0x0000, 0x0062, 0x0000, 0x0064, 0x0000, 0x0066,
|
||||
0x0066, 0x0000, 0x0069, 0x0000, 0x006b, 0x006b, 0x006b, 0x006b,
|
||||
0x006b, 0x006b, 0x006b, 0x0000, 0x0073, 0x0000, 0x0075, 0x0000,
|
||||
0x0077, 0x0000, 0x0000, 0x007a, 0x0000, 0x007c, 0x0000, 0x007e,
|
||||
// Entry 80 - BF
|
||||
0x0000, 0x0080, 0x0080, 0x0000, 0x0083, 0x0083, 0x0000, 0x0086,
|
||||
0x0087, 0x0087, 0x0087, 0x0086, 0x0088, 0x0087, 0x0087, 0x0087,
|
||||
0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0088,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0088, 0x0087, 0x0088, 0x0087,
|
||||
0x0087, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0086, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0087, 0x0086,
|
||||
// Entry C0 - FF
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0088, 0x0087,
|
||||
0x0087, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0086, 0x0087,
|
||||
0x0087, 0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0000,
|
||||
0x00ef, 0x0000, 0x00f1, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2,
|
||||
0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f1, 0x00f2, 0x00f1, 0x00f1,
|
||||
// Entry 100 - 13F
|
||||
0x00f2, 0x00f2, 0x00f1, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f1,
|
||||
0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x0000, 0x010e,
|
||||
0x0000, 0x0110, 0x0000, 0x0112, 0x0000, 0x0114, 0x0114, 0x0000,
|
||||
0x0117, 0x0117, 0x0117, 0x0117, 0x0000, 0x011c, 0x0000, 0x011e,
|
||||
0x0000, 0x0120, 0x0120, 0x0000, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
// Entry 140 - 17F
|
||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
0x0123, 0x0123, 0x0000, 0x0152, 0x0000, 0x0154, 0x0000, 0x0156,
|
||||
0x0000, 0x0158, 0x0000, 0x015a, 0x0000, 0x015c, 0x015c, 0x015c,
|
||||
0x0000, 0x0160, 0x0000, 0x0000, 0x0163, 0x0000, 0x0165, 0x0000,
|
||||
0x0167, 0x0167, 0x0167, 0x0000, 0x016b, 0x0000, 0x016d, 0x0000,
|
||||
0x016f, 0x0000, 0x0171, 0x0171, 0x0000, 0x0174, 0x0000, 0x0176,
|
||||
0x0000, 0x0178, 0x0000, 0x017a, 0x0000, 0x017c, 0x0000, 0x017e,
|
||||
// Entry 180 - 1BF
|
||||
0x0000, 0x0000, 0x0000, 0x0182, 0x0000, 0x0184, 0x0184, 0x0184,
|
||||
0x0184, 0x0000, 0x0000, 0x0000, 0x018b, 0x0000, 0x0000, 0x018e,
|
||||
0x0000, 0x0000, 0x0191, 0x0000, 0x0000, 0x0000, 0x0195, 0x0000,
|
||||
0x0197, 0x0000, 0x0000, 0x019a, 0x0000, 0x0000, 0x019d, 0x0000,
|
||||
0x019f, 0x0000, 0x01a1, 0x0000, 0x01a3, 0x0000, 0x01a5, 0x0000,
|
||||
0x01a7, 0x0000, 0x01a9, 0x0000, 0x01ab, 0x0000, 0x01ad, 0x0000,
|
||||
0x01af, 0x0000, 0x01b1, 0x01b1, 0x0000, 0x01b4, 0x0000, 0x01b6,
|
||||
0x0000, 0x01b8, 0x0000, 0x01ba, 0x0000, 0x01bc, 0x0000, 0x0000,
|
||||
// Entry 1C0 - 1FF
|
||||
0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x0000, 0x01c5, 0x0000,
|
||||
0x01c7, 0x0000, 0x01c9, 0x0000, 0x01cb, 0x01cb, 0x01cb, 0x01cb,
|
||||
0x0000, 0x01d0, 0x0000, 0x01d2, 0x01d2, 0x0000, 0x01d5, 0x0000,
|
||||
0x01d7, 0x0000, 0x01d9, 0x0000, 0x01db, 0x0000, 0x01dd, 0x0000,
|
||||
0x01df, 0x01df, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6,
|
||||
0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x0000, 0x01ee,
|
||||
0x0000, 0x01f0, 0x0000, 0x0000, 0x01f3, 0x0000, 0x01f5, 0x01f5,
|
||||
0x01f5, 0x0000, 0x01f9, 0x0000, 0x01fb, 0x0000, 0x01fd, 0x0000,
|
||||
// Entry 200 - 23F
|
||||
0x01ff, 0x0000, 0x0000, 0x0202, 0x0000, 0x0204, 0x0204, 0x0000,
|
||||
0x0207, 0x0000, 0x0209, 0x0209, 0x0000, 0x020c, 0x020c, 0x0000,
|
||||
0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x0000,
|
||||
0x0217, 0x0000, 0x0219, 0x0000, 0x021b, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0221, 0x0000, 0x0000, 0x0224, 0x0000, 0x0226,
|
||||
0x0226, 0x0000, 0x0229, 0x0000, 0x022b, 0x022b, 0x0000, 0x0000,
|
||||
0x022f, 0x022e, 0x022e, 0x0000, 0x0000, 0x0234, 0x0000, 0x0236,
|
||||
0x0000, 0x0238, 0x0000, 0x0244, 0x023a, 0x0244, 0x0244, 0x0244,
|
||||
// Entry 240 - 27F
|
||||
0x0244, 0x0244, 0x0244, 0x0244, 0x023a, 0x0244, 0x0244, 0x0000,
|
||||
0x0247, 0x0247, 0x0247, 0x0000, 0x024b, 0x0000, 0x024d, 0x0000,
|
||||
0x024f, 0x024f, 0x0000, 0x0252, 0x0000, 0x0254, 0x0254, 0x0254,
|
||||
0x0254, 0x0254, 0x0254, 0x0000, 0x025b, 0x0000, 0x025d, 0x0000,
|
||||
0x025f, 0x0000, 0x0261, 0x0000, 0x0263, 0x0000, 0x0265, 0x0000,
|
||||
0x0000, 0x0268, 0x0268, 0x0268, 0x0000, 0x026c, 0x0000, 0x026e,
|
||||
0x0000, 0x0270, 0x0000, 0x0000, 0x0000, 0x0274, 0x0273, 0x0273,
|
||||
0x0000, 0x0278, 0x0000, 0x027a, 0x0000, 0x027c, 0x0000, 0x0000,
|
||||
// Entry 280 - 2BF
|
||||
0x0000, 0x0000, 0x0281, 0x0000, 0x0000, 0x0284, 0x0000, 0x0286,
|
||||
0x0286, 0x0286, 0x0286, 0x0000, 0x028b, 0x028b, 0x028b, 0x0000,
|
||||
0x028f, 0x028f, 0x028f, 0x028f, 0x028f, 0x0000, 0x0295, 0x0295,
|
||||
0x0295, 0x0295, 0x0000, 0x0000, 0x0000, 0x0000, 0x029d, 0x029d,
|
||||
0x029d, 0x0000, 0x02a1, 0x02a1, 0x02a1, 0x02a1, 0x0000, 0x0000,
|
||||
0x02a7, 0x02a7, 0x02a7, 0x02a7, 0x0000, 0x02ac, 0x0000, 0x02ae,
|
||||
0x02ae, 0x0000, 0x02b1, 0x0000, 0x02b3, 0x0000, 0x02b5, 0x02b5,
|
||||
0x0000, 0x0000, 0x02b9, 0x0000, 0x0000, 0x0000, 0x02bd, 0x0000,
|
||||
// Entry 2C0 - 2FF
|
||||
0x02bf, 0x02bf, 0x0000, 0x0000, 0x02c3, 0x0000, 0x02c5, 0x0000,
|
||||
0x02c7, 0x0000, 0x02c9, 0x0000, 0x02cb, 0x0000, 0x02cd, 0x02cd,
|
||||
0x0000, 0x0000, 0x02d1, 0x0000, 0x02d3, 0x02d0, 0x02d0, 0x0000,
|
||||
0x0000, 0x02d8, 0x02d7, 0x02d7, 0x0000, 0x0000, 0x02dd, 0x0000,
|
||||
0x02df, 0x0000, 0x02e1, 0x0000, 0x0000, 0x02e4, 0x0000, 0x02e6,
|
||||
0x0000, 0x0000, 0x02e9, 0x0000, 0x02eb, 0x0000, 0x02ed, 0x0000,
|
||||
0x02ef, 0x02ef, 0x0000, 0x0000, 0x02f3, 0x02f2, 0x02f2, 0x0000,
|
||||
0x02f7, 0x0000, 0x02f9, 0x02f9, 0x02f9, 0x02f9, 0x02f9, 0x0000,
|
||||
// Entry 300 - 33F
|
||||
0x02ff, 0x0300, 0x02ff, 0x0000, 0x0303, 0x0051, 0x00e6,
|
||||
} // Size: 1574 bytes
|
||||
|
||||
// Total table size 1574 bytes (1KiB); checksum: 895AAF0B
|
||||
+1015
File diff suppressed because it is too large
Load Diff
+91
@@ -0,0 +1,91 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package compact
|
||||
|
||||
var (
|
||||
und = Tag{}
|
||||
|
||||
Und Tag = Tag{}
|
||||
|
||||
Afrikaans Tag = Tag{language: afIndex, locale: afIndex}
|
||||
Amharic Tag = Tag{language: amIndex, locale: amIndex}
|
||||
Arabic Tag = Tag{language: arIndex, locale: arIndex}
|
||||
ModernStandardArabic Tag = Tag{language: ar001Index, locale: ar001Index}
|
||||
Azerbaijani Tag = Tag{language: azIndex, locale: azIndex}
|
||||
Bulgarian Tag = Tag{language: bgIndex, locale: bgIndex}
|
||||
Bengali Tag = Tag{language: bnIndex, locale: bnIndex}
|
||||
Catalan Tag = Tag{language: caIndex, locale: caIndex}
|
||||
Czech Tag = Tag{language: csIndex, locale: csIndex}
|
||||
Danish Tag = Tag{language: daIndex, locale: daIndex}
|
||||
German Tag = Tag{language: deIndex, locale: deIndex}
|
||||
Greek Tag = Tag{language: elIndex, locale: elIndex}
|
||||
English Tag = Tag{language: enIndex, locale: enIndex}
|
||||
AmericanEnglish Tag = Tag{language: enUSIndex, locale: enUSIndex}
|
||||
BritishEnglish Tag = Tag{language: enGBIndex, locale: enGBIndex}
|
||||
Spanish Tag = Tag{language: esIndex, locale: esIndex}
|
||||
EuropeanSpanish Tag = Tag{language: esESIndex, locale: esESIndex}
|
||||
LatinAmericanSpanish Tag = Tag{language: es419Index, locale: es419Index}
|
||||
Estonian Tag = Tag{language: etIndex, locale: etIndex}
|
||||
Persian Tag = Tag{language: faIndex, locale: faIndex}
|
||||
Finnish Tag = Tag{language: fiIndex, locale: fiIndex}
|
||||
Filipino Tag = Tag{language: filIndex, locale: filIndex}
|
||||
French Tag = Tag{language: frIndex, locale: frIndex}
|
||||
CanadianFrench Tag = Tag{language: frCAIndex, locale: frCAIndex}
|
||||
Gujarati Tag = Tag{language: guIndex, locale: guIndex}
|
||||
Hebrew Tag = Tag{language: heIndex, locale: heIndex}
|
||||
Hindi Tag = Tag{language: hiIndex, locale: hiIndex}
|
||||
Croatian Tag = Tag{language: hrIndex, locale: hrIndex}
|
||||
Hungarian Tag = Tag{language: huIndex, locale: huIndex}
|
||||
Armenian Tag = Tag{language: hyIndex, locale: hyIndex}
|
||||
Indonesian Tag = Tag{language: idIndex, locale: idIndex}
|
||||
Icelandic Tag = Tag{language: isIndex, locale: isIndex}
|
||||
Italian Tag = Tag{language: itIndex, locale: itIndex}
|
||||
Japanese Tag = Tag{language: jaIndex, locale: jaIndex}
|
||||
Georgian Tag = Tag{language: kaIndex, locale: kaIndex}
|
||||
Kazakh Tag = Tag{language: kkIndex, locale: kkIndex}
|
||||
Khmer Tag = Tag{language: kmIndex, locale: kmIndex}
|
||||
Kannada Tag = Tag{language: knIndex, locale: knIndex}
|
||||
Korean Tag = Tag{language: koIndex, locale: koIndex}
|
||||
Kirghiz Tag = Tag{language: kyIndex, locale: kyIndex}
|
||||
Lao Tag = Tag{language: loIndex, locale: loIndex}
|
||||
Lithuanian Tag = Tag{language: ltIndex, locale: ltIndex}
|
||||
Latvian Tag = Tag{language: lvIndex, locale: lvIndex}
|
||||
Macedonian Tag = Tag{language: mkIndex, locale: mkIndex}
|
||||
Malayalam Tag = Tag{language: mlIndex, locale: mlIndex}
|
||||
Mongolian Tag = Tag{language: mnIndex, locale: mnIndex}
|
||||
Marathi Tag = Tag{language: mrIndex, locale: mrIndex}
|
||||
Malay Tag = Tag{language: msIndex, locale: msIndex}
|
||||
Burmese Tag = Tag{language: myIndex, locale: myIndex}
|
||||
Nepali Tag = Tag{language: neIndex, locale: neIndex}
|
||||
Dutch Tag = Tag{language: nlIndex, locale: nlIndex}
|
||||
Norwegian Tag = Tag{language: noIndex, locale: noIndex}
|
||||
Punjabi Tag = Tag{language: paIndex, locale: paIndex}
|
||||
Polish Tag = Tag{language: plIndex, locale: plIndex}
|
||||
Portuguese Tag = Tag{language: ptIndex, locale: ptIndex}
|
||||
BrazilianPortuguese Tag = Tag{language: ptBRIndex, locale: ptBRIndex}
|
||||
EuropeanPortuguese Tag = Tag{language: ptPTIndex, locale: ptPTIndex}
|
||||
Romanian Tag = Tag{language: roIndex, locale: roIndex}
|
||||
Russian Tag = Tag{language: ruIndex, locale: ruIndex}
|
||||
Sinhala Tag = Tag{language: siIndex, locale: siIndex}
|
||||
Slovak Tag = Tag{language: skIndex, locale: skIndex}
|
||||
Slovenian Tag = Tag{language: slIndex, locale: slIndex}
|
||||
Albanian Tag = Tag{language: sqIndex, locale: sqIndex}
|
||||
Serbian Tag = Tag{language: srIndex, locale: srIndex}
|
||||
SerbianLatin Tag = Tag{language: srLatnIndex, locale: srLatnIndex}
|
||||
Swedish Tag = Tag{language: svIndex, locale: svIndex}
|
||||
Swahili Tag = Tag{language: swIndex, locale: swIndex}
|
||||
Tamil Tag = Tag{language: taIndex, locale: taIndex}
|
||||
Telugu Tag = Tag{language: teIndex, locale: teIndex}
|
||||
Thai Tag = Tag{language: thIndex, locale: thIndex}
|
||||
Turkish Tag = Tag{language: trIndex, locale: trIndex}
|
||||
Ukrainian Tag = Tag{language: ukIndex, locale: ukIndex}
|
||||
Urdu Tag = Tag{language: urIndex, locale: urIndex}
|
||||
Uzbek Tag = Tag{language: uzIndex, locale: uzIndex}
|
||||
Vietnamese Tag = Tag{language: viIndex, locale: viIndex}
|
||||
Chinese Tag = Tag{language: zhIndex, locale: zhIndex}
|
||||
SimplifiedChinese Tag = Tag{language: zhHansIndex, locale: zhHansIndex}
|
||||
TraditionalChinese Tag = Tag{language: zhHantIndex, locale: zhHantIndex}
|
||||
Zulu Tag = Tag{language: zuIndex, locale: zuIndex}
|
||||
)
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package language
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A Builder allows constructing a Tag from individual components.
|
||||
// Its main user is Compose in the top-level language package.
|
||||
type Builder struct {
|
||||
Tag Tag
|
||||
|
||||
private string // the x extension
|
||||
variants []string
|
||||
extensions []string
|
||||
}
|
||||
|
||||
// Make returns a new Tag from the current settings.
|
||||
func (b *Builder) Make() Tag {
|
||||
t := b.Tag
|
||||
|
||||
if len(b.extensions) > 0 || len(b.variants) > 0 {
|
||||
sort.Sort(sortVariants(b.variants))
|
||||
sort.Strings(b.extensions)
|
||||
|
||||
if b.private != "" {
|
||||
b.extensions = append(b.extensions, b.private)
|
||||
}
|
||||
n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...)
|
||||
buf := make([]byte, n)
|
||||
p := t.genCoreBytes(buf)
|
||||
t.pVariant = byte(p)
|
||||
p += appendTokens(buf[p:], b.variants...)
|
||||
t.pExt = uint16(p)
|
||||
p += appendTokens(buf[p:], b.extensions...)
|
||||
t.str = string(buf[:p])
|
||||
// We may not always need to remake the string, but when or when not
|
||||
// to do so is rather tricky.
|
||||
scan := makeScanner(buf[:p])
|
||||
t, _ = parse(&scan, "")
|
||||
return t
|
||||
|
||||
} else if b.private != "" {
|
||||
t.str = b.private
|
||||
t.RemakeString()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// SetTag copies all the settings from a given Tag. Any previously set values
|
||||
// are discarded.
|
||||
func (b *Builder) SetTag(t Tag) {
|
||||
b.Tag.LangID = t.LangID
|
||||
b.Tag.RegionID = t.RegionID
|
||||
b.Tag.ScriptID = t.ScriptID
|
||||
// TODO: optimize
|
||||
b.variants = b.variants[:0]
|
||||
if variants := t.Variants(); variants != "" {
|
||||
for _, vr := range strings.Split(variants[1:], "-") {
|
||||
b.variants = append(b.variants, vr)
|
||||
}
|
||||
}
|
||||
b.extensions, b.private = b.extensions[:0], ""
|
||||
for _, e := range t.Extensions() {
|
||||
b.AddExt(e)
|
||||
}
|
||||
}
|
||||
|
||||
// AddExt adds extension e to the tag. e must be a valid extension as returned
|
||||
// by Tag.Extension. If the extension already exists, it will be discarded,
|
||||
// except for a -u extension, where non-existing key-type pairs will added.
|
||||
func (b *Builder) AddExt(e string) {
|
||||
if e[0] == 'x' {
|
||||
if b.private == "" {
|
||||
b.private = e
|
||||
}
|
||||
return
|
||||
}
|
||||
for i, s := range b.extensions {
|
||||
if s[0] == e[0] {
|
||||
if e[0] == 'u' {
|
||||
b.extensions[i] += e[1:]
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
b.extensions = append(b.extensions, e)
|
||||
}
|
||||
|
||||
// SetExt sets the extension e to the tag. e must be a valid extension as
|
||||
// returned by Tag.Extension. If the extension already exists, it will be
|
||||
// overwritten, except for a -u extension, where the individual key-type pairs
|
||||
// will be set.
|
||||
func (b *Builder) SetExt(e string) {
|
||||
if e[0] == 'x' {
|
||||
b.private = e
|
||||
return
|
||||
}
|
||||
for i, s := range b.extensions {
|
||||
if s[0] == e[0] {
|
||||
if e[0] == 'u' {
|
||||
b.extensions[i] = e + s[1:]
|
||||
} else {
|
||||
b.extensions[i] = e
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
b.extensions = append(b.extensions, e)
|
||||
}
|
||||
|
||||
// AddVariant adds any number of variants.
|
||||
func (b *Builder) AddVariant(v ...string) {
|
||||
for _, v := range v {
|
||||
if v != "" {
|
||||
b.variants = append(b.variants, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ClearVariants removes any variants previously added, including those
|
||||
// copied from a Tag in SetTag.
|
||||
func (b *Builder) ClearVariants() {
|
||||
b.variants = b.variants[:0]
|
||||
}
|
||||
|
||||
// ClearExtensions removes any extensions previously added, including those
|
||||
// copied from a Tag in SetTag.
|
||||
func (b *Builder) ClearExtensions() {
|
||||
b.private = ""
|
||||
b.extensions = b.extensions[:0]
|
||||
}
|
||||
|
||||
func tokenLen(token ...string) (n int) {
|
||||
for _, t := range token {
|
||||
n += len(t) + 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func appendTokens(b []byte, token ...string) int {
|
||||
p := 0
|
||||
for _, t := range token {
|
||||
b[p] = '-'
|
||||
copy(b[p+1:], t)
|
||||
p += 1 + len(t)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
type sortVariants []string
|
||||
|
||||
func (s sortVariants) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s sortVariants) Swap(i, j int) {
|
||||
s[j], s[i] = s[i], s[j]
|
||||
}
|
||||
|
||||
func (s sortVariants) Less(i, j int) bool {
|
||||
return variantIndex[s[i]] < variantIndex[s[j]]
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package language
|
||||
|
||||
// BaseLanguages returns the list of all supported base languages. It generates
|
||||
// the list by traversing the internal structures.
|
||||
func BaseLanguages() []Language {
|
||||
base := make([]Language, 0, NumLanguages)
|
||||
for i := 0; i < langNoIndexOffset; i++ {
|
||||
// We included "und" already for the value 0.
|
||||
if i != nonCanonicalUnd {
|
||||
base = append(base, Language(i))
|
||||
}
|
||||
}
|
||||
i := langNoIndexOffset
|
||||
for _, v := range langNoIndex {
|
||||
for k := 0; k < 8; k++ {
|
||||
if v&1 == 1 {
|
||||
base = append(base, Language(i))
|
||||
}
|
||||
v >>= 1
|
||||
i++
|
||||
}
|
||||
}
|
||||
return base
|
||||
}
|
||||
+596
@@ -0,0 +1,596 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen.go gen_common.go -output tables.go
|
||||
|
||||
package language // import "golang.org/x/text/internal/language"
|
||||
|
||||
// TODO: Remove above NOTE after:
|
||||
// - verifying that tables are dropped correctly (most notably matcher tables).
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxCoreSize is the maximum size of a BCP 47 tag without variants and
|
||||
// extensions. Equals max lang (3) + script (4) + max reg (3) + 2 dashes.
|
||||
maxCoreSize = 12
|
||||
|
||||
// max99thPercentileSize is a somewhat arbitrary buffer size that presumably
|
||||
// is large enough to hold at least 99% of the BCP 47 tags.
|
||||
max99thPercentileSize = 32
|
||||
|
||||
// maxSimpleUExtensionSize is the maximum size of a -u extension with one
|
||||
// key-type pair. Equals len("-u-") + key (2) + dash + max value (8).
|
||||
maxSimpleUExtensionSize = 14
|
||||
)
|
||||
|
||||
// Tag represents a BCP 47 language tag. It is used to specify an instance of a
|
||||
// specific language or locale. All language tag values are guaranteed to be
|
||||
// well-formed. The zero value of Tag is Und.
|
||||
type Tag struct {
|
||||
// TODO: the following fields have the form TagTypeID. This name is chosen
|
||||
// to allow refactoring the public package without conflicting with its
|
||||
// Base, Script, and Region methods. Once the transition is fully completed
|
||||
// the ID can be stripped from the name.
|
||||
|
||||
LangID Language
|
||||
RegionID Region
|
||||
// TODO: we will soon run out of positions for ScriptID. Idea: instead of
|
||||
// storing lang, region, and ScriptID codes, store only the compact index and
|
||||
// have a lookup table from this code to its expansion. This greatly speeds
|
||||
// up table lookup, speed up common variant cases.
|
||||
// This will also immediately free up 3 extra bytes. Also, the pVariant
|
||||
// field can now be moved to the lookup table, as the compact index uniquely
|
||||
// determines the offset of a possible variant.
|
||||
ScriptID Script
|
||||
pVariant byte // offset in str, includes preceding '-'
|
||||
pExt uint16 // offset of first extension, includes preceding '-'
|
||||
|
||||
// str is the string representation of the Tag. It will only be used if the
|
||||
// tag has variants or extensions.
|
||||
str string
|
||||
}
|
||||
|
||||
// Make is a convenience wrapper for Parse that omits the error.
|
||||
// In case of an error, a sensible default is returned.
|
||||
func Make(s string) Tag {
|
||||
t, _ := Parse(s)
|
||||
return t
|
||||
}
|
||||
|
||||
// Raw returns the raw base language, script and region, without making an
|
||||
// attempt to infer their values.
|
||||
// TODO: consider removing
|
||||
func (t Tag) Raw() (b Language, s Script, r Region) {
|
||||
return t.LangID, t.ScriptID, t.RegionID
|
||||
}
|
||||
|
||||
// equalTags compares language, script and region subtags only.
|
||||
func (t Tag) equalTags(a Tag) bool {
|
||||
return t.LangID == a.LangID && t.ScriptID == a.ScriptID && t.RegionID == a.RegionID
|
||||
}
|
||||
|
||||
// IsRoot returns true if t is equal to language "und".
|
||||
func (t Tag) IsRoot() bool {
|
||||
if int(t.pVariant) < len(t.str) {
|
||||
return false
|
||||
}
|
||||
return t.equalTags(Und)
|
||||
}
|
||||
|
||||
// IsPrivateUse reports whether the Tag consists solely of an IsPrivateUse use
|
||||
// tag.
|
||||
func (t Tag) IsPrivateUse() bool {
|
||||
return t.str != "" && t.pVariant == 0
|
||||
}
|
||||
|
||||
// RemakeString is used to update t.str in case lang, script or region changed.
|
||||
// It is assumed that pExt and pVariant still point to the start of the
|
||||
// respective parts.
|
||||
func (t *Tag) RemakeString() {
|
||||
if t.str == "" {
|
||||
return
|
||||
}
|
||||
extra := t.str[t.pVariant:]
|
||||
if t.pVariant > 0 {
|
||||
extra = extra[1:]
|
||||
}
|
||||
if t.equalTags(Und) && strings.HasPrefix(extra, "x-") {
|
||||
t.str = extra
|
||||
t.pVariant = 0
|
||||
t.pExt = 0
|
||||
return
|
||||
}
|
||||
var buf [max99thPercentileSize]byte // avoid extra memory allocation in most cases.
|
||||
b := buf[:t.genCoreBytes(buf[:])]
|
||||
if extra != "" {
|
||||
diff := len(b) - int(t.pVariant)
|
||||
b = append(b, '-')
|
||||
b = append(b, extra...)
|
||||
t.pVariant = uint8(int(t.pVariant) + diff)
|
||||
t.pExt = uint16(int(t.pExt) + diff)
|
||||
} else {
|
||||
t.pVariant = uint8(len(b))
|
||||
t.pExt = uint16(len(b))
|
||||
}
|
||||
t.str = string(b)
|
||||
}
|
||||
|
||||
// genCoreBytes writes a string for the base languages, script and region tags
|
||||
// to the given buffer and returns the number of bytes written. It will never
|
||||
// write more than maxCoreSize bytes.
|
||||
func (t *Tag) genCoreBytes(buf []byte) int {
|
||||
n := t.LangID.StringToBuf(buf[:])
|
||||
if t.ScriptID != 0 {
|
||||
n += copy(buf[n:], "-")
|
||||
n += copy(buf[n:], t.ScriptID.String())
|
||||
}
|
||||
if t.RegionID != 0 {
|
||||
n += copy(buf[n:], "-")
|
||||
n += copy(buf[n:], t.RegionID.String())
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// String returns the canonical string representation of the language tag.
|
||||
func (t Tag) String() string {
|
||||
if t.str != "" {
|
||||
return t.str
|
||||
}
|
||||
if t.ScriptID == 0 && t.RegionID == 0 {
|
||||
return t.LangID.String()
|
||||
}
|
||||
buf := [maxCoreSize]byte{}
|
||||
return string(buf[:t.genCoreBytes(buf[:])])
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
func (t Tag) MarshalText() (text []byte, err error) {
|
||||
if t.str != "" {
|
||||
text = append(text, t.str...)
|
||||
} else if t.ScriptID == 0 && t.RegionID == 0 {
|
||||
text = append(text, t.LangID.String()...)
|
||||
} else {
|
||||
buf := [maxCoreSize]byte{}
|
||||
text = buf[:t.genCoreBytes(buf[:])]
|
||||
}
|
||||
return text, nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (t *Tag) UnmarshalText(text []byte) error {
|
||||
tag, err := Parse(string(text))
|
||||
*t = tag
|
||||
return err
|
||||
}
|
||||
|
||||
// Variants returns the part of the tag holding all variants or the empty string
|
||||
// if there are no variants defined.
|
||||
func (t Tag) Variants() string {
|
||||
if t.pVariant == 0 {
|
||||
return ""
|
||||
}
|
||||
return t.str[t.pVariant:t.pExt]
|
||||
}
|
||||
|
||||
// VariantOrPrivateUseTags returns variants or private use tags.
|
||||
func (t Tag) VariantOrPrivateUseTags() string {
|
||||
if t.pExt > 0 {
|
||||
return t.str[t.pVariant:t.pExt]
|
||||
}
|
||||
return t.str[t.pVariant:]
|
||||
}
|
||||
|
||||
// HasString reports whether this tag defines more than just the raw
|
||||
// components.
|
||||
func (t Tag) HasString() bool {
|
||||
return t.str != ""
|
||||
}
|
||||
|
||||
// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
|
||||
// specific language are substituted with fields from the parent language.
|
||||
// The parent for a language may change for newer versions of CLDR.
|
||||
func (t Tag) Parent() Tag {
|
||||
if t.str != "" {
|
||||
// Strip the variants and extensions.
|
||||
b, s, r := t.Raw()
|
||||
t = Tag{LangID: b, ScriptID: s, RegionID: r}
|
||||
if t.RegionID == 0 && t.ScriptID != 0 && t.LangID != 0 {
|
||||
base, _ := addTags(Tag{LangID: t.LangID})
|
||||
if base.ScriptID == t.ScriptID {
|
||||
return Tag{LangID: t.LangID}
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
if t.LangID != 0 {
|
||||
if t.RegionID != 0 {
|
||||
maxScript := t.ScriptID
|
||||
if maxScript == 0 {
|
||||
max, _ := addTags(t)
|
||||
maxScript = max.ScriptID
|
||||
}
|
||||
|
||||
for i := range parents {
|
||||
if Language(parents[i].lang) == t.LangID && Script(parents[i].maxScript) == maxScript {
|
||||
for _, r := range parents[i].fromRegion {
|
||||
if Region(r) == t.RegionID {
|
||||
return Tag{
|
||||
LangID: t.LangID,
|
||||
ScriptID: Script(parents[i].script),
|
||||
RegionID: Region(parents[i].toRegion),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strip the script if it is the default one.
|
||||
base, _ := addTags(Tag{LangID: t.LangID})
|
||||
if base.ScriptID != maxScript {
|
||||
return Tag{LangID: t.LangID, ScriptID: maxScript}
|
||||
}
|
||||
return Tag{LangID: t.LangID}
|
||||
} else if t.ScriptID != 0 {
|
||||
// The parent for an base-script pair with a non-default script is
|
||||
// "und" instead of the base language.
|
||||
base, _ := addTags(Tag{LangID: t.LangID})
|
||||
if base.ScriptID != t.ScriptID {
|
||||
return Und
|
||||
}
|
||||
return Tag{LangID: t.LangID}
|
||||
}
|
||||
}
|
||||
return Und
|
||||
}
|
||||
|
||||
// ParseExtension parses s as an extension and returns it on success.
|
||||
func ParseExtension(s string) (ext string, err error) {
|
||||
scan := makeScannerString(s)
|
||||
var end int
|
||||
if n := len(scan.token); n != 1 {
|
||||
return "", ErrSyntax
|
||||
}
|
||||
scan.toLower(0, len(scan.b))
|
||||
end = parseExtension(&scan)
|
||||
if end != len(s) {
|
||||
return "", ErrSyntax
|
||||
}
|
||||
return string(scan.b), nil
|
||||
}
|
||||
|
||||
// HasVariants reports whether t has variants.
|
||||
func (t Tag) HasVariants() bool {
|
||||
return uint16(t.pVariant) < t.pExt
|
||||
}
|
||||
|
||||
// HasExtensions reports whether t has extensions.
|
||||
func (t Tag) HasExtensions() bool {
|
||||
return int(t.pExt) < len(t.str)
|
||||
}
|
||||
|
||||
// Extension returns the extension of type x for tag t. It will return
|
||||
// false for ok if t does not have the requested extension. The returned
|
||||
// extension will be invalid in this case.
|
||||
func (t Tag) Extension(x byte) (ext string, ok bool) {
|
||||
for i := int(t.pExt); i < len(t.str)-1; {
|
||||
var ext string
|
||||
i, ext = getExtension(t.str, i)
|
||||
if ext[0] == x {
|
||||
return ext, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Extensions returns all extensions of t.
|
||||
func (t Tag) Extensions() []string {
|
||||
e := []string{}
|
||||
for i := int(t.pExt); i < len(t.str)-1; {
|
||||
var ext string
|
||||
i, ext = getExtension(t.str, i)
|
||||
e = append(e, ext)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// TypeForKey returns the type associated with the given key, where key and type
|
||||
// are of the allowed values defined for the Unicode locale extension ('u') in
|
||||
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
|
||||
// TypeForKey will traverse the inheritance chain to get the correct value.
|
||||
func (t Tag) TypeForKey(key string) string {
|
||||
if start, end, _ := t.findTypeForKey(key); end != start {
|
||||
return t.str[start:end]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var (
|
||||
errPrivateUse = errors.New("cannot set a key on a private use tag")
|
||||
errInvalidArguments = errors.New("invalid key or type")
|
||||
)
|
||||
|
||||
// SetTypeForKey returns a new Tag with the key set to type, where key and type
|
||||
// are of the allowed values defined for the Unicode locale extension ('u') in
|
||||
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
|
||||
// An empty value removes an existing pair with the same key.
|
||||
func (t Tag) SetTypeForKey(key, value string) (Tag, error) {
|
||||
if t.IsPrivateUse() {
|
||||
return t, errPrivateUse
|
||||
}
|
||||
if len(key) != 2 {
|
||||
return t, errInvalidArguments
|
||||
}
|
||||
|
||||
// Remove the setting if value is "".
|
||||
if value == "" {
|
||||
start, end, _ := t.findTypeForKey(key)
|
||||
if start != end {
|
||||
// Remove key tag and leading '-'.
|
||||
start -= 4
|
||||
|
||||
// Remove a possible empty extension.
|
||||
if (end == len(t.str) || t.str[end+2] == '-') && t.str[start-2] == '-' {
|
||||
start -= 2
|
||||
}
|
||||
if start == int(t.pVariant) && end == len(t.str) {
|
||||
t.str = ""
|
||||
t.pVariant, t.pExt = 0, 0
|
||||
} else {
|
||||
t.str = fmt.Sprintf("%s%s", t.str[:start], t.str[end:])
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
if len(value) < 3 || len(value) > 8 {
|
||||
return t, errInvalidArguments
|
||||
}
|
||||
|
||||
var (
|
||||
buf [maxCoreSize + maxSimpleUExtensionSize]byte
|
||||
uStart int // start of the -u extension.
|
||||
)
|
||||
|
||||
// Generate the tag string if needed.
|
||||
if t.str == "" {
|
||||
uStart = t.genCoreBytes(buf[:])
|
||||
buf[uStart] = '-'
|
||||
uStart++
|
||||
}
|
||||
|
||||
// Create new key-type pair and parse it to verify.
|
||||
b := buf[uStart:]
|
||||
copy(b, "u-")
|
||||
copy(b[2:], key)
|
||||
b[4] = '-'
|
||||
b = b[:5+copy(b[5:], value)]
|
||||
scan := makeScanner(b)
|
||||
if parseExtensions(&scan); scan.err != nil {
|
||||
return t, scan.err
|
||||
}
|
||||
|
||||
// Assemble the replacement string.
|
||||
if t.str == "" {
|
||||
t.pVariant, t.pExt = byte(uStart-1), uint16(uStart-1)
|
||||
t.str = string(buf[:uStart+len(b)])
|
||||
} else {
|
||||
s := t.str
|
||||
start, end, hasExt := t.findTypeForKey(key)
|
||||
if start == end {
|
||||
if hasExt {
|
||||
b = b[2:]
|
||||
}
|
||||
t.str = fmt.Sprintf("%s-%s%s", s[:start], b, s[end:])
|
||||
} else {
|
||||
t.str = fmt.Sprintf("%s%s%s", s[:start], value, s[end:])
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// findKeyAndType returns the start and end position for the type corresponding
|
||||
// to key or the point at which to insert the key-value pair if the type
|
||||
// wasn't found. The hasExt return value reports whether an -u extension was present.
|
||||
// Note: the extensions are typically very small and are likely to contain
|
||||
// only one key-type pair.
|
||||
func (t Tag) findTypeForKey(key string) (start, end int, hasExt bool) {
|
||||
p := int(t.pExt)
|
||||
if len(key) != 2 || p == len(t.str) || p == 0 {
|
||||
return p, p, false
|
||||
}
|
||||
s := t.str
|
||||
|
||||
// Find the correct extension.
|
||||
for p++; s[p] != 'u'; p++ {
|
||||
if s[p] > 'u' {
|
||||
p--
|
||||
return p, p, false
|
||||
}
|
||||
if p = nextExtension(s, p); p == len(s) {
|
||||
return len(s), len(s), false
|
||||
}
|
||||
}
|
||||
// Proceed to the hyphen following the extension name.
|
||||
p++
|
||||
|
||||
// curKey is the key currently being processed.
|
||||
curKey := ""
|
||||
|
||||
// Iterate over keys until we get the end of a section.
|
||||
for {
|
||||
// p points to the hyphen preceding the current token.
|
||||
if p3 := p + 3; s[p3] == '-' {
|
||||
// Found a key.
|
||||
// Check whether we just processed the key that was requested.
|
||||
if curKey == key {
|
||||
return start, p, true
|
||||
}
|
||||
// Set to the next key and continue scanning type tokens.
|
||||
curKey = s[p+1 : p3]
|
||||
if curKey > key {
|
||||
return p, p, true
|
||||
}
|
||||
// Start of the type token sequence.
|
||||
start = p + 4
|
||||
// A type is at least 3 characters long.
|
||||
p += 7 // 4 + 3
|
||||
} else {
|
||||
// Attribute or type, which is at least 3 characters long.
|
||||
p += 4
|
||||
}
|
||||
// p points past the third character of a type or attribute.
|
||||
max := p + 5 // maximum length of token plus hyphen.
|
||||
if len(s) < max {
|
||||
max = len(s)
|
||||
}
|
||||
for ; p < max && s[p] != '-'; p++ {
|
||||
}
|
||||
// Bail if we have exhausted all tokens or if the next token starts
|
||||
// a new extension.
|
||||
if p == len(s) || s[p+2] == '-' {
|
||||
if curKey == key {
|
||||
return start, p, true
|
||||
}
|
||||
return p, p, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ParseBase parses a 2- or 3-letter ISO 639 code.
|
||||
// It returns a ValueError if s is a well-formed but unknown language identifier
|
||||
// or another error if another error occurred.
|
||||
func ParseBase(s string) (Language, error) {
|
||||
if n := len(s); n < 2 || 3 < n {
|
||||
return 0, ErrSyntax
|
||||
}
|
||||
var buf [3]byte
|
||||
return getLangID(buf[:copy(buf[:], s)])
|
||||
}
|
||||
|
||||
// ParseScript parses a 4-letter ISO 15924 code.
|
||||
// It returns a ValueError if s is a well-formed but unknown script identifier
|
||||
// or another error if another error occurred.
|
||||
func ParseScript(s string) (Script, error) {
|
||||
if len(s) != 4 {
|
||||
return 0, ErrSyntax
|
||||
}
|
||||
var buf [4]byte
|
||||
return getScriptID(script, buf[:copy(buf[:], s)])
|
||||
}
|
||||
|
||||
// EncodeM49 returns the Region for the given UN M.49 code.
|
||||
// It returns an error if r is not a valid code.
|
||||
func EncodeM49(r int) (Region, error) {
|
||||
return getRegionM49(r)
|
||||
}
|
||||
|
||||
// ParseRegion parses a 2- or 3-letter ISO 3166-1 or a UN M.49 code.
|
||||
// It returns a ValueError if s is a well-formed but unknown region identifier
|
||||
// or another error if another error occurred.
|
||||
func ParseRegion(s string) (Region, error) {
|
||||
if n := len(s); n < 2 || 3 < n {
|
||||
return 0, ErrSyntax
|
||||
}
|
||||
var buf [3]byte
|
||||
return getRegionID(buf[:copy(buf[:], s)])
|
||||
}
|
||||
|
||||
// IsCountry returns whether this region is a country or autonomous area. This
|
||||
// includes non-standard definitions from CLDR.
|
||||
func (r Region) IsCountry() bool {
|
||||
if r == 0 || r.IsGroup() || r.IsPrivateUse() && r != _XK {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsGroup returns whether this region defines a collection of regions. This
|
||||
// includes non-standard definitions from CLDR.
|
||||
func (r Region) IsGroup() bool {
|
||||
if r == 0 {
|
||||
return false
|
||||
}
|
||||
return int(regionInclusion[r]) < len(regionContainment)
|
||||
}
|
||||
|
||||
// Contains returns whether Region c is contained by Region r. It returns true
|
||||
// if c == r.
|
||||
func (r Region) Contains(c Region) bool {
|
||||
if r == c {
|
||||
return true
|
||||
}
|
||||
g := regionInclusion[r]
|
||||
if g >= nRegionGroups {
|
||||
return false
|
||||
}
|
||||
m := regionContainment[g]
|
||||
|
||||
d := regionInclusion[c]
|
||||
b := regionInclusionBits[d]
|
||||
|
||||
// A contained country may belong to multiple disjoint groups. Matching any
|
||||
// of these indicates containment. If the contained region is a group, it
|
||||
// must strictly be a subset.
|
||||
if d >= nRegionGroups {
|
||||
return b&m != 0
|
||||
}
|
||||
return b&^m == 0
|
||||
}
|
||||
|
||||
var errNoTLD = errors.New("language: region is not a valid ccTLD")
|
||||
|
||||
// TLD returns the country code top-level domain (ccTLD). UK is returned for GB.
|
||||
// In all other cases it returns either the region itself or an error.
|
||||
//
|
||||
// This method may return an error for a region for which there exists a
|
||||
// canonical form with a ccTLD. To get that ccTLD canonicalize r first. The
|
||||
// region will already be canonicalized it was obtained from a Tag that was
|
||||
// obtained using any of the default methods.
|
||||
func (r Region) TLD() (Region, error) {
|
||||
// See http://en.wikipedia.org/wiki/Country_code_top-level_domain for the
|
||||
// difference between ISO 3166-1 and IANA ccTLD.
|
||||
if r == _GB {
|
||||
r = _UK
|
||||
}
|
||||
if (r.typ() & ccTLD) == 0 {
|
||||
return 0, errNoTLD
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Canonicalize returns the region or a possible replacement if the region is
|
||||
// deprecated. It will not return a replacement for deprecated regions that
|
||||
// are split into multiple regions.
|
||||
func (r Region) Canonicalize() Region {
|
||||
if cr := normRegion(r); cr != 0 {
|
||||
return cr
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Variant represents a registered variant of a language as defined by BCP 47.
|
||||
type Variant struct {
|
||||
ID uint8
|
||||
str string
|
||||
}
|
||||
|
||||
// ParseVariant parses and returns a Variant. An error is returned if s is not
|
||||
// a valid variant.
|
||||
func ParseVariant(s string) (Variant, error) {
|
||||
s = strings.ToLower(s)
|
||||
if id, ok := variantIndex[s]; ok {
|
||||
return Variant{id, s}, nil
|
||||
}
|
||||
return Variant{}, NewValueError([]byte(s))
|
||||
}
|
||||
|
||||
// String returns the string representation of the variant.
|
||||
func (v Variant) String() string {
|
||||
return v.str
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user