Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support format flag to support json content for the head commands #103

Merged
merged 10 commits into from
Nov 23, 2023
70 changes: 65 additions & 5 deletions cmd/cmd_head.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ func cmdHeadObj() *cli.Command {
send headObject txn to chain and fetch object info on greenfield chain
Examples:
$ gnfd-cmd object head gnfd://bucket-name/object-name`,
Flags: []cli.Flag{
&cli.GenericFlag{
Name: formatFlag,
Aliases: []string{"f"},
Value: &CmdEnumValue{
Enum: []string{defaultFormat, jsonFormat},
Default: defaultFormat,
},
Usage: "set format of the return content of plaintxt or json",
},
},
}
}

Expand All @@ -33,6 +44,17 @@ func cmdHeadBucket() *cli.Command {
send headBucket txn to chain and fetch bucket info on greenfield chain
Examples:
$ gnfd-cmd bucket head gnfd://bucket-name`,
Flags: []cli.Flag{
&cli.GenericFlag{
Name: formatFlag,
Aliases: []string{"f"},
Value: &CmdEnumValue{
Enum: []string{defaultFormat, jsonFormat},
Default: defaultFormat,
},
Usage: "set format of the return content of plaintxt or json",
},
},
}
}

Expand All @@ -53,6 +75,15 @@ $ gnfd-cmd group head --groupOwner group-name`,
Value: "",
Usage: "need set the owner address if you are not the owner of the group",
},
&cli.GenericFlag{
Name: formatFlag,
Aliases: []string{"f"},
Value: &CmdEnumValue{
Enum: []string{defaultFormat, jsonFormat},
Default: defaultFormat,
},
Usage: "set format of the return content of plaintxt or json",
},
},
}
}
Expand Down Expand Up @@ -99,7 +130,17 @@ func headObject(ctx *cli.Context) error {
fmt.Println("no such object")
return nil
}
parseChainInfo(objectDetail.ObjectInfo.String(), false)

fmt.Println("latest object info:")
if format := ctx.String(formatFlag); format != "" {
if format == defaultFormat {
parseObjectInfo(objectDetail)
} else if format == jsonFormat {
parseObjectByJsonFormat(objectDetail)
} else {
return toCmdErr(fmt.Errorf("invalid format"))
}
}
return nil
}

Expand All @@ -123,7 +164,16 @@ func headBucket(ctx *cli.Context) error {
return nil
}

parseChainInfo(bucketInfo.String(), true)
fmt.Println("latest bucket info:")
if format := ctx.String(formatFlag); format != "" {
if format == defaultFormat {
parseBucketInfo(bucketInfo)
} else if format == jsonFormat {
parseBucketByJsonFormat(bucketInfo)
} else {
return toCmdErr(fmt.Errorf("invalid format"))
}
}
return nil
}

Expand Down Expand Up @@ -152,10 +202,20 @@ func headGroup(ctx *cli.Context) error {
return nil
}

infoStr := strings.Split(groupInfo.String(), " ")
for _, info := range infoStr {
fmt.Println(info)
fmt.Println("latest group info:")
if format := ctx.String(formatFlag); format != "" {
if format == defaultFormat {
infoStr := strings.Split(groupInfo.String(), " ")
for _, info := range infoStr {
fmt.Println(info)
}
} else if format == jsonFormat {
parseGroupByFormat(groupInfo)
} else {
return toCmdErr(fmt.Errorf("invalid format"))
}
}

return nil
}

Expand Down
23 changes: 20 additions & 3 deletions cmd/cmd_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,17 +372,34 @@ func uploadFolder(urlInfo string, ctx *cli.Context,
if !fileInfo.IsDir() {
return errors.New("failed to parse folder path with recursive flag")
}

baseDir := filepath.Base(folderName)

fileInfos := make([]os.FileInfo, 0)
filePaths := make([]string, 0)
objectNames := make([]string, 0)
listFolderErr := filepath.Walk(folderName, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
fileInfos = append(fileInfos, info)
// use the base dir to construct object name of the file
index := strings.Index(path, baseDir)
if index == -1 {
flywukong marked this conversation as resolved.
Show resolved Hide resolved
return nil
}
objectNames = append(objectNames, path[index:])
filePaths = append(filePaths, path)
} else {
fmt.Println("creating folder:", path)
if createFolderErr := uploadFile(bucketName, path+"/", path, urlInfo, ctx, gnfdClient, true, false, 0); createFolderErr != nil {
// use the base dir to construct object name of the sub-folder
index := strings.Index(path, baseDir)
if index == -1 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

return nil
}
subFolderName := path[index:] + "/"
fmt.Println("creating folder:", subFolderName)
if createFolderErr := uploadFile(bucketName, subFolderName, path, urlInfo, ctx, gnfdClient, true, false, 0); createFolderErr != nil {
return toCmdErr(createFolderErr)
}

}
return nil
})
Expand All @@ -392,7 +409,7 @@ func uploadFolder(urlInfo string, ctx *cli.Context,
}
// upload folder
for id, info := range fileInfos {
if uploadErr := uploadFile(bucketName, filePaths[id], filePaths[id], urlInfo, ctx, gnfdClient, false, false, info.Size()); uploadErr != nil {
if uploadErr := uploadFile(bucketName, objectNames[id], filePaths[id], urlInfo, ctx, gnfdClient, false, false, info.Size()); uploadErr != nil {
fmt.Printf("failed to upload object: %s, error:%v \n", filePaths[id], uploadErr)
}
}
Expand Down
204 changes: 190 additions & 14 deletions cmd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ const (
unsafeFlag = "unsafe"
unarmoredFlag = "unarmoredHex"
passwordFileFlag = "passwordfile"
formatFlag = "format"
defaultFormat = "plaintxt"
jsonFormat = "json"
homeFlag = "home"
keyStoreFlag = "keystore"
configFlag = "config"
Expand Down Expand Up @@ -127,6 +130,37 @@ var (
TxnOptionWithSyncMode = types.TxOption{Mode: &SyncBroadcastMode}
)

type ObjectInfo struct {
ObjectStatus string `json:"object_status"`
Owner string `json:"owner"`
BucketName string `json:"bucket_name"`
ObjectName string `json:"object_name"`
ID string `json:"id"`
LocalVirtualGroupID int `json:"local_virtual_group_id"`
PayloadSize int `json:"payload_size"`
Visibility string `json:"visibility"`
ContentType string `json:"content_type"`
CreateAt string `json:"create_at"`
Checksums map[string]string `json:"checksums"`
}

type BucketInfo struct {
Owner string `json:"owner"`
BucketName string `json:"bucket_name"`
Visibility string `json:"visibility"`
ID string `json:"id"`
CreateAt string `json:"create_at"`
PaymentAddress string `json:"payment_address"`
GlobalVirtualGroupFamilyID int `json:"global_virtual_group_family_id"`
BucketStatus string `json:"bucket_status"`
}

type GroupInfo struct {
Owner string `json:"owner"`
GroupName string `json:"group_name"`
ID string `json:"id"`
}

type CmdEnumValue struct {
Enum []string
Default string
Expand Down Expand Up @@ -173,28 +207,170 @@ func toCmdErr(err error) error {
return nil
}

// parse bucket info or object info meta on the chain
func parseChainInfo(info string, isBucketInfo bool) {
if isBucketInfo {
fmt.Println("latest bucket info:")
} else {
fmt.Println("latest object info:")
// parse object info meta on the chain
func parseObjectInfo(objectDetail *sdktypes.ObjectDetail) {
info := objectDetail.ObjectInfo.String()
fmt.Println("object_status:", objectDetail.ObjectInfo.ObjectStatus)
infoStr := strings.Split(info, " ")
checksumID := 0
for _, objInfo := range infoStr {
if strings.Contains(objInfo, "create_at:") {
timeInfo := strings.Split(objInfo, ":")
timestamp, _ := strconv.ParseInt(timeInfo[1], 10, 64)
location, _ := time.LoadLocation("Asia/Shanghai")
t := time.Unix(timestamp, 0).In(location)
objInfo = timeInfo[0] + ":" + t.Format(iso8601DateFormat)
}
if strings.Contains(objInfo, "checksums:") {
if checksumID == 0 {
fmt.Println("checksums:")
}
hashInfo := strings.Split(objInfo, ":")
objInfo = hashInfo[0] + "[" + strconv.Itoa(checksumID) + "]" + ":" + hex.EncodeToString([]byte(hashInfo[1]))
checksumID++
}
if strings.Contains(objInfo, "status") {
continue
}
fmt.Println(objInfo)
}
}

func parseObjectByJsonFormat(objectDetail *sdktypes.ObjectDetail) {
info := objectDetail.ObjectInfo.String()
objectInfo := ObjectInfo{
ObjectStatus: objectDetail.ObjectInfo.ObjectStatus.String(),
Checksums: make(map[string]string),
}
infoStr := strings.Split(info, " ")
for _, info := range infoStr {
if strings.Contains(info, "create_at:") {
timeInfo := strings.Split(info, ":")
checksumID := 0
for _, objInfo := range infoStr {
if strings.Contains(objInfo, "create_at:") {
timeInfo := strings.Split(objInfo, ":")
timestamp, _ := strconv.ParseInt(timeInfo[1], 10, 64)
location, _ := time.LoadLocation("Asia/Shanghai")
t := time.Unix(timestamp, 0).In(location)
objectInfo.CreateAt = t.Format(iso8601DateFormat)
}
if strings.Contains(objInfo, "checksums:") {
hashInfo := strings.Split(objInfo, ":")
objectInfo.Checksums["checksum["+strconv.Itoa(checksumID)+"]"] = hex.EncodeToString([]byte(hashInfo[1]))
checksumID++
}
if strings.Contains(objInfo, "status") {
continue
}
keyValue := strings.Split(objInfo, ":")
if len(keyValue) == 2 {
switch keyValue[0] {
case "owner":
objectInfo.Owner = keyValue[1]
case "bucket_name":
objectInfo.BucketName = keyValue[1]
case "object_name":
objectInfo.ObjectName = keyValue[1]
case "id":
objectInfo.ID = keyValue[1]
case "local_virtual_group_id":
groupID, _ := strconv.Atoi(keyValue[1])
objectInfo.LocalVirtualGroupID = groupID
case "payload_size":
payloadSize, _ := strconv.Atoi(keyValue[1])
objectInfo.PayloadSize = payloadSize
case "visibility":
objectInfo.Visibility = keyValue[1]
case "content_type":
objectInfo.ContentType = keyValue[1]
default:
continue
}
}
}
jsonData, err := json.Marshal(objectInfo)
if err != nil {
fmt.Println("Error marshalling to JSON:", err)
return
}
fmt.Println(string(jsonData))
}

func parseBucketInfo(info *storageTypes.BucketInfo) {
fmt.Println("bucket_status:", info.BucketStatus.String())
infoStr := strings.Split(info.String(), " ")
for _, bucketInfo := range infoStr {
if strings.Contains(bucketInfo, "create_at:") {
timeInfo := strings.Split(bucketInfo, ":")
timestamp, _ := strconv.ParseInt(timeInfo[1], 10, 64)
location, _ := time.LoadLocation("Asia/Shanghai")
t := time.Unix(timestamp, 0).In(location)
info = timeInfo[0] + ":" + t.Format(iso8601DateFormat)
bucketInfo = timeInfo[0] + ":" + t.Format(iso8601DateFormat)
}
fmt.Println(bucketInfo)
}
}

func parseBucketByJsonFormat(info *storageTypes.BucketInfo) {
infoStr := strings.Split(info.String(), " ")
bucketInfo := BucketInfo{}
bucketInfo.BucketStatus = info.BucketStatus.String()
for _, entry := range infoStr {
keyValue := strings.Split(entry, ":")
if len(keyValue) == 2 {
key := strings.TrimSpace(keyValue[0])
value := strings.TrimSpace(keyValue[1])
switch key {
case "owner":
bucketInfo.Owner = value
case "bucket_name":
bucketInfo.BucketName = value
case "visibility":
bucketInfo.Visibility = value
case "id":
bucketInfo.ID = value
case "create_at":
bucketInfo.CreateAt = value
case "payment_address":
bucketInfo.PaymentAddress = value
case "global_virtual_group_family_id":
id, _ := strconv.Atoi(value)
bucketInfo.GlobalVirtualGroupFamilyID = id
flywukong marked this conversation as resolved.
Show resolved Hide resolved
}
}
if strings.Contains(info, "checksums:") {
hashInfo := strings.Split(info, ":")
info = hashInfo[0] + ":" + hex.EncodeToString([]byte(hashInfo[1]))
}

jsonData, err := json.Marshal(bucketInfo)
if err != nil {
fmt.Println("Error marshalling to JSON:", err)
return
}
fmt.Println(string(jsonData))
}

func parseGroupByFormat(info *storageTypes.GroupInfo) {
infoStr := strings.Split(info.String(), " ")
groupInfo := GroupInfo{}
for _, entry := range infoStr {
keyValue := strings.Split(entry, ":")
if len(keyValue) == 2 {
key := strings.TrimSpace(keyValue[0])
value := strings.TrimSpace(keyValue[1])
switch key {
case "owner":
groupInfo.Owner = value
case "group_name":
groupInfo.GroupName = value
case "id":
groupInfo.ID = value
}
}
fmt.Println(info)
}

jsonData, err := json.Marshal(groupInfo)
if err != nil {
fmt.Println("Error marshalling to JSON:", err)
return
}
fmt.Println(string(jsonData))
}

func getBucketNameByUrl(ctx *cli.Context) (string, error) {
Expand Down
Loading