Objects
Objects represent items stored within a container . These are subject to the permissions of the container being the most relaxed possible permissions that can be applied to an object. It is possible using Session/Bearer Tokens to restrict permissions further on objects within a container however
Please note actions on objects are restricted by the permissions on the container AND the permissions of the token used to access the functions.
Uploading Objects
you will need
-
A container ID to upload the object to, with the correct permissions
-
An object to upload (
filepath
) -
Have created a NeoFS client (
cli
)
Attributes
Attributes are key value pairs (string:string) that are attached to the metadata of objects. You can specify anything as an attribute, however there are a couple of reserved ones
var attributes []*object.Attribute
timeStampAttr := new(object.Attribute)
timeStampAttr.SetKey(object.AttributeTimestamp) // AttributeTimestamp key is like a 'created at' attribute
timeStampAttr.SetValue(strconv.FormatInt(time.Now().Unix(), 10))
fileNameAttr := new(object.Attribute)
fileNameAttr.SetKey(object.AttributeFileName) // AttributeFileName key is the filename to be associated with the object.
fileNameAttr.SetValue(path.Base(filepath)) //path.Base(filepath) returns the last element of a file path (usually the filename)
expirationEpochAttr := new(object.Attribute)
expirationEpochAttr.SetKey("__NEOFS__EXPIRATION_EPOCH") // Reserved case for when the life of the object should expire
expirationEpochAttr.SetValue(strconv.Itoa(epoch)) //The epoch at which the object will expire
attributes = append(attributes, []*object.Attribute{timeStampAttr, fileNameAttr, expirationEpochAttr}...)
If you have set the FileName attribute, you can also refer to the object by its filename, i.ehttps://http.testnet.fs.neo.org/CONTAINER_ID/upload.pngwhen its uploaded, (see acl permissions )
Session Token
See tokens for how to create a session token
Upload
This example demonstrates how to upload binary data using an io.Reader
defined by the developer
var objectID oid.ID
o := object.New()
o.SetContainerID(&containerID)
o.SetOwnerID(ownerID)
o.SetAttributes(attr...)
objWriter, err := cli.ObjectPutInit(ctx, client.PrmObjectPutInit{})
//you probably have either a session or bearer token depending on your permissions. If the container is yours, use a session token
if sessionToken != nil {
objWriter.WithinSession(*sessionToken)
}
if bearerToken != nil {
objWriter.WithBearerToken(*bearerToken)
}
if !objWriter.WriteHeader(*o) {
return objectID, errors.New("could not write object header")
}
buf := make([]byte, 1024*1024) // 1 MiB
for {
// update progress bar
_, err := (*reader).Read(buf) //could be a file reader for instance .. reader *io.Reader
if !objWriter.WritePayloadChunk(buf) {
break
}
if errors.Is(err, io.EOF) {
break
}
}
res, err := objWriter.Close()
if err != nil {
return objectID, err
}
res.ReadStoredObjectID(&objectID)
}
//the object ID is stored in response.ID()
Depending on your container's permissions you should now be able to view the file you uploaded at:
https://http.testnet.fs.neo.org/CONTAINER_ID/OBJECT_ID
Listing the content of a container
Once you have uploaded objects to a container, you will want to list them out. Listing is a special case of searching within a container. To search for specific objects, you add filters to the search. By setting the only filter as a root filter, it will list everything within the container
var filters = object.SearchFilters{}
filters.AddRootFilter()
search := client.PrmObjectSearch{}
if sessionToken != nil {
search.WithinSession(*sessionToken)
}
if bearerToken != nil {
search.WithBearerToken(*bearerToken)
}
search.SetFilters(filters)
search.InContainer(containerID)
var list []oid.ID
searchInit, err := cli.ObjectSearchInit(ctx,search)
if err != nil {
return list, err
}
err = searchInit.Iterate(func(id oid.ID) bool {
list = append(list, id)
return true
})
fmt.Printf("list objects %+v\n", list)
Retrieve an Object
Once you have the ID of an object, you can download it.
You will need
-
an io.Writer to write the data to a file such as a file writer
-
an object address, which is made up of a container ID and an object ID
To generate an object address from the string forms of a containerID and an objectID:
contID := cid.New()
contID.Parse(containerID)
objID := obj.NewID()
objID.Parse(objectID)
Then use an io.Writer to save the content back to somewhere such as a local file `go dstObject := &object.Object{} getParms := client.PrmObjectGet{} getParms.ByID(objID) getParms.FromContainer(contID) if sessionToken != nil { getParms.WithinSession(*sessionToken) } if bearerToken != nil { getParms.WithBearerToken(*bearerToken) } objReader, err := cli.ObjectGetInit(ctx, getParms) if err != nil { return dstObject, err } if !objReader.ReadHeader(dstObject) { _, err = objReader.Close() return dstObject, err } buf := make([]byte, 1024) // 1 MiB for { if _, writerErr := (*writer).Write(buf); writerErr != nil { return nil, errors.New("error writing to buffer: " + writerErr.Error()) } if _, ok := objReader.ReadChunk(buf); !ok { break } fmt.Printf("* %v\r\n", string(buf)) // get total size from object header and update progress bar based on n bytes received if errors.Is(err, io.EOF) { break } } return dstObject, err
`
Retrieving an objects HEAD/metadata
Sometimes you want information about an object, without actually downloading the entire object, for instance the size of an object
From a container, you can find out storage policies, owners and any other meta information about the container itself. This is very similar to retrieving the object
h := client.PrmObjectHead{}
h.ByID(objectID)
if sessionToken != nil {
h.WithinSession(*sessionToken)
}
if bearerToken != nil {
h.WithBearerToken(*bearerToken)
}
h.FromContainer(containerID)
var o = &object.Object{}
head, err := cli.ObjectHead(ctx, h)
if err != nil {
return o, err
}
response := head.ReadHeader(o)
if !response {
return o, errors.New("could not read the object header. Did not exist")
}
return o, nil
Deleting Objects
You may wish to delete an object for a container
del := client.PrmObjectDelete{}
if sessionToken != nil {
del.WithinSession(*sessionToken)
}
if bearerToken != nil {
del.WithBearerToken(*bearerToken)
}
del.ByID(objectID)
del.FromContainer(containerID)
deleteResponse, err := cli.ObjectDelete(ctx, del)
return deleteResponse, err
Questions about objects
-
Can you update the attributes of an existing object
-
Can you determine the original uploader of an object