diff --git a/frostfsid/client/client.go b/frostfsid/client/client.go index fde12b7..8588d53 100644 --- a/frostfsid/client/client.go +++ b/frostfsid/client/client.go @@ -96,6 +96,7 @@ const ( createSubjectMethod = "createSubject" getSubjectMethod = "getSubject" getSubjectExtendedMethod = "getSubjectExtended" + getSubjectKVMethod = "getSubjectKV" listSubjectsMethod = "listSubjects" addSubjectKeyMethod = "addSubjectKey" removeSubjectKeyMethod = "removeSubjectKey" @@ -266,6 +267,11 @@ func (c Client) GetSubjectExtended(addr util.Uint160) (*SubjectExtended, error) return ParseSubjectExtended(items) } +// GetSubjectKV invokes `getSubjectKV` method of contract. +func (c Client) GetSubjectKV(addr util.Uint160, name string) (string, error) { + return unwrap.UTF8String(c.act.Call(c.contract, getSubjectKVMethod, addr, name)) +} + // ListSubjects gets all subjects. func (c Client) ListSubjects() ([]util.Uint160, error) { return UnwrapArrayOfUint160(commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listSubjectsMethod)) diff --git a/frostfsid/config.yml b/frostfsid/config.yml index 0beb114..c2d07db 100644 --- a/frostfsid/config.yml +++ b/frostfsid/config.yml @@ -7,6 +7,7 @@ safemethods: - "getGroupByName" - "getNamespace" - "getNamespaceExtended" + - "getSubjectKV" - "getSubject" - "getSubjectExtended" - "getSubjectByKey" diff --git a/frostfsid/frostfsid_contract.go b/frostfsid/frostfsid_contract.go index d7c2f38..a9cca0e 100644 --- a/frostfsid/frostfsid_contract.go +++ b/frostfsid/frostfsid_contract.go @@ -472,6 +472,34 @@ func GetSubjectKeyByName(ns, name string) interop.PublicKey { return subjKey } +// GetSubjectKV GetSubjectKey returns the value associated with the key for the subject. +func GetSubjectKV(addr interop.Hash160, name string) string { + if len(addr) != interop.Hash160Len { + panic("incorrect address length") + } + + ctx := storage.GetReadOnlyContext() + sKey := subjectKeyFromAddr(addr) + data := storage.Get(ctx, sKey).([]byte) + if data == nil { + return "" + } + + sbj := std.Deserialize(data).(Subject) + + if sbj.KV == nil { + return "" + } + + for k, v := range sbj.KV { + if k == name { + return v + } + } + + return "" +} + func ListSubjects() iterator.Iterator { ctx := storage.GetReadOnlyContext() return storage.Find(ctx, []byte{subjectKeysPrefix}, storage.KeysOnly|storage.RemovePrefix) diff --git a/rpcclient/frostfsid/client.go b/rpcclient/frostfsid/client.go index ddea629..6c485cf 100644 --- a/rpcclient/frostfsid/client.go +++ b/rpcclient/frostfsid/client.go @@ -222,6 +222,11 @@ func (c *ContractReader) GetSubjectExtended(addr util.Uint160) ([]stackitem.Item return unwrap.Array(c.invoker.Call(c.hash, "getSubjectExtended", addr)) } +// GetSubjectKV invokes `getSubjectKV` method of contract. +func (c *ContractReader) GetSubjectKV(addr util.Uint160, name string) (string, error) { + return unwrap.UTF8String(c.invoker.Call(c.hash, "getSubjectKV", addr, name)) +} + // GetSubjectKeyByName invokes `getSubjectKeyByName` method of contract. func (c *ContractReader) GetSubjectKeyByName(ns string, name string) (*keys.PublicKey, error) { return unwrap.PublicKey(c.invoker.Call(c.hash, "getSubjectKeyByName", ns, name))