github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/state/impl_federation_cmd_storage.go (about) 1 /* 2 * Copyright (c) 2022-present unTill Pro, Ltd. 3 */ 4 5 package state 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "strconv" 11 "strings" 12 13 "github.com/voedger/voedger/pkg/appdef" 14 "github.com/voedger/voedger/pkg/istructs" 15 "github.com/voedger/voedger/pkg/itokens" 16 payloads "github.com/voedger/voedger/pkg/itokens-payloads" 17 coreutils "github.com/voedger/voedger/pkg/utils" 18 "github.com/voedger/voedger/pkg/utils/federation" 19 ) 20 21 const ( 22 ContentType = "Content-Type" 23 ) 24 25 type FederationCommandHandler = func(owner, appname string, wsid istructs.WSID, command appdef.QName, body string) (statusCode int, newIDs map[string]int64, result string, err error) 26 27 type federationCommandStorage struct { 28 appStructs AppStructsFunc 29 wsid WSIDFunc 30 federation federation.IFederation 31 tokens itokens.ITokens 32 emulation FederationCommandHandler 33 } 34 35 func (s *federationCommandStorage) NewKeyBuilder(appdef.QName, istructs.IStateKeyBuilder) istructs.IStateKeyBuilder { 36 return newKeyBuilder(FederationCommand, appdef.NullQName) 37 } 38 func (s *federationCommandStorage) Get(key istructs.IStateKeyBuilder) (istructs.IStateValue, error) { 39 appqname := s.appStructs().AppQName() 40 var owner string 41 var appname string 42 var wsid istructs.WSID 43 var command appdef.QName 44 var body string 45 opts := make([]coreutils.ReqOptFunc, 0) 46 47 kb := key.(*keyBuilder) 48 49 if v, ok := kb.data[Field_ExpectedCodes]; ok { 50 for _, ec := range strings.Split(v.(string), ",") { 51 code, err := strconv.Atoi(ec) 52 if err != nil { 53 return nil, err 54 } 55 opts = append(opts, coreutils.WithExpectedCode(code)) 56 } 57 } 58 59 if v, ok := kb.data[Field_Owner]; ok { 60 owner = v.(string) 61 } else { 62 owner = appqname.Owner() 63 } 64 65 if v, ok := kb.data[Field_AppName]; ok { 66 appname = v.(string) 67 } else { 68 appname = appqname.Name() 69 } 70 71 if v, ok := kb.data[Field_WSID]; ok { 72 wsid = v.(istructs.WSID) 73 } else { 74 wsid = s.wsid() 75 } 76 77 if v, ok := kb.data[Field_Command]; ok { 78 command = v.(appdef.QName) 79 } else { 80 return nil, errCommandNotSpecified 81 } 82 83 if v, ok := kb.data[Field_Body]; ok { 84 body = v.(string) 85 } 86 if v, ok := kb.data[Field_Token]; ok { 87 opts = append(opts, coreutils.WithAuthorizeBy(v.(string))) 88 } else { 89 appQName := istructs.NewAppQName(owner, appname) 90 systemPrincipalToken, err := payloads.GetSystemPrincipalToken(s.tokens, appQName) 91 if err != nil { 92 return nil, err 93 } 94 opts = append(opts, coreutils.WithAuthorizeBy(systemPrincipalToken)) 95 } 96 97 appOwnerAndName := owner + istructs.AppQNameQualifierChar + appname 98 99 relativeUrl := fmt.Sprintf("api/%s/%d/%s", appOwnerAndName, wsid, command) 100 101 var resStatus int 102 var resBody string 103 var newIDs map[string]int64 104 var err error 105 106 if s.emulation != nil { 107 resStatus, newIDs, resBody, err = s.emulation(owner, appname, wsid, command, body) 108 if err != nil { 109 return nil, err 110 } 111 } else { 112 resp, err := s.federation.Func(relativeUrl, body, opts...) 113 if err != nil { 114 return nil, err 115 } 116 resBody = resp.Body 117 newIDs = resp.NewIDs 118 resStatus = resp.HTTPResp.StatusCode 119 } 120 121 result := map[string]interface{}{} 122 err = json.Unmarshal([]byte(resBody), &result) 123 if err != nil { 124 return nil, err 125 } 126 127 return &fcCmdValue{ 128 statusCode: resStatus, 129 newIds: &fcCmdNewIds{newIds: newIDs}, 130 result: &jsonValue{json: result}, 131 }, nil 132 } 133 func (s *federationCommandStorage) Read(key istructs.IStateKeyBuilder, callback istructs.ValueCallback) (err error) { 134 v, err := s.Get(key) 135 if err != nil { 136 return err 137 } 138 return callback(nil, v) 139 } 140 141 type fcCmdValue struct { 142 baseStateValue 143 statusCode int 144 newIds istructs.IStateValue 145 result istructs.IStateValue 146 } 147 148 func (v *fcCmdValue) AsInt32(name string) int32 { 149 if name == Field_StatusCode { 150 return int32(v.statusCode) 151 } 152 panic(errUndefined(name)) 153 } 154 155 func (v *fcCmdValue) AsValue(name string) istructs.IStateValue { 156 if name == Field_NewIDs { 157 return v.newIds 158 } 159 if name == Field_Result { 160 return v.result 161 } 162 panic(errUndefined(name)) 163 } 164 165 type fcCmdNewIds struct { 166 baseStateValue 167 newIds map[string]int64 168 } 169 170 func (v *fcCmdNewIds) AsInt64(name string) int64 { 171 if id, ok := v.newIds[name]; ok { 172 return id 173 } 174 panic(errUndefined(name)) 175 }