Merge pull request #8214 from rhafer/stable-5-merge

Merge master into stable-5.0
This commit is contained in:
Michael Barz
2024-01-16 15:58:53 +01:00
committed by GitHub
63 changed files with 2453 additions and 1421 deletions

8
go.mod
View File

@@ -47,7 +47,7 @@ require (
github.com/google/go-cmp v0.6.0
github.com/google/go-tika v0.3.0
github.com/google/uuid v1.5.0
github.com/gookit/config/v2 v2.2.4
github.com/gookit/config/v2 v2.2.5
github.com/gorilla/mux v1.8.1
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0
github.com/jellydator/ttlcache/v2 v2.11.1
@@ -61,7 +61,7 @@ require (
github.com/mna/pigeon v1.2.1
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/nats-io/nats-server/v2 v2.10.9
github.com/nats-io/nats.go v1.31.0
github.com/nats-io/nats.go v1.32.0
github.com/oklog/run v1.1.0
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.16.5
@@ -69,7 +69,7 @@ require (
github.com/onsi/gomega v1.30.0
github.com/open-policy-agent/opa v0.60.0
github.com/orcaman/concurrent-map v1.0.0
github.com/owncloud/libre-graph-api-go v1.0.5-0.20231201125350-a08244876423
github.com/owncloud/libre-graph-api-go v1.0.5-0.20240115110609-b018a896364e
github.com/pkg/errors v0.9.1
github.com/pkg/xattr v0.4.9
github.com/prometheus/client_golang v1.18.0
@@ -223,7 +223,7 @@ require (
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/renameio/v2 v2.0.0 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/gookit/goutil v0.6.14 // indirect
github.com/gookit/goutil v0.6.15 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/schema v1.2.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect

20
go.sum
View File

@@ -1423,12 +1423,12 @@ github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gookit/config/v2 v2.2.4 h1:uLHNzFzREe5gDBP4Gb1+WOC9LB6vauPvq4eolp32Dcg=
github.com/gookit/config/v2 v2.2.4/go.mod h1:k1ofSAuJnW6n1kTriFMSzFDC8ZT20tAPQ+1iGI3QOrU=
github.com/gookit/goutil v0.6.14 h1:96elyOG4BvVoDaiT7vx1vHPrVyEtFfYlPPBODR0/FGQ=
github.com/gookit/goutil v0.6.14/go.mod h1:YyDBddefmjS+mU2PDPgCcjVzTDM5WgExiDv5ZA/b8I8=
github.com/gookit/ini/v2 v2.2.2 h1:3B8abZJrVH1vi/7TU4STuTBxdhiAq1ORSt6NJZCahaI=
github.com/gookit/ini/v2 v2.2.2/go.mod h1:wGEfnBxv+7nVXytWM44tiqczv5hLKJ+m9MaA2uJg3iM=
github.com/gookit/config/v2 v2.2.5 h1:RECbYYbtherywmzn3LNeu9NA5ZqhD7MSKEMsJ7l+MpU=
github.com/gookit/config/v2 v2.2.5/go.mod h1:NeX+yiNYn6Ei10eJvCQFXuHEPIE/IPS8bqaFIsszzaM=
github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo=
github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY=
github.com/gookit/ini/v2 v2.2.3 h1:nSbN+x9OfQPcMObTFP+XuHt8ev6ndv/fWWqxFhPMu2E=
github.com/gookit/ini/v2 v2.2.3/go.mod h1:Vu6p7P7xcfmb8KYu3L0ek8bqu/Im63N81q208SCCZY4=
github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
github.com/gophercloud/gophercloud v0.16.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae/go.mod h1:wx8HMD8oQD0Ryhz6+6ykq75PJ79iPyEqYHfwZ4l7OsA=
@@ -1744,8 +1744,8 @@ github.com/nats-io/jwt/v2 v2.5.3 h1:/9SWvzc6hTfamcgXJ3uYRpgj+QuY2aLNqRiqrKcrpEo=
github.com/nats-io/jwt/v2 v2.5.3/go.mod h1:iysuPemFcc7p4IoYots3IuELSI4EDe9Y0bQMe+I3Bf4=
github.com/nats-io/nats-server/v2 v2.10.9 h1:VEW43Zz+p+9lARtiPM9ctd6ckun+92ZT2T17HWtwiFI=
github.com/nats-io/nats-server/v2 v2.10.9/go.mod h1:oorGiV9j3BOLLO3ejQe+U7pfAGyPo+ppD7rpgNF6KTQ=
github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E=
github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8=
github.com/nats-io/nats.go v1.32.0 h1:Bx9BZS+aXYlxW08k8Gd3yR2s73pV5XSoAQUyp1Kwvp0=
github.com/nats-io/nats.go v1.32.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
@@ -1789,8 +1789,8 @@ github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35uk
github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY=
github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
github.com/owncloud/libre-graph-api-go v1.0.5-0.20231201125350-a08244876423 h1:G3i2n+lY6cTEerVEearRliEGeAxFuFQN0qM/1mdCQvs=
github.com/owncloud/libre-graph-api-go v1.0.5-0.20231201125350-a08244876423/go.mod h1:v2aAl5IwEI8t+GmcWvBd+bvJMYp9Vf1hekLuRf0UnEs=
github.com/owncloud/libre-graph-api-go v1.0.5-0.20240115110609-b018a896364e h1:Y7MEJYsPe+UGlmU7oR9LaBIsQQYTwCq4a/p0JCia2cA=
github.com/owncloud/libre-graph-api-go v1.0.5-0.20240115110609-b018a896364e/go.mod h1:v2aAl5IwEI8t+GmcWvBd+bvJMYp9Vf1hekLuRf0UnEs=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=

View File

@@ -3,17 +3,20 @@ package svc
import (
"context"
"net/http"
"strings"
"reflect"
"slices"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/go-chi/render"
libregraph "github.com/owncloud/libre-graph-api-go"
"golang.org/x/sync/errgroup"
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
"github.com/owncloud/ocis/v2/services/graph/pkg/identity"
"github.com/owncloud/ocis/v2/services/graph/pkg/unifiedrole"
)
// ListSharedWithMe lists the files shared with the current user.
@@ -30,6 +33,7 @@ func (g Graph) ListSharedWithMe(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, &ListResponse{Value: driveItems})
}
// listSharedWithMe is a helper function that lists the drive items shared with the current user.
func (g Graph) listSharedWithMe(ctx context.Context) ([]libregraph.DriveItem, error) {
gatewayClient, err := g.gatewaySelector.Next()
if err != nil {
@@ -38,189 +42,305 @@ func (g Graph) listSharedWithMe(ctx context.Context) ([]libregraph.DriveItem, er
}
listReceivedSharesResponse, err := gatewayClient.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{})
if err != nil {
if errCode := errorcode.FromCS3Status(listReceivedSharesResponse.GetStatus(), err); errCode != nil {
g.logger.Error().Err(err).Msg("listing shares failed")
return nil, errorcode.New(errorcode.GeneralException, err.Error())
return nil, *errCode
}
switch listReceivedSharesResponse.Status.Code {
case rpc.Code_CODE_NOT_FOUND:
return nil, identity.ErrNotFound
// doStat is a helper function that stat a resource.
doStat := func(resourceId *storageprovider.ResourceId) (*storageprovider.StatResponse, error) {
shareStat, err := gatewayClient.Stat(ctx, &storageprovider.StatRequest{
Ref: &storageprovider.Reference{ResourceId: resourceId},
})
switch errCode := errorcode.FromCS3Status(shareStat.GetStatus(), err); {
case errCode == nil:
break
// skip ItemNotFound shares, they might have been deleted in the meantime or orphans.
case errCode.GetCode() == errorcode.ItemNotFound:
return nil, nil
default:
g.logger.Error().Err(errCode).Msg("could not stat")
return nil, errCode
}
return shareStat, nil
}
var driveItems []libregraph.DriveItem
for _, receivedShare := range listReceivedSharesResponse.GetShares() {
share := receivedShare.GetShare()
if share == nil {
g.logger.Error().Interface("ListReceivedShares", listReceivedSharesResponse).Msg("unexpected empty ReceivedShare.Share")
continue
}
group := new(errgroup.Group)
receivedShares := listReceivedSharesResponse.GetShares()
driveItems := make([]libregraph.DriveItem, len(receivedShares))
driveItem := &libregraph.DriveItem{}
for i, receivedShare := range receivedShares {
i, receivedShare := i, receivedShare
statResponse, err := gatewayClient.Stat(ctx, &storageprovider.StatRequest{Ref: &storageprovider.Reference{ResourceId: share.GetResourceId()}})
if err != nil {
g.logger.Error().Err(err).Msg("could not stat")
continue
}
if statResponse.GetStatus().GetCode() != rpc.Code_CODE_OK {
g.logger.Error().Err(err).Msg("invalid stat response")
continue
}
resourceInfo := statResponse.GetInfo()
var driveOwner *libregraph.Identity
if userID := statResponse.GetInfo().GetOwner(); userID != nil {
if user, err := g.identityCache.GetUser(ctx, userID.GetOpaqueId()); err != nil {
g.logger.Error().Err(err).Msg("could not get user")
continue
} else {
driveOwner = &libregraph.Identity{
DisplayName: user.GetDisplayName(),
Id: libregraph.PtrString(user.GetId()),
}
}
}
var shareCreator *libregraph.Identity
if userID := share.GetCreator(); userID != nil {
if user, err := g.identityCache.GetUser(ctx, userID.GetOpaqueId()); err != nil {
g.logger.Error().Err(err).Msg("could not get user")
continue
} else {
shareCreator = &libregraph.Identity{
DisplayName: user.GetDisplayName(),
Id: libregraph.PtrString(user.GetId()),
}
}
}
if cTime := share.GetCtime(); cTime != nil {
driveItem.CreatedDateTime = libregraph.PtrTime(cs3TimestampToTime(cTime))
}
driveItem.ETag = libregraph.PtrString(strings.Trim(statResponse.GetInfo().GetEtag(), "\""))
if id := share.GetId().GetOpaqueId(); id != "" {
driveItem.Id = libregraph.PtrString(id)
}
if mTime := share.GetMtime(); mTime != nil {
driveItem.LastModifiedDateTime = libregraph.PtrTime(cs3TimestampToTime(mTime))
}
if name := resourceInfo.GetName(); name != "" {
driveItem.Name = libregraph.PtrString(name)
}
{
addParentReference := false
parentReference := &libregraph.ItemReference{}
if id := share.GetId().GetOpaqueId(); id != "" {
parentReference.DriveId = libregraph.PtrString(id)
addParentReference = true
group.Go(func() error {
shareStat, err := doStat(receivedShare.GetShare().GetResourceId())
if shareStat == nil || err != nil {
return err
}
if addParentReference {
driveItem.ParentReference = parentReference
}
}
{
remoteItem := &libregraph.RemoteItem{}
if id := resourceInfo.GetId(); id != nil {
remoteItem.Id = libregraph.PtrString(storagespace.FormatResourceID(*id))
}
if mTime := resourceInfo.GetMtime(); mTime != nil {
remoteItem.LastModifiedDateTime = libregraph.PtrTime(cs3TimestampToTime(mTime))
}
if name := resourceInfo.GetName(); name != "" {
remoteItem.Name = libregraph.PtrString(name)
}
// fixMe:
// - negative permission could distort the size, am i right?
remoteItem.Size = libregraph.PtrInt64(int64(resourceInfo.GetSize()))
remoteItem.CreatedBy = &libregraph.IdentitySet{
User: driveOwner,
permission, err := g.cs3ReceivedShareToLibreGraphPermissions(ctx, receivedShare, shareStat.GetInfo())
if err != nil {
return err
}
shared := libregraph.NewShared()
{
addFileSystemInfo := false
fileSystemInfo := &libregraph.FileSystemInfo{}
if cTime := share.GetCtime(); cTime != nil {
// fixMe:
// - ms uses the root resource ctime for that,
// the stat response does not contain any information about this, use share instead?
fileSystemInfo.CreatedDateTime = libregraph.PtrTime(cs3TimestampToTime(cTime))
addFileSystemInfo = true
}
if mTime := resourceInfo.GetMtime(); mTime != nil {
fileSystemInfo.LastModifiedDateTime = libregraph.PtrTime(cs3TimestampToTime(mTime))
addFileSystemInfo = true
}
if addFileSystemInfo {
remoteItem.FileSystemInfo = fileSystemInfo
if cTime := receivedShare.GetShare().GetCtime(); cTime != nil {
shared.SetSharedDateTime(cs3TimestampToTime(cTime))
}
}
switch resourceInfo.GetType() {
case storageprovider.ResourceType_RESOURCE_TYPE_CONTAINER:
remoteItem.Folder = &libregraph.Folder{}
case storageprovider.ResourceType_RESOURCE_TYPE_FILE:
openGraphFile := &libregraph.OpenGraphFile{}
if mimeType := resourceInfo.GetMimeType(); mimeType != "" {
openGraphFile.MimeType = libregraph.PtrString(mimeType)
}
remoteItem.File = openGraphFile
case storageprovider.ResourceType_RESOURCE_TYPE_INVALID:
g.logger.Error().Msg("invalid resource type")
continue
}
remoteItem := libregraph.NewRemoteItem()
{
addShared := false
shared := &libregraph.Shared{
Owner: &libregraph.IdentitySet{
User: shareCreator,
},
SharedBy: &libregraph.IdentitySet{
User: shareCreator,
},
if id := shareStat.GetInfo().GetId(); id != nil {
remoteItem.SetId(storagespace.FormatResourceID(*id))
}
if cTime := share.GetCtime(); cTime != nil {
shared.SharedDateTime = libregraph.PtrTime(cs3TimestampToTime(cTime))
addShared = true
if name := shareStat.GetInfo().GetName(); name != "" {
remoteItem.SetName(name)
}
if shareCreator != nil {
shared.Owner.User = shareCreator
shared.SharedBy.User = shareCreator
addShared = true
if etag := shareStat.GetInfo().GetEtag(); etag != "" {
remoteItem.SetETag(etag)
}
if addShared {
if mTime := shareStat.GetInfo().GetMtime(); mTime != nil {
remoteItem.SetLastModifiedDateTime(cs3TimestampToTime(mTime))
}
if size := shareStat.GetInfo().GetSize(); size != 0 {
remoteItem.SetSize(int64(size))
}
parentReference := libregraph.NewItemReference()
if spaceType := shareStat.GetInfo().GetSpace().GetSpaceType(); spaceType != "" {
parentReference.SetDriveType(spaceType)
}
if root := shareStat.GetInfo().GetSpace().GetRoot(); root != nil {
parentReference.SetDriveId(storagespace.FormatResourceID(*root))
}
if !reflect.ValueOf(*parentReference).IsZero() {
remoteItem.ParentReference = parentReference
}
}
driveItem := libregraph.NewDriveItem()
// handle share state related stuff
switch receivedShare.GetState() {
case collaboration.ShareState_SHARE_STATE_ACCEPTED:
driveItem.SetId(storagespace.FormatResourceID(storageprovider.ResourceId{
StorageId: utils.ShareStorageProviderID,
OpaqueId: receivedShare.GetShare().GetId().GetOpaqueId(),
SpaceId: utils.ShareStorageSpaceID,
}))
if name := receivedShare.GetMountPoint().GetPath(); name != "" {
driveItem.SetName(receivedShare.GetMountPoint().GetPath())
}
if etag := shareStat.GetInfo().GetEtag(); etag != "" {
driveItem.SetETag(etag)
}
// parentReference of the out driveItem should be the drive containing the mountpoint
// i.e. the share jail
driveItem.ParentReference = libregraph.NewItemReference()
driveItem.ParentReference.SetDriveType("virtual")
driveItem.ParentReference.SetDriveId(storagespace.FormatStorageID(utils.ShareStorageProviderID, utils.ShareStorageSpaceID))
driveItem.ParentReference.SetId(storagespace.FormatResourceID(storageprovider.ResourceId{
StorageId: utils.ShareStorageProviderID,
OpaqueId: utils.ShareStorageSpaceID,
SpaceId: utils.ShareStorageSpaceID,
}))
case collaboration.ShareState_SHARE_STATE_PENDING:
fallthrough
case collaboration.ShareState_SHARE_STATE_REJECTED:
if name := shareStat.GetInfo().GetName(); name != "" {
driveItem.SetName(name)
}
}
// connect the dots
{
if mTime := shareStat.GetInfo().GetMtime(); mTime != nil {
t := cs3TimestampToTime(mTime)
driveItem.SetLastModifiedDateTime(t)
remoteItem.SetLastModifiedDateTime(t)
}
if size := shareStat.GetInfo().GetSize(); size != 0 {
s := int64(size)
driveItem.SetSize(s)
remoteItem.SetSize(s)
}
if userID := shareStat.GetInfo().GetOwner(); userID != nil {
user, err := g.identityCache.GetUser(ctx, userID.GetOpaqueId())
if err != nil {
g.logger.Error().Err(err).Msg("could not get user")
return err
}
identitySet := libregraph.IdentitySet{
User: &libregraph.Identity{
DisplayName: user.GetDisplayName(),
Id: libregraph.PtrString(user.GetId()),
},
}
remoteItem.SetCreatedBy(identitySet)
driveItem.SetCreatedBy(identitySet)
}
if userID := receivedShare.GetShare().GetOwner(); userID != nil {
user, err := g.identityCache.GetUser(ctx, userID.GetOpaqueId())
if err != nil {
g.logger.Error().Err(err).Msg("could not get user")
return err
}
identitySet := libregraph.IdentitySet{
User: &libregraph.Identity{
DisplayName: user.GetDisplayName(),
Id: libregraph.PtrString(user.GetId()),
},
}
shared.SetOwner(identitySet)
}
if userID := receivedShare.GetShare().GetCreator(); userID != nil {
user, err := g.identityCache.GetUser(ctx, userID.GetOpaqueId())
if err != nil {
g.logger.Error().Err(err).Msg("could not get user")
return err
}
identitySet := libregraph.IdentitySet{
User: &libregraph.Identity{
DisplayName: user.GetDisplayName(),
Id: libregraph.PtrString(user.GetId()),
},
}
shared.SetSharedBy(identitySet)
}
switch info := shareStat.GetInfo(); {
case info.GetType() == storageprovider.ResourceType_RESOURCE_TYPE_CONTAINER:
folder := libregraph.NewFolder()
remoteItem.Folder = folder
driveItem.Folder = folder
case info.GetType() == storageprovider.ResourceType_RESOURCE_TYPE_FILE:
file := libregraph.NewOpenGraphFile()
if mimeType := info.GetMimeType(); mimeType != "" {
file.MimeType = &mimeType
}
remoteItem.File = file
driveItem.File = file
}
if !reflect.ValueOf(*shared).IsZero() {
remoteItem.Shared = shared
}
if !reflect.ValueOf(*permission).IsZero() {
permissions := []libregraph.Permission{*permission}
remoteItem.Permissions = permissions
}
if !reflect.ValueOf(*remoteItem).IsZero() {
driveItem.RemoteItem = remoteItem
}
}
driveItem.RemoteItem = remoteItem
}
driveItems[i] = *driveItem
driveItems = append(driveItems, *driveItem)
return nil
})
}
return driveItems, nil
// wait for concurrent requests to finish
err = group.Wait()
// filter out empty drive items
return slices.Clip(slices.DeleteFunc(driveItems, func(item libregraph.DriveItem) bool {
return reflect.ValueOf(item).IsZero()
})), err
}
func (g Graph) cs3ReceivedShareToLibreGraphPermissions(ctx context.Context, receivedShare *collaboration.ReceivedShare, shareStatInfo *storageprovider.ResourceInfo) (*libregraph.Permission, error) {
permission := libregraph.NewPermission()
if id := receivedShare.GetShare().GetId().GetOpaqueId(); id != "" {
permission.SetId(id)
}
if expiration := receivedShare.GetShare().GetExpiration(); expiration != nil {
permission.SetExpirationDateTime(cs3TimestampToTime(expiration))
}
if permissionSet := shareStatInfo.GetPermissionSet(); permissionSet != nil {
role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(
*permissionSet,
unifiedrole.UnifiedRoleConditionGrantee,
g.config.FilesSharing.EnableResharing,
)
if role != nil {
permission.SetRoles([]string{role.GetId()})
}
actions := unifiedrole.CS3ResourcePermissionsToLibregraphActions(*permissionSet)
// actions only make sense if no role is set
if role == nil && len(actions) > 0 {
permission.SetLibreGraphPermissionsActions(actions)
}
}
switch grantee := receivedShare.GetShare().GetGrantee(); {
case grantee.GetType() == storageprovider.GranteeType_GRANTEE_TYPE_USER:
user, err := g.identityCache.GetUser(ctx, grantee.GetUserId().GetOpaqueId())
if err != nil {
g.logger.Error().Err(err).Msg("could not get user")
return nil, err
}
permission.SetGrantedToV2(libregraph.SharePointIdentitySet{
User: &libregraph.Identity{
DisplayName: user.GetDisplayName(),
Id: user.Id,
},
})
case grantee.GetType() == storageprovider.GranteeType_GRANTEE_TYPE_GROUP:
group, err := g.identityCache.GetGroup(ctx, grantee.GetGroupId().GetOpaqueId())
if err != nil {
g.logger.Error().Err(err).Msg("could not get group")
return nil, err
}
permission.SetGrantedToV2(libregraph.SharePointIdentitySet{
Group: &libregraph.Identity{
DisplayName: group.GetDisplayName(),
Id: group.Id,
},
})
}
permission.SetUiHidden(receivedShare.GetHidden())
permission.SetClientSynchronize(receivedShare.GetState() == collaboration.ShareState_SHARE_STATE_ACCEPTED)
return permission, nil
}

View File

@@ -11,6 +11,7 @@ import (
collaborationv1beta1 "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
roleconversions "github.com/cs3org/reva/v2/pkg/conversions"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/storagespace"
@@ -28,6 +29,7 @@ import (
"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
identitymocks "github.com/owncloud/ocis/v2/services/graph/pkg/identity/mocks"
service "github.com/owncloud/ocis/v2/services/graph/pkg/service/v0"
"github.com/owncloud/ocis/v2/services/graph/pkg/unifiedrole"
)
var _ = Describe("SharedWithMe", func() {
@@ -72,9 +74,11 @@ var _ = Describe("SharedWithMe", func() {
Describe("ListSharedWithMe", func() {
var (
listReceivedSharesResponse *collaborationv1beta1.ListReceivedSharesResponse
statResponse *providerv1beta1.StatResponse
getUserResponse *userv1beta1.GetUserResponse
listReceivedSharesResponse *collaborationv1beta1.ListReceivedSharesResponse
statResponse *providerv1beta1.StatResponse
getUserResponseDefault *userv1beta1.GetUserResponse
getUserResponseResourceCreator *userv1beta1.GetUserResponse
getUserResponseShareCreator *userv1beta1.GetUserResponse
)
toResourceID := func(in string) *providerv1beta1.ResourceId {
@@ -86,7 +90,7 @@ var _ = Describe("SharedWithMe", func() {
BeforeEach(func() {
getUserResponse = &userv1beta1.GetUserResponse{
getUserResponseDefault = &userv1beta1.GetUserResponse{
Status: status.NewOK(ctx),
User: &userv1beta1.User{
Id: &userv1beta1.UserId{
@@ -95,13 +99,51 @@ var _ = Describe("SharedWithMe", func() {
DisplayName: "John Romero",
},
}
getUserResponseResourceCreator = &userv1beta1.GetUserResponse{
Status: status.NewOK(ctx),
User: &userv1beta1.User{
Id: &userv1beta1.UserId{
OpaqueId: "resource-creator-id",
},
DisplayName: "Resource Creator",
},
}
getUserResponseShareCreator = &userv1beta1.GetUserResponse{
Status: status.NewOK(ctx),
User: &userv1beta1.User{
Id: &userv1beta1.UserId{
OpaqueId: "share-creator-id",
},
DisplayName: "Share Creator",
},
}
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
gatewayClient.On("GetUser", mock.Anything, mock.MatchedBy(
func(req *userv1beta1.GetUserRequest) bool {
return req.UserId.OpaqueId == "resource-creator-id"
})).
Return(getUserResponseResourceCreator, nil)
gatewayClient.On("GetUser", mock.Anything, mock.MatchedBy(
func(req *userv1beta1.GetUserRequest) bool {
return req.UserId.OpaqueId == "share-creator-id"
})).
Return(getUserResponseShareCreator, nil)
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponseDefault, nil)
listReceivedSharesResponse = &collaborationv1beta1.ListReceivedSharesResponse{
Status: status.NewOK(ctx),
Shares: []*collaborationv1beta1.ReceivedShare{
{Share: &collaborationv1beta1.Share{ResourceId: toResourceID("1$2!3")}},
{
Share: &collaborationv1beta1.Share{ResourceId: toResourceID("1$2!3")},
MountPoint: &providerv1beta1.Reference{
ResourceId: &providerv1beta1.ResourceId{
StorageId: utils.ShareStorageProviderID,
SpaceId: utils.ShareStorageSpaceID,
},
Path: "some folder",
},
State: collaborationv1beta1.ShareState_SHARE_STATE_ACCEPTED,
},
},
}
@@ -142,23 +184,7 @@ var _ = Describe("SharedWithMe", func() {
Expect(tape.Code, errorcode.ItemNotFound)
})
It("ignores hidden received shares by default", func() {
listReceivedSharesResponse.Shares = append(listReceivedSharesResponse.Shares, &collaborationv1beta1.ReceivedShare{
Hidden: true,
})
svc.ListSharedWithMe(
tape,
httptest.NewRequest(http.MethodGet, "/graph/v1beta1/me/drive/sharedWithMe", nil),
)
jsonData := gjson.Get(tape.Body.String(), "value")
Expect(len(listReceivedSharesResponse.Shares)).To(Equal(2))
Expect(jsonData.Get("#").Num).To(Equal(float64(1)))
})
It("includes hidden shares if explicitly stated", func() {
It("includes hidden shares", func() {
listReceivedSharesResponse.Shares = append(listReceivedSharesResponse.Shares, &collaborationv1beta1.ReceivedShare{
Hidden: true,
Share: &collaborationv1beta1.Share{
@@ -168,7 +194,7 @@ var _ = Describe("SharedWithMe", func() {
svc.ListSharedWithMe(
tape,
httptest.NewRequest(http.MethodGet, "/graph/v1beta1/me/drive/sharedWithMe?show-hidden=true", nil),
httptest.NewRequest(http.MethodGet, "/graph/v1beta1/me/drive/sharedWithMe", nil),
)
jsonData := gjson.Get(tape.Body.String(), "value")
@@ -181,14 +207,19 @@ var _ = Describe("SharedWithMe", func() {
share := listReceivedSharesResponse.Shares[0].Share
share.Id = &collaborationv1beta1.ShareId{OpaqueId: "1:2:3"}
share.Ctime = &typesv1beta1.Timestamp{Seconds: 4000}
share.Mtime = &typesv1beta1.Timestamp{Seconds: 40000}
etag := "5ffb8e4bec7026050af7fde9482b289a"
share.Ctime = &typesv1beta1.Timestamp{Seconds: 4001}
share.Mtime = &typesv1beta1.Timestamp{Seconds: 4002}
share.Creator = &userv1beta1.UserId{
OpaqueId: "share-creator-id",
}
resourceInfo := statResponse.Info
resourceInfo.Name = "some folder"
resourceInfo.Etag = "\"" + etag + "\""
resourceInfo.Etag = "\"5ffb8e4bec7026050af7fde9482b289a\""
resourceInfo.Owner = &userv1beta1.UserId{
OpaqueId: "resource-creator-id",
}
resourceInfo.Mtime = &typesv1beta1.Timestamp{Seconds: 40000}
svc.ListSharedWithMe(
tape,
@@ -197,11 +228,18 @@ var _ = Describe("SharedWithMe", func() {
jsonData := gjson.Get(tape.Body.String(), "value.0")
Expect(jsonData.Get("createdDateTime").String()).To(Equal(utils.TSToTime(share.Ctime).Format(time.RFC3339Nano)))
Expect(jsonData.Get("eTag").String()).To(Equal(etag))
Expect(jsonData.Get("id").String()).To(Equal(share.Id.OpaqueId))
Expect(jsonData.Get("lastModifiedDateTime").String()).To(Equal(utils.TSToTime(share.Mtime).Format(time.RFC3339Nano)))
Expect(jsonData.Get("eTag").String()).To(Equal(resourceInfo.Etag))
Expect(jsonData.Get("id").String()).To(Equal(storagespace.FormatResourceID(
providerv1beta1.ResourceId{
StorageId: utils.ShareStorageProviderID,
SpaceId: utils.ShareStorageSpaceID,
OpaqueId: share.Id.OpaqueId,
},
)))
Expect(jsonData.Get("lastModifiedDateTime").String()).To(Equal(utils.TSToTime(resourceInfo.Mtime).Format(time.RFC3339Nano)))
Expect(jsonData.Get("createdBy.user.id").String()).To(Equal(resourceInfo.Owner.OpaqueId))
Expect(jsonData.Get("name").String()).To(Equal(resourceInfo.Name))
})
It("populates the driveItem parentReference properties", func() {
@@ -215,17 +253,20 @@ var _ = Describe("SharedWithMe", func() {
jsonData := gjson.Get(tape.Body.String(), "value.0.parentReference")
Expect(jsonData.Get("driveId").String()).To(Equal(share.Id.OpaqueId))
Expect(jsonData.Get("driveId").String()).To(Equal(storagespace.FormatStorageID(utils.ShareStorageProviderID, utils.ShareStorageSpaceID)))
})
It("populates the driveItem remoteItem properties", func() {
share := listReceivedSharesResponse.Shares[0].Share
share.Id = &collaborationv1beta1.ShareId{OpaqueId: "1:2:3"}
share.Ctime = &typesv1beta1.Timestamp{Seconds: 4001}
share.Mtime = &typesv1beta1.Timestamp{Seconds: 40002}
resourceInfo := statResponse.Info
resourceInfo.Name = "some folder"
resourceInfo.Mtime = &typesv1beta1.Timestamp{Seconds: 40000}
resourceInfo.Size = 500
resourceInfo.Etag = "\"5ffb8e4bec7026050af7fde9482b289a\""
svc.ListSharedWithMe(
tape,
@@ -234,6 +275,7 @@ var _ = Describe("SharedWithMe", func() {
jsonData := gjson.Get(tape.Body.String(), "value.0.remoteItem")
Expect(jsonData.Get("eTag").String()).To(Equal(resourceInfo.Etag))
Expect(jsonData.Get("id").String()).To(Equal(storagespace.FormatResourceID(*share.ResourceId)))
Expect(jsonData.Get("lastModifiedDateTime").String()).To(Equal(utils.TSToTime(resourceInfo.Mtime).Format(time.RFC3339Nano)))
Expect(jsonData.Get("name").String()).To(Equal(resourceInfo.Name))
@@ -241,7 +283,7 @@ var _ = Describe("SharedWithMe", func() {
})
It("populates the driveItem.remoteItem.createdBy properties", func() {
driveOwner := getUserResponse.User
driveOwner := getUserResponseDefault.User
resourceInfo := statResponse.Info
resourceInfo.Owner = driveOwner.Id
@@ -257,25 +299,6 @@ var _ = Describe("SharedWithMe", func() {
Expect(jsonData.Get("user.id").String()).To(Equal(driveOwner.Id.OpaqueId))
})
It("populates the driveItem.remoteItem.fileSystemInfo properties", func() {
share := listReceivedSharesResponse.Shares[0].Share
share.Ctime = &typesv1beta1.Timestamp{Seconds: 400}
resourceInfo := statResponse.Info
resourceInfo.Mtime = &typesv1beta1.Timestamp{Seconds: 4000}
svc.ListSharedWithMe(
tape,
httptest.NewRequest(http.MethodGet, "/graph/v1beta1/me/drive/sharedWithMe", nil),
)
jsonData := gjson.Get(tape.Body.String(), "value.0.remoteItem.fileSystemInfo")
Expect(jsonData.Get("createdDateTime").String()).To(Equal(utils.TSToTime(share.Ctime).Format(time.RFC3339Nano)))
Expect(jsonData.Get("lastModifiedDateTime").String()).To(Equal(utils.TSToTime(resourceInfo.Mtime).Format(time.RFC3339Nano)))
})
It("populates the driveItem.remoteItem.folder properties", func() {
svc.ListSharedWithMe(
@@ -305,18 +328,22 @@ var _ = Describe("SharedWithMe", func() {
Expect(jsonData.Get("file.mimeType").String()).To(Equal(resourceInfo.MimeType))
})
It("populates the driveItem.remoteItem.folder properties", func() {
It("populates the driveItem.remoteItem.permissions properties", func() {
resourceInfo := statResponse.Info
resourceInfo.Type = providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER
resourceInfo.PermissionSet = roleconversions.NewViewerRole(true).CS3ResourcePermissions()
svc.ListSharedWithMe(
tape,
httptest.NewRequest(http.MethodGet, "/graph/v1beta1/me/drive/sharedWithMe", nil),
)
jsonData := gjson.Get(tape.Body.String(), "value.0.remoteItem")
jsonData := gjson.Get(tape.Body.String(), "value.0.remoteItem.permissions.0")
Expect(jsonData.Get("folder").Exists()).To(BeTrue())
Expect(jsonData.Get("roles.0").String()).To(Equal(unifiedrole.UnifiedRoleViewerID))
Expect(jsonData.Get("@ui\\.hidden").Exists()).To(BeTrue())
Expect(jsonData.Get("@ui\\.hidden").Bool()).To(BeFalse())
Expect(jsonData.Get("@client\\.synchronize").Exists()).To(BeTrue())
Expect(jsonData.Get("@client\\.synchronize").Bool()).To(BeTrue())
})
It("populates the driveItem.remoteItem.shared properties", func() {
@@ -334,10 +361,10 @@ var _ = Describe("SharedWithMe", func() {
})
It("populates the driveItem.remoteItem.shared.owner properties", func() {
shareCreator := getUserResponse.User
shareOwner := getUserResponseDefault.User
share := listReceivedSharesResponse.Shares[0].Share
share.Creator = shareCreator.Id
share.Owner = shareOwner.Id
svc.ListSharedWithMe(
tape,
@@ -346,12 +373,12 @@ var _ = Describe("SharedWithMe", func() {
jsonData := gjson.Get(tape.Body.String(), "value.0.remoteItem.shared.owner")
Expect(jsonData.Get("user.displayName").String()).To(Equal(shareCreator.DisplayName))
Expect(jsonData.Get("user.id").String()).To(Equal(shareCreator.Id.OpaqueId))
Expect(jsonData.Get("user.displayName").String()).To(Equal(shareOwner.DisplayName))
Expect(jsonData.Get("user.id").String()).To(Equal(shareOwner.Id.OpaqueId))
})
It("populates the driveItem.remoteItem.shared.sharedBy properties", func() {
shareCreator := getUserResponse.User
shareCreator := getUserResponseDefault.User
share := listReceivedSharesResponse.Shares[0].Share
share.Creator = shareCreator.Id

View File

@@ -89,6 +89,7 @@ import (
// go run ./examples/yaml.go
func main() {
// config.ParseEnv: will parse env var in string value. eg: shell: ${SHELL}
config.WithOptions(config.ParseEnv)
// add driver for support yaml content
@@ -350,7 +351,7 @@ ioutil.WriteFile("my-config.yaml", buf.Bytes(), 0755)
```go
// Options config options
type Options struct {
// parse env value. like: "${EnvName}" "${EnvName|default}"
// parse env in string value. like: "${EnvName}" "${EnvName|default}"
ParseEnv bool
// ParseTime parses a duration string to time.Duration
// eg: 10s, 2m
@@ -361,10 +362,6 @@ type Options struct {
EnableCache bool
// parse key, allow find value by key path. default is True eg: 'key.sub' will find `map[key]sub`
ParseKey bool
// tag name for binding data to struct
// Deprecated
// please set tag name by DecoderConfig
TagName string
// the delimiter char for split key path, if `FindByPath=true`. default is '.'
Delimiter byte
// default write format
@@ -380,6 +377,15 @@ type Options struct {
}
```
Examples for set options:
```go
config.WithOptions(config.WithTagName("mytag"))
config.WithOptions(func(opt *Options) {
opt.SetTagNames("config")
})
```
### Options: Parse default
Support parse default value by struct tag `default`

View File

@@ -21,14 +21,20 @@
- 支持从 OS ENV 变量数据加载配置
- 支持从远程 URL 加载配置数据
- 支持从命令行参数(`flags`)设置配置数据
- 支持在配置数据更改时触发事件
- 可用事件: `set.value`, `set.data`, `load.data`, `clean.data`, `reload.data`
- 支持数据覆盖合并加载多份数据时将按key自动合并
- 数据自动覆盖合并,加载多份数据时将按`key`自动合并
- 支持丰富的自定义选项设置
- `Readonly` 支持设置配置数据只读
- `EnableCache` 支持设置配置数据缓存
- `ParseEnv` 支持获取时自动解析string值里的ENV变量(`shell: ${SHELL}` -> `shell: /bin/zsh`)
- `ParseDefault` 支持在绑定数据到结构体时解析默认值 (tag: `default:"def_value"`, 配合ParseEnv也支持ENV变量)
- `ParseTime` 支持绑定数据到struct时自动转换 `10s`,`2m``time.Duration`
- 完整选项设置请查看 `config.Options`
- 支持将全部或部分配置数据绑定到结构体 `config.BindStruct("key", &s)`
- 支持通过结构体标签 `default` 解析并设置默认值. eg: `default:"def_value"`
- 支持从 ENV 初始化设置字段值 `default:"${APP_ENV | dev}"`
- 支持通过 `.` 分隔符来按路径获取子级值,也支持自定义分隔符。 e.g `map.key` `arr.2`
- 支持解析ENV变量名称。 like `shell: ${SHELL}` -> `shell: /bin/zsh`
- 支持在配置数据更改时触发事件
- 可用事件: `set.value`, `set.data`, `load.data`, `clean.data`, `reload.data`
- 简洁的使用API `Get` `Int` `Uint` `Int64` `String` `Bool` `Ints` `IntMap` `Strings` `StringMap` ...
- 完善的单元测试(code coverage > 95%)
@@ -88,7 +94,7 @@ import (
// go run ./examples/yaml.go
func main() {
// 设置选项支持 ENV 解析
// 设置选项支持ENV变量解析当获取的值为string类型时会尝试解析其中的ENV变量
config.WithOptions(config.ParseEnv)
// 添加驱动程序以支持yaml内容解析除了JSON是默认支持其他的则是按需使用
@@ -334,7 +340,7 @@ ioutil.WriteFile("my-config.yaml", buf.Bytes(), 0755)
```go
// Options config options
type Options struct {
// parse env value. like: "${EnvName}" "${EnvName|default}"
// parse env in string value. like: "${EnvName}" "${EnvName|default}"
ParseEnv bool
// ParseTime parses a duration string to time.Duration
// eg: 10s, 2m
@@ -345,8 +351,6 @@ type Options struct {
EnableCache bool
// parse key, allow find value by key path. default is True eg: 'key.sub' will find `map[key]sub`
ParseKey bool
// tag name for binding data to struct
TagName string
// the delimiter char for split key, when `FindByPath=true`. default is '.'
Delimiter byte
// default write format. default is JSON
@@ -362,6 +366,15 @@ type Options struct {
}
```
Examples for set options:
```go
config.WithOptions(config.WithTagName("mytag"))
config.WithOptions(func(opt *Options) {
opt.SetTagNames("config")
})
```
### 选项: 解析默认值
NEW: 支持通过结构标签 `default` 解析并设置默认值

View File

@@ -111,23 +111,24 @@ type Config struct {
sMapCache map[string]strMap
}
// New config instance, default add JSON driver
// New config instance with custom options, default with JSON driver
func New(name string, opts ...OptionFn) *Config {
return NewEmpty(name).WithDriver(JSONDriver).WithOptions(opts...)
return NewEmpty(name, opts...).WithDriver(JSONDriver)
}
// NewEmpty config instance
func NewEmpty(name string) *Config {
return &Config{
// NewEmpty create config instance with custom options
func NewEmpty(name string, opts ...OptionFn) *Config {
c := &Config{
name: name,
opts: newDefaultOption(),
data: make(map[string]any),
// don't add any drivers
encoders: map[string]Encoder{},
decoders: map[string]Decoder{},
aliasMap: make(map[string]string),
}
return c.WithOptions(opts...)
}
// NewWith create config instance, and you can call some init func

View File

@@ -121,7 +121,7 @@ func (c *Config) Structure(key string, dst any) (err error) {
return err
}
// ToJSON string
// ToJSON string, will ignore error
func (c *Config) ToJSON() string {
buf := &bytes.Buffer{}
@@ -129,7 +129,6 @@ func (c *Config) ToJSON() string {
if err != nil {
return ""
}
return buf.String()
}
@@ -168,7 +167,6 @@ func (c *Config) DumpTo(out io.Writer, format string) (n int64, err error) {
// write content to out
num, _ := fmt.Fprintln(out, string(encoded))
return int64(num), nil
}

View File

@@ -12,9 +12,9 @@ import (
"strings"
"time"
"dario.cat/mergo"
"github.com/gookit/goutil/errorx"
"github.com/gookit/goutil/fsutil"
"github.com/imdario/mergo"
)
// LoadFiles load one or multi files, will fire OnLoadData event
@@ -103,10 +103,8 @@ func (c *Config) LoadOSEnv(keys []string, keyToLower bool) {
if keyToLower {
key = strings.ToLower(key)
}
_ = c.Set(key, val)
}
c.fireHook(OnLoadData)
}
@@ -195,7 +193,7 @@ func LoadData(dataSource ...any) error { return dc.LoadData(dataSource...) }
// LoadData load data from map OR struct
//
// The dataSources can be:
// The dataSources type allow:
// - map[string]any
// - map[string]string
func (c *Config) LoadData(dataSources ...any) (err error) {
@@ -203,19 +201,24 @@ func (c *Config) LoadData(dataSources ...any) (err error) {
c.opts.Delimiter = defaultDelimiter
}
var loaded bool
for _, ds := range dataSources {
if smp, ok := ds.(map[string]string); ok {
loaded = true
c.LoadSMap(smp)
continue
}
err = mergo.Merge(&c.data, ds, mergo.WithOverride)
err = mergo.Merge(&c.data, ds, c.opts.MergeOptions...)
if err != nil {
return errorx.WithStack(err)
}
loaded = true
}
c.fireHook(OnLoadData)
if loaded {
c.fireHook(OnLoadData)
}
return
}
@@ -237,8 +240,8 @@ func LoadSources(format string, src []byte, more ...[]byte) error {
// Usage:
//
// config.LoadSources(config.Yaml, []byte(`
// name: blog
// arr:
// name: blog
// arr:
// key: val
//
// `))
@@ -308,6 +311,24 @@ func (c *Config) LoadExistsByFormat(format string, configFiles ...string) (err e
return
}
// LoadOptions for load config from dir.
type LoadOptions struct {
// DataKey use for load config from dir.
// see https://github.com/gookit/config/issues/173
DataKey string
}
// LoadOptFn type func
type LoadOptFn func(lo *LoadOptions)
func newLoadOptions(loFns []LoadOptFn) *LoadOptions {
lo := &LoadOptions{}
for _, fn := range loFns {
fn(lo)
}
return lo
}
// LoadFromDir Load custom format files from the given directory, the file name will be used as the key.
//
// Example:
@@ -317,24 +338,30 @@ func (c *Config) LoadExistsByFormat(format string, configFiles ...string) (err e
//
// // after load
// Config.data = map[string]any{"task": file data}
func LoadFromDir(dirPath, format string) error {
return dc.LoadFromDir(dirPath, format)
func LoadFromDir(dirPath, format string, loFns ...LoadOptFn) error {
return dc.LoadFromDir(dirPath, format, loFns...)
}
// LoadFromDir Load custom format files from the given directory, the file name will be used as the key.
//
// NOTE: will not be reloaded on call ReloadFiles(), if data loaded by the method.
//
// Example:
//
// // file: /somedir/task.json
// // file: /somedir/task.json , will use filename 'task' as key
// Config.LoadFromDir("/somedir", "json")
//
// // after load
// Config.data = map[string]any{"task": file data}
func (c *Config) LoadFromDir(dirPath, format string) (err error) {
// // after load, the data will be:
// Config.data = map[string]any{"task": {file data}}
func (c *Config) LoadFromDir(dirPath, format string, loFns ...LoadOptFn) (err error) {
extName := "." + format
extLen := len(extName)
return fsutil.FindInDir(dirPath, func(fPath string, ent fs.DirEntry) error {
lo := newLoadOptions(loFns)
dirData := make(map[string]any)
dataList := make([]map[string]any, 0, 8)
err = fsutil.FindInDir(dirPath, func(fPath string, ent fs.DirEntry) error {
baseName := ent.Name()
if strings.HasSuffix(baseName, extName) {
data, err := c.parseSourceToMap(format, fsutil.MustReadFile(fPath))
@@ -342,18 +369,31 @@ func (c *Config) LoadFromDir(dirPath, format string) (err error) {
return err
}
// filename without ext.
onlyName := baseName[:len(baseName)-extLen]
err = c.loadDataMap(map[string]any{onlyName: data})
if lo.DataKey != "" {
dataList = append(dataList, data)
} else {
dirData[onlyName] = data
}
// use file name as key, it cannot be reloaded. SO, cannot append to loadedFiles
// if err == nil {
// c.loadedFiles = append(c.loadedFiles, fPath)
// }
return err
// TODO use file name as key, it cannot be reloaded. So, cannot append to loadedFiles
// c.loadedFiles = append(c.loadedFiles, fPath)
}
return nil
})
if err != nil {
return err
}
if lo.DataKey != "" {
dirData[lo.DataKey] = dataList
}
if len(dirData) == 0 {
return nil
}
return c.loadDataMap(dirData)
}
// ReloadFiles reload config data use loaded files
@@ -440,7 +480,7 @@ func (c *Config) loadDataMap(data map[string]any) (err error) {
c.data = data
} else {
// again ... will merge data
err = mergo.Merge(&c.data, data, mergo.WithOverride, mergo.WithTypeCheck)
err = mergo.Merge(&c.data, data, c.opts.MergeOptions...)
}
if !c.reloading && err == nil {

View File

@@ -3,6 +3,8 @@ package config
import (
"strings"
"dario.cat/mergo"
"github.com/gookit/goutil"
"github.com/mitchellh/mapstructure"
)
@@ -20,20 +22,22 @@ type HookFunc func(event string, c *Config)
// Options config options
type Options struct {
// ParseEnv parse env value. like: "${EnvName}" "${EnvName|default}"
// ParseEnv parse env in string value and default value. like: "${EnvName}" "${EnvName|default}"
ParseEnv bool
// ParseTime parses a duration string to time.Duration
// eg: 10s, 2m
ParseTime bool
// Readonly config is readonly
Readonly bool
// ParseDefault tag on binding data to struct. tag: default
ParseDefault bool
// EnableCache enable config data cache
EnableCache bool
// ParseKey parse key path, allow find value by key path. eg: 'key.sub' will find `map[key]sub`
ParseKey bool
// TagName tag name for binding data to struct
//
// Tips: please set tag name by DecoderConfig
// Deprecated: please set tag name by DecoderConfig, or use SetTagName()
TagName string
// Delimiter the delimiter char for split key path, if `FindByPath=true`. default is '.'
Delimiter byte
@@ -45,8 +49,8 @@ type Options struct {
DecoderConfig *mapstructure.DecoderConfig
// HookFunc on data changed. you can do something...
HookFunc HookFunc
// ParseDefault tag on binding data to struct. tag: default
ParseDefault bool
// MergeOptions settings for merge two data
MergeOptions []func(*mergo.Config)
// WatchChange bool
}
@@ -63,6 +67,10 @@ func newDefaultOption() *Options {
ReadFormat: JSON,
// struct decoder config
DecoderConfig: newDefaultDecoderConfig(""),
MergeOptions: []func(*mergo.Config){
mergo.WithOverride,
mergo.WithTypeCheck,
},
}
}
@@ -79,6 +87,12 @@ func newDefaultDecoderConfig(tagName string) *mapstructure.DecoderConfig {
}
}
// SetTagName for mapping data to struct
func (o *Options) SetTagName(tagName string) {
o.TagName = tagName
o.DecoderConfig.TagName = tagName
}
func (o *Options) shouldAddHookFunc() bool {
return o.ParseTime || o.ParseEnv
}
@@ -113,8 +127,7 @@ func (o *Options) makeDecoderConfig() *mapstructure.DecoderConfig {
// WithTagName set tag name for export to struct
func WithTagName(tagName string) func(*Options) {
return func(opts *Options) {
opts.TagName = tagName
opts.DecoderConfig.TagName = tagName
opts.SetTagName(tagName)
}
}
@@ -137,15 +150,12 @@ func Delimiter(sep byte) func(*Options) {
}
}
// SaveFileOnSet set hook func
// SaveFileOnSet set hook func, will panic on save error
func SaveFileOnSet(fileName string, format string) func(options *Options) {
return func(opts *Options) {
opts.HookFunc = func(event string, c *Config) {
if strings.HasPrefix(event, "set.") {
err := c.DumpToFile(fileName, format)
if err != nil {
panic(err)
}
goutil.PanicErr(c.DumpToFile(fileName, format))
}
}
}

View File

@@ -664,7 +664,6 @@ func SizeToString(size uint64) string
func StringToByte(sizeStr string) uint64
func ParseByte(sizeStr string) uint64
func PrettyJSON(v any) (string, error)
func StringsToInts(ss []string) (ints []int, err error)
func ArgsWithSpaces(vs []any) (message string)
// source at fmtutil/time.go
func HowLongAgo(sec int64) string
@@ -909,6 +908,8 @@ func SimpleMerge(src, dst map[string]any) map[string]any
func DeepMerge(src, dst map[string]any, deep int) map[string]any
func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string
func MergeMultiSMap(mps ...map[string]string) map[string]string
func FilterSMap(sm map[string]string) map[string]string
func MakeByPath(path string, val any) (mp map[string]any)
func MakeByKeys(keys []string, val any) (mp map[string]any)
// source at maputil/setval.go
@@ -942,36 +943,49 @@ func MaxI64(x, y int64) int64
func SwapMaxI64(x, y int64) (int64, int64)
func MaxFloat(x, y float64) float64
// source at mathutil/convert.go
func NewConvOption[T any](optFns ...ConvOptionFn[T]) *ConvOption[T]
func WithNilAsFail[T any](opt *ConvOption[T])
func WithHandlePtr[T any](opt *ConvOption[T])
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T]
func Int(in any) (int, error)
func SafeInt(in any) int
func QuietInt(in any) int
func MustInt(in any) int
func IntOrPanic(in any) int
func MustInt(in any) int
func IntOrDefault(in any, defVal int) int
func IntOr(in any, defVal int) int
func IntOrErr(in any) (iVal int, err error)
func ToInt(in any) (iVal int, err error)
func ToIntWithFunc(in any, usrFn ToIntFunc) (iVal int, err error)
func IntOrErr(in any) (int, error)
func ToInt(in any) (int, error)
func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error)
func StrInt(s string) int
func StrIntOr(s string, defVal int) int
func Uint(in any) (uint64, error)
func SafeUint(in any) uint64
func QuietUint(in any) uint64
func MustUint(in any) uint64
func UintOrDefault(in any, defVal uint64) uint64
func UintOr(in any, defVal uint64) uint64
func UintOrErr(in any) (uint64, error)
func ToUint(in any) (u64 uint64, err error)
func ToUintWithFunc(in any, usrFn ToUintFunc) (u64 uint64, err error)
func Int64(in any) (int64, error)
func SafeInt64(in any) int64
func QuietInt64(in any) int64
func MustInt64(in any) int64
func Int64OrDefault(in any, defVal int64) int64
func Int64Or(in any, defVal int64) int64
func ToInt64(in any) (int64, error)
func Int64OrErr(in any) (int64, error)
func ToInt64(in any) (i64 int64, err error)
func ToInt64WithFunc(in any, usrFn ToInt64Func) (i64 int64, err error)
func ToInt64With(in any, optFns ...ConvOptionFn[int64]) (i64 int64, err error)
func Uint(in any) (uint, error)
func SafeUint(in any) uint
func QuietUint(in any) uint
func MustUint(in any) uint
func UintOrDefault(in any, defVal uint) uint
func UintOr(in any, defVal uint) uint
func UintOrErr(in any) (uint, error)
func ToUint(in any) (u64 uint, err error)
func ToUintWith(in any, optFns ...ConvOptionFn[uint]) (uVal uint, err error)
func Uint64(in any) (uint64, error)
func QuietUint64(in any) uint64
func SafeUint64(in any) uint64
func MustUint64(in any) uint64
func Uint64OrDefault(in any, defVal uint64) uint64
func Uint64Or(in any, defVal uint64) uint64
func Uint64OrErr(in any) (uint64, error)
func ToUint64(in any) (uint64, error)
func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error)
func QuietFloat(in any) float64
func SafeFloat(in any) float64
func FloatOrPanic(in any) float64
@@ -980,8 +994,8 @@ func FloatOrDefault(in any, defVal float64) float64
func FloatOr(in any, defVal float64) float64
func Float(in any) (float64, error)
func FloatOrErr(in any) (float64, error)
func ToFloat(in any) (f64 float64, err error)
func ToFloatWithFunc(in any, usrFn ToFloatFunc) (f64 float64, err error)
func ToFloat(in any) (float64, error)
func ToFloatWith(in any, optFns ...ConvOptionFn[float64]) (f64 float64, err error)
func MustString(val any) string
func StringOrPanic(val any) string
func StringOrDefault(val any, defVal string) string
@@ -991,10 +1005,8 @@ func StringOrErr(val any) (string, error)
func QuietString(val any) string
func String(val any) string
func SafeString(val any) string
func TryToString(val any, defaultAsErr bool) (str string, err error)
func ToStringWithFunc(val any, usrFn comdef.ToStringFunc) (str string, err error)
func Percent(val, total int) float64
func ElapsedTime(startTime time.Time) string
func TryToString(val any, defaultAsErr bool) (string, error)
func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error)
// source at mathutil/format.go
func DataSize(size uint64) string
func HowLongAgo(sec int64) string
@@ -1005,11 +1017,19 @@ func LessOr[T comdef.XintOrFloat](val, max, devVal T) T
func LteOr[T comdef.XintOrFloat](val, max, devVal T) T
func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T
func GteOr[T comdef.XintOrFloat](val, min, defVal T) T
func Mul[T1, T2 comdef.XintOrFloat](a T1, b T2) float64
func MulF2i(a, b float64) int
func Div[T1, T2 comdef.XintOrFloat](a T1, b T2) float64
func DivInt[T comdef.Integer](a, b T) int
func DivF2i(a, b float64) int
func Percent(val, total int) float64
// source at mathutil/random.go
func RandomInt(min, max int) int
func RandInt(min, max int) int
func RandIntWithSeed(min, max int, seed int64) int
func RandomIntWithSeed(min, max int, seed int64) int
// source at mathutil/value.go
func New[T comdef.IntOrFloat](v T) *Num[T]
```
### Reflects
@@ -1223,7 +1243,7 @@ func MustString(val any) string
func StringOrDefault(val any, defVal string) string
func StringOr(val any, defVal string) string
func AnyToString(val any, defaultAsErr bool) (s string, err error)
func ToStringWithFunc(val any, fbFn comdef.ToStringFunc) (str string, err error)
func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error)
func ToBool(s string) (bool, error)
func QuietBool(s string) bool
func SafeBool(s string) bool
@@ -1238,8 +1258,8 @@ func QuietInt(s string) int
func MustInt(s string) int
func IntOrPanic(s string) int
func Int64(s string) int64
func SafeInt64(s string) int64
func QuietInt64(s string) int64
func SafeInt64(s string) int64
func ToInt64(s string) (int64, error)
func Int64OrDefault(s string, defVal int64) int64
func Int64Or(s string, defVal int64) int64
@@ -1401,9 +1421,6 @@ func OrHandle(s string, fn comdef.StringHandleFunc) string
func Valid(ss ...string) string
func Replaces(str string, pairs map[string]string) string
func NewReplacer(pairs map[string]string) *strings.Replacer
func PrettyJSON(v any) (string, error)
func RenderTemplate(input string, data any, fns template.FuncMap, isFile ...bool) string
func RenderText(input string, data any, fns template.FuncMap, isFile ...bool) string
func WrapTag(s, tag string) string
func SubstrCount(s, substr string, params ...uint64) (int, error)
```

View File

@@ -665,7 +665,6 @@ func SizeToString(size uint64) string
func StringToByte(sizeStr string) uint64
func ParseByte(sizeStr string) uint64
func PrettyJSON(v any) (string, error)
func StringsToInts(ss []string) (ints []int, err error)
func ArgsWithSpaces(vs []any) (message string)
// source at fmtutil/time.go
func HowLongAgo(sec int64) string
@@ -910,6 +909,8 @@ func SimpleMerge(src, dst map[string]any) map[string]any
func DeepMerge(src, dst map[string]any, deep int) map[string]any
func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string
func MergeMultiSMap(mps ...map[string]string) map[string]string
func FilterSMap(sm map[string]string) map[string]string
func MakeByPath(path string, val any) (mp map[string]any)
func MakeByKeys(keys []string, val any) (mp map[string]any)
// source at maputil/setval.go
@@ -943,36 +944,49 @@ func MaxI64(x, y int64) int64
func SwapMaxI64(x, y int64) (int64, int64)
func MaxFloat(x, y float64) float64
// source at mathutil/convert.go
func NewConvOption[T any](optFns ...ConvOptionFn[T]) *ConvOption[T]
func WithNilAsFail[T any](opt *ConvOption[T])
func WithHandlePtr[T any](opt *ConvOption[T])
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T]
func Int(in any) (int, error)
func SafeInt(in any) int
func QuietInt(in any) int
func MustInt(in any) int
func IntOrPanic(in any) int
func MustInt(in any) int
func IntOrDefault(in any, defVal int) int
func IntOr(in any, defVal int) int
func IntOrErr(in any) (iVal int, err error)
func ToInt(in any) (iVal int, err error)
func ToIntWithFunc(in any, usrFn ToIntFunc) (iVal int, err error)
func IntOrErr(in any) (int, error)
func ToInt(in any) (int, error)
func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error)
func StrInt(s string) int
func StrIntOr(s string, defVal int) int
func Uint(in any) (uint64, error)
func SafeUint(in any) uint64
func QuietUint(in any) uint64
func MustUint(in any) uint64
func UintOrDefault(in any, defVal uint64) uint64
func UintOr(in any, defVal uint64) uint64
func UintOrErr(in any) (uint64, error)
func ToUint(in any) (u64 uint64, err error)
func ToUintWithFunc(in any, usrFn ToUintFunc) (u64 uint64, err error)
func Int64(in any) (int64, error)
func SafeInt64(in any) int64
func QuietInt64(in any) int64
func MustInt64(in any) int64
func Int64OrDefault(in any, defVal int64) int64
func Int64Or(in any, defVal int64) int64
func ToInt64(in any) (int64, error)
func Int64OrErr(in any) (int64, error)
func ToInt64(in any) (i64 int64, err error)
func ToInt64WithFunc(in any, usrFn ToInt64Func) (i64 int64, err error)
func ToInt64With(in any, optFns ...ConvOptionFn[int64]) (i64 int64, err error)
func Uint(in any) (uint, error)
func SafeUint(in any) uint
func QuietUint(in any) uint
func MustUint(in any) uint
func UintOrDefault(in any, defVal uint) uint
func UintOr(in any, defVal uint) uint
func UintOrErr(in any) (uint, error)
func ToUint(in any) (u64 uint, err error)
func ToUintWith(in any, optFns ...ConvOptionFn[uint]) (uVal uint, err error)
func Uint64(in any) (uint64, error)
func QuietUint64(in any) uint64
func SafeUint64(in any) uint64
func MustUint64(in any) uint64
func Uint64OrDefault(in any, defVal uint64) uint64
func Uint64Or(in any, defVal uint64) uint64
func Uint64OrErr(in any) (uint64, error)
func ToUint64(in any) (uint64, error)
func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error)
func QuietFloat(in any) float64
func SafeFloat(in any) float64
func FloatOrPanic(in any) float64
@@ -981,8 +995,8 @@ func FloatOrDefault(in any, defVal float64) float64
func FloatOr(in any, defVal float64) float64
func Float(in any) (float64, error)
func FloatOrErr(in any) (float64, error)
func ToFloat(in any) (f64 float64, err error)
func ToFloatWithFunc(in any, usrFn ToFloatFunc) (f64 float64, err error)
func ToFloat(in any) (float64, error)
func ToFloatWith(in any, optFns ...ConvOptionFn[float64]) (f64 float64, err error)
func MustString(val any) string
func StringOrPanic(val any) string
func StringOrDefault(val any, defVal string) string
@@ -992,10 +1006,8 @@ func StringOrErr(val any) (string, error)
func QuietString(val any) string
func String(val any) string
func SafeString(val any) string
func TryToString(val any, defaultAsErr bool) (str string, err error)
func ToStringWithFunc(val any, usrFn comdef.ToStringFunc) (str string, err error)
func Percent(val, total int) float64
func ElapsedTime(startTime time.Time) string
func TryToString(val any, defaultAsErr bool) (string, error)
func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error)
// source at mathutil/format.go
func DataSize(size uint64) string
func HowLongAgo(sec int64) string
@@ -1006,11 +1018,19 @@ func LessOr[T comdef.XintOrFloat](val, max, devVal T) T
func LteOr[T comdef.XintOrFloat](val, max, devVal T) T
func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T
func GteOr[T comdef.XintOrFloat](val, min, defVal T) T
func Mul[T1, T2 comdef.XintOrFloat](a T1, b T2) float64
func MulF2i(a, b float64) int
func Div[T1, T2 comdef.XintOrFloat](a T1, b T2) float64
func DivInt[T comdef.Integer](a, b T) int
func DivF2i(a, b float64) int
func Percent(val, total int) float64
// source at mathutil/random.go
func RandomInt(min, max int) int
func RandInt(min, max int) int
func RandIntWithSeed(min, max int, seed int64) int
func RandomIntWithSeed(min, max int, seed int64) int
// source at mathutil/value.go
func New[T comdef.IntOrFloat](v T) *Num[T]
```
### Reflects
@@ -1224,7 +1244,7 @@ func MustString(val any) string
func StringOrDefault(val any, defVal string) string
func StringOr(val any, defVal string) string
func AnyToString(val any, defaultAsErr bool) (s string, err error)
func ToStringWithFunc(val any, fbFn comdef.ToStringFunc) (str string, err error)
func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error)
func ToBool(s string) (bool, error)
func QuietBool(s string) bool
func SafeBool(s string) bool
@@ -1239,8 +1259,8 @@ func QuietInt(s string) int
func MustInt(s string) int
func IntOrPanic(s string) int
func Int64(s string) int64
func SafeInt64(s string) int64
func QuietInt64(s string) int64
func SafeInt64(s string) int64
func ToInt64(s string) (int64, error)
func Int64OrDefault(s string, defVal int64) int64
func Int64Or(s string, defVal int64) int64
@@ -1402,9 +1422,6 @@ func OrHandle(s string, fn comdef.StringHandleFunc) string
func Valid(ss ...string) string
func Replaces(str string, pairs map[string]string) string
func NewReplacer(pairs map[string]string) *strings.Replacer
func PrettyJSON(v any) (string, error)
func RenderTemplate(input string, data any, fns template.FuncMap, isFile ...bool) string
func RenderText(input string, data any, fns template.FuncMap, isFile ...bool) string
func WrapTag(s, tag string) string
func SubstrCount(s, substr string, params ...uint64) (int, error)
```

View File

@@ -9,6 +9,9 @@ type (
UnmarshalFunc func(bts []byte, ptr any) error
)
// ToTypeFunc convert value to defined type
type ToTypeFunc[T any] func(any) (T, error)
// IntCheckFunc check func
type IntCheckFunc func(val int) error

View File

@@ -1,6 +1,38 @@
package comdef
import "errors"
import (
"errors"
"strings"
)
// ErrConvType error
var ErrConvType = errors.New("convert value type error")
// Errors multi error list
type Errors []error
// Error string
func (es Errors) Error() string {
var sb strings.Builder
for _, err := range es {
sb.WriteString(err.Error())
sb.WriteByte('\n')
}
return sb.String()
}
// ErrOrNil error
func (es Errors) ErrOrNil() error {
if len(es) == 0 {
return nil
}
return es
}
// First error
func (es Errors) First() error {
if len(es) > 0 {
return es[0]
}
return nil
}

View File

@@ -24,6 +24,11 @@ type Int64able interface {
Int64() (int64, error)
}
// Float64able interface
type Float64able interface {
Float64() (float64, error)
}
//
//
// Matcher type

View File

@@ -57,17 +57,28 @@ func ToInt64(v any) (int64, error) {
return mathutil.ToInt64(v)
}
// Uint convert value to uint64
func Uint(v any) uint64 {
// Uint convert value to uint
func Uint(v any) uint {
iv, _ := mathutil.ToUint(v)
return iv
}
// ToUint try to convert value to uint64
func ToUint(v any) (uint64, error) {
// ToUint try to convert value to uint
func ToUint(v any) (uint, error) {
return mathutil.ToUint(v)
}
// Uint64 convert value to uint64
func Uint64(v any) uint64 {
iv, _ := mathutil.ToUint64(v)
return iv
}
// ToUint64 try to convert value to uint64
func ToUint64(v any) (uint64, error) {
return mathutil.ToUint64(v)
}
// BoolString convert bool to string
func BoolString(bl bool) string {
return strconv.FormatBool(bl)
@@ -166,12 +177,12 @@ func ToKind(val any, kind reflect.Kind, fbFunc func(val any) (any, error)) (newV
newVal = dstV
}
case reflect.Uint:
var dstV uint64
var dstV uint
if dstV, err = mathutil.ToUint(val); err == nil {
newVal = uint(dstV)
newVal = dstV
}
case reflect.Uint8:
var dstV uint64
var dstV uint
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV > math.MaxUint8 {
return nil, fmt.Errorf("value overflow uint8. val: %v", val)
@@ -179,7 +190,7 @@ func ToKind(val any, kind reflect.Kind, fbFunc func(val any) (any, error)) (newV
newVal = uint8(dstV)
}
case reflect.Uint16:
var dstV uint64
var dstV uint
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV > math.MaxUint16 {
return nil, fmt.Errorf("value overflow uint16. val: %v", val)
@@ -187,7 +198,7 @@ func ToKind(val any, kind reflect.Kind, fbFunc func(val any) (any, error)) (newV
newVal = uint16(dstV)
}
case reflect.Uint32:
var dstV uint64
var dstV uint
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV > math.MaxUint32 {
return nil, fmt.Errorf("value overflow uint32. val: %v", val)
@@ -196,7 +207,7 @@ func ToKind(val any, kind reflect.Kind, fbFunc func(val any) (any, error)) (newV
}
case reflect.Uint64:
var dstV uint64
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV, err = mathutil.ToUint64(val); err == nil {
newVal = dstV
}
case reflect.Float32:

View File

@@ -1,3 +1,4 @@
// Package encodes provide some util for encode/decode data
package encodes
import (

View File

@@ -57,7 +57,8 @@ func TempDir(dir, pattern string) (string, error) {
// MustSave create file and write contents to file, panic on error.
//
// data type allow: string, []byte, io.Reader
// - data type allow: string, []byte, io.Reader
//
// default option see NewOpenOption()
func MustSave(filePath string, data any, optFns ...OpenOptionFunc) {
basefn.MustOK(SaveFile(filePath, data, optFns...))
@@ -65,6 +66,8 @@ func MustSave(filePath string, data any, optFns ...OpenOptionFunc) {
// SaveFile create file and write contents to file. will auto create dir.
//
// - data type allow: string, []byte, io.Reader
//
// default option see NewOpenOption()
func SaveFile(filePath string, data any, optFns ...OpenOptionFunc) error {
opt := NewOpenOption(optFns...)

View File

@@ -46,7 +46,7 @@ func SafeRun(fn func()) (err error) {
return nil
}
// SafeRun sync run a func with error.
// SafeRunWithError sync run a func with error.
// If the func panics, the panic value is returned as an error.
func SafeRunWithError(fn func() error) (err error) {
defer func() {

View File

@@ -1,11 +1,10 @@
package checkfn
import (
"bytes"
"fmt"
"reflect"
"strings"
"github.com/gookit/goutil/reflects"
)
// IsNil value check
@@ -13,15 +12,46 @@ func IsNil(v any) bool {
if v == nil {
return true
}
return reflects.IsNil(reflect.ValueOf(v))
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return rv.IsNil()
default:
return false
}
}
// IsEmpty value check
func IsEmpty(v any) bool {
if v == nil {
// IsSimpleKind kind in: string, bool, intX, uintX, floatX
func IsSimpleKind(k reflect.Kind) bool {
if reflect.String == k {
return true
}
return reflects.IsEmpty(reflect.ValueOf(v))
return k > reflect.Invalid && k <= reflect.Float64
}
// IsEqual determines if two objects are considered equal.
//
// TIP: cannot compare function type
func IsEqual(src, dst any) bool {
if src == nil || dst == nil {
return src == dst
}
bs1, ok := src.([]byte)
if !ok {
return reflect.DeepEqual(src, dst)
}
bs2, ok := dst.([]byte)
if !ok {
return false
}
if bs1 == nil || bs2 == nil {
return bs1 == nil && bs2 == nil
}
return bytes.Equal(bs1, bs2)
}
// Contains try loop over the data check if the data includes the element.
@@ -57,7 +87,7 @@ func Contains(data, elem any) (valid, found bool) {
if dataKind == reflect.Map {
mapKeys := dataRv.MapKeys()
for i := 0; i < len(mapKeys); i++ {
if reflects.IsEqual(mapKeys[i].Interface(), elem) {
if IsEqual(mapKeys[i].Interface(), elem) {
return true, true
}
}
@@ -70,7 +100,7 @@ func Contains(data, elem any) (valid, found bool) {
}
for i := 0; i < dataRv.Len(); i++ {
if reflects.IsEqual(dataRv.Index(i).Interface(), elem) {
if IsEqual(dataRv.Index(i).Interface(), elem) {
return true, true
}
}

View File

@@ -16,7 +16,6 @@ func Environ() map[string]string {
for _, str := range envList {
nodes := strings.SplitN(str, "=", 2)
if len(nodes) < 2 {
envMap[nodes[0]] = ""
} else {

View File

@@ -2,9 +2,13 @@ package comfunc
import (
"fmt"
"reflect"
"strconv"
"strings"
"time"
"github.com/gookit/goutil/comdef"
"github.com/gookit/goutil/internal/checkfn"
)
// Bool try to convert type to bool
@@ -60,3 +64,117 @@ func FormatWithArgs(fmtAndArgs []any) string {
}
return fmt.Sprint(fmtAndArgs...)
}
// ConvOption convert options
type ConvOption struct {
// if ture: value is nil, will return convert error;
// if false(default): value is nil, will convert to zero value
NilAsFail bool
// HandlePtr auto convert ptr type(int,float,string) value. eg: *int to int
// - if true: will use real type try convert. default is false
// - NOTE: current T type's ptr is default support.
HandlePtr bool
// set custom fallback convert func for not supported type.
UserConvFn comdef.ToStringFunc
}
// ConvOptionFn convert option func
type ConvOptionFn func(opt *ConvOption)
// StrBySprintFn convert any value to string by fmt.Sprint
var StrBySprintFn = func(v any) (string, error) {
return fmt.Sprint(v), nil
}
// WithHandlePtr set ConvOption.HandlePtr option
func WithHandlePtr(opt *ConvOption) {
opt.HandlePtr = true
}
// WithUserConvFn set ConvOption.UserConvFn option
func WithUserConvFn(fn comdef.ToStringFunc) ConvOptionFn {
return func(opt *ConvOption) {
opt.UserConvFn = fn
}
}
// NewConvOption create a new ConvOption
func NewConvOption(optFns ...ConvOptionFn) *ConvOption {
opt := &ConvOption{}
opt.WithOption(optFns...)
return opt
}
// WithOption set convert option
func (opt *ConvOption) WithOption(optFns ...ConvOptionFn) {
for _, fn := range optFns {
if fn != nil {
fn(opt)
}
}
}
// ToStringWith try to convert value to string. can with some option func, more see ConvOption.
func ToStringWith(in any, optFns ...ConvOptionFn) (str string, err error) {
opt := NewConvOption(optFns...)
if !opt.NilAsFail && in == nil {
return "", nil
}
switch value := in.(type) {
case int:
str = strconv.Itoa(value)
case int8:
str = strconv.Itoa(int(value))
case int16:
str = strconv.Itoa(int(value))
case int32: // same as `rune`
str = strconv.Itoa(int(value))
case int64:
str = strconv.FormatInt(value, 10)
case uint:
str = strconv.FormatUint(uint64(value), 10)
case uint8:
str = strconv.FormatUint(uint64(value), 10)
case uint16:
str = strconv.FormatUint(uint64(value), 10)
case uint32:
str = strconv.FormatUint(uint64(value), 10)
case uint64:
str = strconv.FormatUint(value, 10)
case float32:
str = strconv.FormatFloat(float64(value), 'f', -1, 32)
case float64:
str = strconv.FormatFloat(value, 'f', -1, 64)
case bool:
str = strconv.FormatBool(value)
case string:
str = value
case *string:
str = *value
case []byte:
str = string(value)
case time.Duration:
str = strconv.FormatInt(int64(value), 10)
case fmt.Stringer:
str = value.String()
case error:
str = value.Error()
default:
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToStringWith(rv.Interface(), optFns...)
}
}
}
if opt.UserConvFn != nil {
str, err = opt.UserConvFn(in)
} else {
err = comdef.ErrConvType
}
}
return
}

View File

@@ -20,8 +20,14 @@ import (
"strings"
)
// SepChar separator char
const SepChar = "|"
const (
// SepChar separator char split var name and default value
SepChar = "|"
VarLeft = "${" // default var left format chars
VarRight = "}" // default var right format chars
mustPrefix = '?' // must prefix char
)
// ParseOptFn option func
type ParseOptFn func(o *ParseOpts)
@@ -34,8 +40,15 @@ type ParseOpts struct {
ParseFn func(string) (string, error)
// Regexp custom expression regex.
Regexp *regexp.Regexp
// Keyword check chars for expression. default is "${"
Keyword string
// var format chars for expression.
// default left="${", right="}"
VarLeft, VarRight string
}
func (opt *ParseOpts) useDefaultRegex() {
opt.Regexp = envRegex
opt.VarLeft = VarLeft
opt.VarRight = VarRight
}
// must add "?" - To ensure that there is no greedy match
@@ -71,15 +84,12 @@ type Parser struct {
// New create a new Parser
func New(optFns ...ParseOptFn) *Parser {
opts := &ParseOpts{
Getter: os.Getenv,
Regexp: envRegex,
Keyword: "${",
}
opts := &ParseOpts{Getter: os.Getenv}
opts.useDefaultRegex()
for _, fn := range optFns {
fn(opts)
}
return &Parser{ParseOpts: *opts}
}
@@ -92,13 +102,19 @@ func New(optFns ...ParseOptFn) *Parser {
// ${var_name | ?error} With error on value is empty.
func (p *Parser) Parse(val string) (newVal string, err error) {
if p.Regexp == nil {
p.Regexp = envRegex
p.useDefaultRegex()
}
if p.Keyword != "" && !strings.Contains(val, p.Keyword) {
times := strings.Count(val, p.VarLeft)
if times == 0 {
return val, nil
}
// enhance: see https://github.com/gookit/goutil/issues/135
if times == 1 && strings.HasPrefix(val, p.VarLeft) && strings.HasSuffix(val, p.VarRight) {
return p.parseOne(val)
}
// parse expression
newVal = p.Regexp.ReplaceAllStringFunc(val, func(s string) string {
if err != nil {
@@ -116,11 +132,11 @@ func (p *Parser) parseOne(eVar string) (val string, err error) {
return p.ParseFn(eVar)
}
// eVar like "${NotExist|defValue}", first remove "${" and "}", then split it
// like "${NotExist | defValue}". first remove "${" and "}", then split it
ss := strings.SplitN(eVar[2:len(eVar)-1], SepChar, 2)
var name, def string
// with default value. ${NotExist|defValue}
// with default value.
if len(ss) == 2 {
name, def = strings.TrimSpace(ss[0]), strings.TrimSpace(ss[1])
} else {
@@ -131,7 +147,7 @@ func (p *Parser) parseOne(eVar string) (val string, err error) {
val = p.Getter(name)
if val == "" && def != "" {
// check def is "?error"
if def[0] == '?' {
if def[0] == mustPrefix {
msg := "value is required for var: " + name
if len(def) > 1 {
msg = def[1:]

View File

@@ -20,8 +20,8 @@ func (d Data) Has(key string) bool {
return ok
}
// IsEmtpy if the data map
func (d Data) IsEmtpy() bool {
// IsEmpty if the data map
func (d Data) IsEmpty() bool {
return len(d) == 0
}
@@ -127,13 +127,21 @@ func (d Data) Int64(key string) int64 {
}
// Uint value get
func (d Data) Uint(key string) uint64 {
func (d Data) Uint(key string) uint {
if val, ok := d.GetByPath(key); ok {
return mathutil.QuietUint(val)
}
return 0
}
// Uint64 value get
func (d Data) Uint64(key string) uint64 {
if val, ok := d.GetByPath(key); ok {
return mathutil.QuietUint64(val)
}
return 0
}
// Str value get by key
func (d Data) Str(key string) string {
if val, ok := d.GetByPath(key); ok {
@@ -223,6 +231,16 @@ func (d Data) Sub(key string) Data {
return nil
}
// Slice get []any value from data map
func (d Data) Slice(key string) ([]any, error) {
val, ok := d.GetByPath(key)
if !ok {
return nil, nil
}
return arrutil.AnyToSlice(val)
}
// Keys of the data map
func (d Data) Keys() []string {
keys := make([]string, 0, len(d))

View File

@@ -16,8 +16,7 @@ const (
KeySepChar = '.'
)
// SimpleMerge simple merge two data map by string key.
// will merge the src to dst map
// SimpleMerge simple merge two data map by string key. will merge the src to dst map
func SimpleMerge(src, dst map[string]any) map[string]any {
if len(src) == 0 {
return dst
@@ -66,6 +65,27 @@ func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]stri
return dst
}
// MergeMultiSMap quick merge multi string-map data.
func MergeMultiSMap(mps ...map[string]string) map[string]string {
newMp := make(map[string]string)
for _, mp := range mps {
for k, v := range mp {
newMp[k] = v
}
}
return newMp
}
// FilterSMap filter empty elem for the string map.
func FilterSMap(sm map[string]string) map[string]string {
for key, val := range sm {
if val == "" {
delete(sm, key)
}
}
return sm
}
// MakeByPath build new value by key names
//
// Example:

View File

@@ -105,6 +105,20 @@ func (m SMap) Strings(key string) (ss []string) {
return
}
// IfExist key, then call the fn with value.
func (m SMap) IfExist(key string, fn func(val string)) {
if val, ok := m[key]; ok {
fn(val)
}
}
// IfValid value is not empty, then call the fn
func (m SMap) IfValid(key string, fn func(val string)) {
if val, ok := m[key]; ok && val != "" {
fn(val)
}
}
// Keys of the string-map
func (m SMap) Keys() []string {
keys := make([]string, 0, len(m))

View File

@@ -3,11 +3,14 @@ package mathutil
import (
"fmt"
"math"
"reflect"
"strconv"
"strings"
"time"
"github.com/gookit/goutil/comdef"
"github.com/gookit/goutil/internal/checkfn"
"github.com/gookit/goutil/internal/comfunc"
)
// ToIntFunc convert value to int
@@ -17,19 +20,76 @@ type ToIntFunc func(any) (int, error)
type ToInt64Func func(any) (int64, error)
// ToUintFunc convert value to uint
type ToUintFunc func(any) (uint64, error)
type ToUintFunc func(any) (uint, error)
// ToUint64Func convert value to uint
type ToUint64Func func(any) (uint64, error)
// ToFloatFunc convert value to float
type ToFloatFunc func(any) (float64, error)
// ToTypeFunc convert value to defined type
type ToTypeFunc[T any] func(any) (T, error)
// ConvOption convert options
type ConvOption[T any] struct {
// if ture: value is nil, will return convert error;
// if false(default): value is nil, will convert to zero value
NilAsFail bool
// HandlePtr auto convert ptr type(int,float,string) value. eg: *int to int
// - if true: will use real type try convert. default is false
// - NOTE: current T type's ptr is default support.
HandlePtr bool
// set custom fallback convert func for not supported type.
UserConvFn ToTypeFunc[T]
}
// NewConvOption create a new ConvOption
func NewConvOption[T any](optFns ...ConvOptionFn[T]) *ConvOption[T] {
opt := &ConvOption[T]{}
opt.WithOption(optFns...)
return opt
}
// WithOption set convert option
func (opt *ConvOption[T]) WithOption(optFns ...ConvOptionFn[T]) {
for _, fn := range optFns {
if fn != nil {
fn(opt)
}
}
}
// ConvOptionFn convert option func
type ConvOptionFn[T any] func(opt *ConvOption[T])
// WithNilAsFail set ConvOption.NilAsFail option
//
// Example:
//
// ToIntWithFunc(val, mathutil.WithNilAsFail[int])
func WithNilAsFail[T any](opt *ConvOption[T]) {
opt.NilAsFail = true
}
// WithHandlePtr set ConvOption.HandlePtr option
func WithHandlePtr[T any](opt *ConvOption[T]) {
opt.HandlePtr = true
}
// WithUserConvFn set ConvOption.UserConvFn option
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T] {
return func(opt *ConvOption[T]) {
opt.UserConvFn = fn
}
}
/*************************************************************
* convert value to int
*************************************************************/
// Int convert value to int
func Int(in any) (int, error) {
return ToInt(in)
}
func Int(in any) (int, error) { return ToInt(in) }
// SafeInt convert value to int, will ignore error
func SafeInt(in any) int {
@@ -38,12 +98,10 @@ func SafeInt(in any) int {
}
// QuietInt convert value to int, will ignore error
func QuietInt(in any) int {
return SafeInt(in)
}
func QuietInt(in any) int { return SafeInt(in) }
// MustInt convert value to int, will panic on error
func MustInt(in any) int {
// IntOrPanic convert value to int, will panic on error
func IntOrPanic(in any) int {
val, err := ToInt(in)
if err != nil {
panic(err)
@@ -51,19 +109,15 @@ func MustInt(in any) int {
return val
}
// IntOrPanic convert value to int, will panic on error
func IntOrPanic(in any) int {
return MustInt(in)
}
// MustInt convert value to int, will panic on error
func MustInt(in any) int { return IntOrPanic(in) }
// IntOrDefault convert value to int, return defaultVal on failed
func IntOrDefault(in any, defVal int) int {
return IntOr(in, defVal)
}
func IntOrDefault(in any, defVal int) int { return IntOr(in, defVal) }
// IntOr convert value to int, return defaultVal on failed
func IntOr(in any, defVal int) int {
val, err := ToIntWithFunc(in, nil)
val, err := ToIntWith(in)
if err != nil {
return defVal
}
@@ -71,20 +125,28 @@ func IntOr(in any, defVal int) int {
}
// IntOrErr convert value to int, return error on failed
func IntOrErr(in any) (iVal int, err error) {
return ToIntWithFunc(in, nil)
}
func IntOrErr(in any) (int, error) { return ToIntWith(in) }
// ToInt convert value to int, return error on failed
func ToInt(in any) (iVal int, err error) {
return ToIntWithFunc(in, nil)
}
func ToInt(in any) (int, error) { return ToIntWith(in) }
// ToIntWith convert value to int, can with some option func.
//
// Example:
//
// ToIntWithFunc(val, mathutil.WithNilAsFail, mathutil.WithUserConvFn(func(in any) (int, error) {
// })
func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error) {
opt := NewConvOption[int](optFns...)
if !opt.NilAsFail && in == nil {
return 0, nil
}
// ToIntWithFunc convert value to int, will call usrFn on value type not supported.
func ToIntWithFunc(in any, usrFn ToIntFunc) (iVal int, err error) {
switch tVal := in.(type) {
case int:
iVal = tVal
case *int: // default support int ptr type
iVal = *tVal
case int8:
iVal = int(tVal)
case int16:
@@ -131,7 +193,7 @@ func ToIntWithFunc(in any, usrFn ToIntFunc) (iVal int, err error) {
}
case string:
iVal, err = strconv.Atoi(strings.TrimSpace(tVal))
case interface{ Int64() (int64, error) }: // eg: json.Number
case comdef.Int64able: // eg: json.Number
var i64 int64
if i64, err = tVal.Int64(); err == nil {
if i64 > math.MaxInt32 {
@@ -141,11 +203,19 @@ func ToIntWithFunc(in any, usrFn ToIntFunc) (iVal int, err error) {
}
}
default:
if usrFn != nil {
return usrFn(in)
} else {
err = comdef.ErrConvType
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToIntWith(rv.Interface(), optFns...)
}
}
}
if opt.UserConvFn != nil {
return opt.UserConvFn(in)
}
err = comdef.ErrConvType
}
return
}
@@ -165,29 +235,127 @@ func StrIntOr(s string, defVal int) int {
return iVal
}
/*************************************************************
* convert value to int64
*************************************************************/
// Int64 convert value to int64, return error on failed
func Int64(in any) (int64, error) { return ToInt64(in) }
// SafeInt64 convert value to int64, will ignore error
func SafeInt64(in any) int64 {
i64, _ := ToInt64With(in)
return i64
}
// QuietInt64 convert value to int64, will ignore error
func QuietInt64(in any) int64 { return SafeInt64(in) }
// MustInt64 convert value to int64, will panic on error
func MustInt64(in any) int64 {
i64, err := ToInt64With(in)
if err != nil {
panic(err)
}
return i64
}
// Int64OrDefault convert value to int64, return default val on failed
func Int64OrDefault(in any, defVal int64) int64 { return Int64Or(in, defVal) }
// Int64Or convert value to int64, return default val on failed
func Int64Or(in any, defVal int64) int64 {
i64, err := ToInt64With(in)
if err != nil {
return defVal
}
return i64
}
// ToInt64 convert value to int64, return error on failed
func ToInt64(in any) (int64, error) { return ToInt64With(in) }
// Int64OrErr convert value to int64, return error on failed
func Int64OrErr(in any) (int64, error) { return ToInt64With(in) }
// ToInt64With try to convert value to int64. can with some option func, more see ConvOption.
func ToInt64With(in any, optFns ...ConvOptionFn[int64]) (i64 int64, err error) {
opt := NewConvOption(optFns...)
if !opt.NilAsFail && in == nil {
return 0, nil
}
switch tVal := in.(type) {
case string:
i64, err = strconv.ParseInt(strings.TrimSpace(tVal), 10, 0)
case int:
i64 = int64(tVal)
case int8:
i64 = int64(tVal)
case int16:
i64 = int64(tVal)
case int32:
i64 = int64(tVal)
case int64:
i64 = tVal
case *int64: // default support int64 ptr type
i64 = *tVal
case uint:
i64 = int64(tVal)
case uint8:
i64 = int64(tVal)
case uint16:
i64 = int64(tVal)
case uint32:
i64 = int64(tVal)
case uint64:
i64 = int64(tVal)
case float32:
i64 = int64(tVal)
case float64:
i64 = int64(tVal)
case time.Duration:
i64 = int64(tVal)
case comdef.Int64able: // eg: json.Number
i64, err = tVal.Int64()
default:
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToInt64With(rv.Interface(), optFns...)
}
}
}
if opt.UserConvFn != nil {
i64, err = opt.UserConvFn(in)
} else {
err = comdef.ErrConvType
}
}
return
}
/*************************************************************
* convert value to uint
*************************************************************/
// Uint convert any to uint, return error on failed
func Uint(in any) (uint64, error) {
return ToUint(in)
}
func Uint(in any) (uint, error) { return ToUint(in) }
// SafeUint convert any to uint, will ignore error
func SafeUint(in any) uint64 {
func SafeUint(in any) uint {
val, _ := ToUint(in)
return val
}
// QuietUint convert any to uint, will ignore error
func QuietUint(in any) uint64 {
return SafeUint(in)
}
func QuietUint(in any) uint { return SafeUint(in) }
// MustUint convert any to uint, will panic on error
func MustUint(in any) uint64 {
val, err := ToUintWithFunc(in, nil)
func MustUint(in any) uint {
val, err := ToUintWith(in)
if err != nil {
panic(err)
}
@@ -195,13 +363,11 @@ func MustUint(in any) uint64 {
}
// UintOrDefault convert any to uint, return default val on failed
func UintOrDefault(in any, defVal uint64) uint64 {
return UintOr(in, defVal)
}
func UintOrDefault(in any, defVal uint) uint { return UintOr(in, defVal) }
// UintOr convert any to uint, return default val on failed
func UintOr(in any, defVal uint64) uint64 {
val, err := ToUintWithFunc(in, nil)
func UintOr(in any, defVal uint) uint {
val, err := ToUintWith(in)
if err != nil {
return defVal
}
@@ -209,17 +375,124 @@ func UintOr(in any, defVal uint64) uint64 {
}
// UintOrErr convert value to uint, return error on failed
func UintOrErr(in any) (uint64, error) {
return ToUintWithFunc(in, nil)
}
func UintOrErr(in any) (uint, error) { return ToUintWith(in) }
// ToUint convert value to uint, return error on failed
func ToUint(in any) (u64 uint64, err error) {
return ToUintWithFunc(in, nil)
func ToUint(in any) (u64 uint, err error) { return ToUintWith(in) }
// ToUintWith try to convert value to uint. can with some option func, more see ConvOption.
func ToUintWith(in any, optFns ...ConvOptionFn[uint]) (uVal uint, err error) {
opt := NewConvOption(optFns...)
if !opt.NilAsFail && in == nil {
return 0, nil
}
switch tVal := in.(type) {
case int:
uVal = uint(tVal)
case int8:
uVal = uint(tVal)
case int16:
uVal = uint(tVal)
case int32:
uVal = uint(tVal)
case int64:
uVal = uint(tVal)
case uint:
uVal = tVal
case *uint: // default support uint ptr type
uVal = *tVal
case uint8:
uVal = uint(tVal)
case uint16:
uVal = uint(tVal)
case uint32:
uVal = uint(tVal)
case uint64:
uVal = uint(tVal)
case float32:
uVal = uint(tVal)
case float64:
uVal = uint(tVal)
case time.Duration:
uVal = uint(tVal)
case comdef.Int64able: // eg: json.Number
var i64 int64
i64, err = tVal.Int64()
uVal = uint(i64)
case string:
var u64 uint64
u64, err = strconv.ParseUint(strings.TrimSpace(tVal), 10, 0)
uVal = uint(u64)
default:
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToUintWith(rv.Interface(), optFns...)
}
}
}
if opt.UserConvFn != nil {
uVal, err = opt.UserConvFn(in)
} else {
err = comdef.ErrConvType
}
}
return
}
// ToUintWithFunc convert value to uint, will call usrFn on value type not supported.
func ToUintWithFunc(in any, usrFn ToUintFunc) (u64 uint64, err error) {
/*************************************************************
* convert value to uint64
*************************************************************/
// Uint64 convert any to uint64, return error on failed
func Uint64(in any) (uint64, error) { return ToUint64(in) }
// QuietUint64 convert any to uint64, will ignore error
func QuietUint64(in any) uint64 { return SafeUint64(in) }
// SafeUint64 convert any to uint64, will ignore error
func SafeUint64(in any) uint64 {
val, _ := ToUint64(in)
return val
}
// MustUint64 convert any to uint64, will panic on error
func MustUint64(in any) uint64 {
val, err := ToUint64With(in)
if err != nil {
panic(err)
}
return val
}
// Uint64OrDefault convert any to uint64, return default val on failed
func Uint64OrDefault(in any, defVal uint64) uint64 { return Uint64Or(in, defVal) }
// Uint64Or convert any to uint64, return default val on failed
func Uint64Or(in any, defVal uint64) uint64 {
val, err := ToUint64With(in)
if err != nil {
return defVal
}
return val
}
// Uint64OrErr convert value to uint64, return error on failed
func Uint64OrErr(in any) (uint64, error) { return ToUint64With(in) }
// ToUint64 convert value to uint64, return error on failed
func ToUint64(in any) (uint64, error) { return ToUint64With(in) }
// ToUint64With try to convert value to uint64. can with some option func, more see ConvOption.
func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error) {
opt := NewConvOption(optFns...)
if !opt.NilAsFail && in == nil {
return 0, nil
}
switch tVal := in.(type) {
case int:
u64 = uint64(tVal)
@@ -241,21 +514,32 @@ func ToUintWithFunc(in any, usrFn ToUintFunc) (u64 uint64, err error) {
u64 = uint64(tVal)
case uint64:
u64 = tVal
case *uint64: // default support uint64 ptr type
u64 = *tVal
case float32:
u64 = uint64(tVal)
case float64:
u64 = uint64(tVal)
case time.Duration:
u64 = uint64(tVal)
case interface{ Int64() (int64, error) }: // eg: json.Number
case comdef.Int64able: // eg: json.Number
var i64 int64
i64, err = tVal.Int64()
u64 = uint64(i64)
case string:
u64, err = strconv.ParseUint(strings.TrimSpace(tVal), 10, 0)
default:
if usrFn != nil {
u64, err = usrFn(in)
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToUint64With(rv.Interface(), optFns...)
}
}
}
if opt.UserConvFn != nil {
u64, err = opt.UserConvFn(in)
} else {
err = comdef.ErrConvType
}
@@ -264,124 +548,24 @@ func ToUintWithFunc(in any, usrFn ToUintFunc) (u64 uint64, err error) {
}
/*************************************************************
* convert value to int64
*************************************************************/
// Int64 convert value to int64, return error on failed
func Int64(in any) (int64, error) {
return ToInt64(in)
}
// SafeInt64 convert value to int64, will ignore error
func SafeInt64(in any) int64 {
i64, _ := ToInt64WithFunc(in, nil)
return i64
}
// QuietInt64 convert value to int64, will ignore error
func QuietInt64(in any) int64 {
return SafeInt64(in)
}
// MustInt64 convert value to int64, will panic on error
func MustInt64(in any) int64 {
i64, err := ToInt64WithFunc(in, nil)
if err != nil {
panic(err)
}
return i64
}
// Int64OrDefault convert value to int64, return default val on failed
func Int64OrDefault(in any, defVal int64) int64 {
return Int64Or(in, defVal)
}
// Int64Or convert value to int64, return default val on failed
func Int64Or(in any, defVal int64) int64 {
i64, err := ToInt64WithFunc(in, nil)
if err != nil {
return defVal
}
return i64
}
// Int64OrErr convert value to int64, return error on failed
func Int64OrErr(in any) (int64, error) {
return ToInt64(in)
}
// ToInt64 convert value to int64, return error on failed
func ToInt64(in any) (i64 int64, err error) {
return ToInt64WithFunc(in, nil)
}
// ToInt64WithFunc convert value to int64, will call usrFn on value type not supported.
func ToInt64WithFunc(in any, usrFn ToInt64Func) (i64 int64, err error) {
switch tVal := in.(type) {
case string:
i64, err = strconv.ParseInt(strings.TrimSpace(tVal), 10, 0)
case int:
i64 = int64(tVal)
case int8:
i64 = int64(tVal)
case int16:
i64 = int64(tVal)
case int32:
i64 = int64(tVal)
case int64:
i64 = tVal
case uint:
i64 = int64(tVal)
case uint8:
i64 = int64(tVal)
case uint16:
i64 = int64(tVal)
case uint32:
i64 = int64(tVal)
case uint64:
i64 = int64(tVal)
case float32:
i64 = int64(tVal)
case float64:
i64 = int64(tVal)
case time.Duration:
i64 = int64(tVal)
case interface{ Int64() (int64, error) }: // eg: json.Number
i64, err = tVal.Int64()
default:
if usrFn != nil {
i64, err = usrFn(in)
} else {
err = comdef.ErrConvType
}
}
return
}
/*************************************************************
* convert value to float
* convert value to float64
*************************************************************/
// QuietFloat convert value to float64, will ignore error. alias of SafeFloat
func QuietFloat(in any) float64 {
return SafeFloat(in)
}
func QuietFloat(in any) float64 { return SafeFloat(in) }
// SafeFloat convert value to float64, will ignore error
func SafeFloat(in any) float64 {
val, _ := ToFloatWithFunc(in, nil)
val, _ := ToFloatWith(in)
return val
}
// FloatOrPanic convert value to float64, will panic on error
func FloatOrPanic(in any) float64 {
return MustFloat(in)
}
func FloatOrPanic(in any) float64 { return MustFloat(in) }
// MustFloat convert value to float64, will panic on error
func MustFloat(in any) float64 {
val, err := ToFloatWithFunc(in, nil)
val, err := ToFloatWith(in)
if err != nil {
panic(err)
}
@@ -389,13 +573,11 @@ func MustFloat(in any) float64 {
}
// FloatOrDefault convert value to float64, will return default value on error
func FloatOrDefault(in any, defVal float64) float64 {
return FloatOr(in, defVal)
}
func FloatOrDefault(in any, defVal float64) float64 { return FloatOr(in, defVal) }
// FloatOr convert value to float64, will return default value on error
func FloatOr(in any, defVal float64) float64 {
val, err := ToFloatWithFunc(in, nil)
val, err := ToFloatWith(in)
if err != nil {
return defVal
}
@@ -403,22 +585,21 @@ func FloatOr(in any, defVal float64) float64 {
}
// Float convert value to float64, return error on failed
func Float(in any) (float64, error) {
return ToFloatWithFunc(in, nil)
}
func Float(in any) (float64, error) { return ToFloatWith(in) }
// FloatOrErr convert value to float64, return error on failed
func FloatOrErr(in any) (float64, error) {
return ToFloatWithFunc(in, nil)
}
func FloatOrErr(in any) (float64, error) { return ToFloatWith(in) }
// ToFloat convert value to float64, return error on failed
func ToFloat(in any) (f64 float64, err error) {
return ToFloatWithFunc(in, nil)
}
func ToFloat(in any) (float64, error) { return ToFloatWith(in) }
// ToFloatWith try to convert value to float64. can with some option func, more see ConvOption.
func ToFloatWith(in any, optFns ...ConvOptionFn[float64]) (f64 float64, err error) {
opt := NewConvOption(optFns...)
if !opt.NilAsFail && in == nil {
return 0, nil
}
// ToFloatWithFunc convert value to float64, will call usrFn if value type not supported.
func ToFloatWithFunc(in any, usrFn ToFloatFunc) (f64 float64, err error) {
switch tVal := in.(type) {
case string:
f64, err = strconv.ParseFloat(strings.TrimSpace(tVal), 64)
@@ -446,13 +627,24 @@ func ToFloatWithFunc(in any, usrFn ToFloatFunc) (f64 float64, err error) {
f64 = float64(tVal)
case float64:
f64 = tVal
case *float64: // default support float64 ptr type
f64 = *tVal
case time.Duration:
f64 = float64(tVal)
case interface{ Float64() (float64, error) }: // eg: json.Number
case comdef.Float64able: // eg: json.Number
f64, err = tVal.Float64()
default:
if usrFn != nil {
f64, err = usrFn(in)
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToFloatWith(rv.Interface(), optFns...)
}
}
}
if opt.UserConvFn != nil {
f64, err = opt.UserConvFn(in)
} else {
err = comdef.ErrConvType
}
@@ -466,7 +658,7 @@ func ToFloatWithFunc(in any, usrFn ToFloatFunc) (f64 float64, err error) {
// MustString convert intX/floatX value to string, will panic on error
func MustString(val any) string {
str, err := ToStringWithFunc(val, nil)
str, err := ToStringWith(val)
if err != nil {
panic(err)
}
@@ -477,13 +669,11 @@ func MustString(val any) string {
func StringOrPanic(val any) string { return MustString(val) }
// StringOrDefault convert intX/floatX value to string, will return default value on error
func StringOrDefault(val any, defVal string) string {
return StringOr(val, defVal)
}
func StringOrDefault(val any, defVal string) string { return StringOr(val, defVal) }
// StringOr convert intX/floatX value to string, will return default value on error
func StringOr(val any, defVal string) string {
str, err := ToStringWithFunc(val, nil)
str, err := ToStringWith(val)
if err != nil {
return defVal
}
@@ -491,19 +681,13 @@ func StringOr(val any, defVal string) string {
}
// ToString convert intX/floatX value to string, return error on failed
func ToString(val any) (string, error) {
return ToStringWithFunc(val, nil)
}
func ToString(val any) (string, error) { return ToStringWith(val) }
// StringOrErr convert intX/floatX value to string, return error on failed
func StringOrErr(val any) (string, error) {
return ToStringWithFunc(val, nil)
}
func StringOrErr(val any) (string, error) { return ToStringWith(val) }
// QuietString convert intX/floatX value to string, other type convert by fmt.Sprint
func QuietString(val any) string {
return SafeString(val)
}
func QuietString(val any) string { return SafeString(val) }
// String convert intX/floatX value to string, other type convert by fmt.Sprint
func String(val any) string {
@@ -520,76 +704,15 @@ func SafeString(val any) string {
// TryToString try convert intX/floatX value to string
//
// if defaultAsErr is False, will use fmt.Sprint convert other type
func TryToString(val any, defaultAsErr bool) (str string, err error) {
var usrFn comdef.ToStringFunc
func TryToString(val any, defaultAsErr bool) (string, error) {
var optFn comfunc.ConvOptionFn
if !defaultAsErr {
usrFn = func(v any) (string, error) {
if val == nil {
return "", nil
}
return fmt.Sprint(v), nil
}
optFn = comfunc.WithUserConvFn(comfunc.StrBySprintFn)
}
return ToStringWithFunc(val, usrFn)
return ToStringWith(val, optFn)
}
// ToStringWithFunc try convert intX/floatX value to string, will call usrFn if value type not supported.
//
// if defaultAsErr is False, will use fmt.Sprint convert other type
func ToStringWithFunc(val any, usrFn comdef.ToStringFunc) (str string, err error) {
switch value := val.(type) {
case int:
str = strconv.Itoa(value)
case int8:
str = strconv.Itoa(int(value))
case int16:
str = strconv.Itoa(int(value))
case int32: // same as `rune`
str = strconv.Itoa(int(value))
case int64:
str = strconv.FormatInt(value, 10)
case uint:
str = strconv.FormatUint(uint64(value), 10)
case uint8:
str = strconv.FormatUint(uint64(value), 10)
case uint16:
str = strconv.FormatUint(uint64(value), 10)
case uint32:
str = strconv.FormatUint(uint64(value), 10)
case uint64:
str = strconv.FormatUint(value, 10)
case float32:
str = strconv.FormatFloat(float64(value), 'f', -1, 32)
case float64:
str = strconv.FormatFloat(value, 'f', -1, 64)
case time.Duration:
str = strconv.FormatInt(int64(value), 10)
case string:
str = value
case fmt.Stringer:
str = value.String()
default:
if usrFn != nil {
str, err = usrFn(val)
} else {
err = comdef.ErrConvType
}
}
return
}
// Percent returns a values percent of the total
func Percent(val, total int) float64 {
if total == 0 {
return float64(0)
}
return (float64(val) / float64(total)) * 100
}
// ElapsedTime calc elapsed time 计算运行时间消耗 单位 ms(毫秒)
//
// Deprecated: use timex.ElapsedTime()
func ElapsedTime(startTime time.Time) string {
return fmt.Sprintf("%.3f", time.Since(startTime).Seconds()*1000)
// ToStringWith try to convert value to string. can with some option func, more see comfunc.ConvOption.
func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error) {
return comfunc.ToStringWith(in, optFns...)
}

View File

@@ -2,6 +2,8 @@
package mathutil
import (
"math"
"github.com/gookit/goutil/comdef"
)
@@ -71,3 +73,37 @@ func GteOr[T comdef.XintOrFloat](val, min, defVal T) T {
}
return defVal
}
// Mul computes the a*b value, rounding the result.
func Mul[T1, T2 comdef.XintOrFloat](a T1, b T2) float64 {
return math.Round(SafeFloat(a) * SafeFloat(b))
}
// MulF2i computes the float64 type a * b value, rounding the result to an integer.
func MulF2i(a, b float64) int {
return int(math.Round(a * b))
}
// Div computes the a/b value, result use round handle.
func Div[T1, T2 comdef.XintOrFloat](a T1, b T2) float64 {
return math.Round(SafeFloat(a) / SafeFloat(b))
}
// DivInt computes the int type a / b value, rounding the result to an integer.
func DivInt[T comdef.Integer](a, b T) int {
fv := math.Round(float64(a) / float64(b))
return int(fv)
}
// DivF2i computes the float64 type a / b value, rounding the result to an integer.
func DivF2i(a, b float64) int {
return int(math.Round(a / b))
}
// Percent returns a values percent of the total
func Percent(val, total int) float64 {
if total == 0 {
return float64(0)
}
return (float64(val) / float64(total)) * 100
}

View File

@@ -10,8 +10,9 @@ func HasChild(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.Map, reflect.Struct:
return true
default:
return false
}
return false
}
// IsArrayOrSlice check. eg: array, slice
@@ -122,9 +123,9 @@ func IsEmpty(v reflect.Value) bool {
return v.Float() == 0
case reflect.Interface, reflect.Ptr, reflect.Func:
return v.IsNil()
default:
return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}
return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}
// IsEmptyValue reflect value check, alias of the IsEmptyReal()
@@ -158,7 +159,7 @@ func IsEmptyReal(v reflect.Value) bool {
return v.IsNil()
case reflect.Invalid:
return true
default:
return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}
return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}

View File

@@ -126,12 +126,12 @@ func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
rv = reflect.ValueOf(dstV)
}
case reflect.Uint:
var dstV uint64
var dstV uint
if dstV, err = mathutil.ToUint(val); err == nil {
rv = reflect.ValueOf(uint(dstV))
rv = reflect.ValueOf(dstV)
}
case reflect.Uint8:
var dstV uint64
var dstV uint
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV > math.MaxUint8 {
return rv, fmt.Errorf("value overflow uint8. val: %v", val)
@@ -139,7 +139,7 @@ func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
rv = reflect.ValueOf(uint8(dstV))
}
case reflect.Uint16:
var dstV uint64
var dstV uint
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV > math.MaxUint16 {
return rv, fmt.Errorf("value overflow uint16. val: %v", val)
@@ -147,7 +147,7 @@ func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
rv = reflect.ValueOf(uint16(dstV))
}
case reflect.Uint32:
var dstV uint64
var dstV uint
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV > math.MaxUint32 {
return rv, fmt.Errorf("value overflow uint32. val: %v", val)
@@ -156,7 +156,7 @@ func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
}
case reflect.Uint64:
var dstV uint64
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV, err = mathutil.ToUint64(val); err == nil {
rv = reflect.ValueOf(dstV)
}
case reflect.Float32:

View File

@@ -2,7 +2,6 @@
package reflects
import (
"fmt"
"reflect"
)
@@ -12,6 +11,6 @@ var (
anyType = reflect.TypeOf((*any)(nil)).Elem()
errorType = reflect.TypeOf((*error)(nil)).Elem()
fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
// fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem()
)

View File

@@ -4,9 +4,12 @@ import (
"errors"
"fmt"
"reflect"
"time"
"github.com/gookit/goutil/comdef"
"github.com/gookit/goutil/maputil"
"github.com/gookit/goutil/reflects"
"github.com/gookit/goutil/strutil"
)
// NewWriter create a struct writer
@@ -46,6 +49,9 @@ type SetOptions struct {
//
// default: false
ParseDefaultEnv bool
// StopOnError if true, will stop set value on error happened. default: false
// StopOnError bool
}
// WithParseDefault value by tag "default"
@@ -85,6 +91,7 @@ func setValues(rv reflect.Value, data map[string]any, opt *SetOptions) error {
return nil
}
var es comdef.Errors
rt := rv.Type()
for i := 0; i < rt.NumField(); i++ {
@@ -100,7 +107,8 @@ func setValues(rv reflect.Value, data map[string]any, opt *SetOptions) error {
if ok {
info, err := ParseTagValueDefault(name, tagVal)
if err != nil {
return err
es = append(es, err)
continue
}
name = info.Get("name")
}
@@ -112,7 +120,7 @@ func setValues(rv reflect.Value, data map[string]any, opt *SetOptions) error {
if !ok && opt.ParseDefault && fv.IsZero() {
defVal := ft.Tag.Get(opt.DefaultValTag)
if err := initDefaultValue(fv, defVal, opt.ParseDefaultEnv); err != nil {
return err
es = append(es, err)
}
continue
}
@@ -127,22 +135,39 @@ func setValues(rv reflect.Value, data map[string]any, opt *SetOptions) error {
// field is struct
if fv.Kind() == reflect.Struct {
asMp, err := maputil.TryAnyMap(val)
if err != nil {
return fmt.Errorf("must provide map data for field %q, err=%v", ft.Name, err)
// up: special handle time.Time struct
if _, ok := fv.Interface().(time.Time); ok {
tm, er := strutil.ToTime(strutil.StringOr(val, ""))
if er != nil {
es = append(es, er)
continue
}
if er = reflects.SetValue(fv, tm); er != nil {
es = append(es, er)
}
continue
}
if err := setValues(fv, asMp, opt); err != nil {
return err
asMp, err := maputil.TryAnyMap(val)
if err != nil {
err = fmt.Errorf("must provide map for set struct field %q, err=%v", ft.Name, err)
es = append(es, err)
continue
}
// recursive processing sub-struct
if err = setValues(fv, asMp, opt); err != nil {
es = append(es, err)
}
continue
}
// set field value
if err := reflects.SetValue(fv, val); err != nil {
return err
es = append(es, err)
continue
}
}
return nil
return es.ErrOrNil()
}

View File

@@ -2,7 +2,6 @@ package strutil
import (
"errors"
"fmt"
"reflect"
"regexp"
"strconv"
@@ -10,7 +9,6 @@ import (
"time"
"unsafe"
"github.com/gookit/goutil/comdef"
"github.com/gookit/goutil/internal/comfunc"
"github.com/gookit/goutil/mathutil"
)
@@ -91,39 +89,29 @@ func Implode(sep string, ss ...string) string { return strings.Join(ss, sep) }
*************************************************************/
// String convert value to string, return error on failed
func String(val any) (string, error) {
return ToStringWithFunc(val, nil)
}
func String(val any) (string, error) { return ToStringWith(val) }
// ToString convert value to string, return error on failed
func ToString(val any) (string, error) {
return ToStringWithFunc(val, nil)
}
func ToString(val any) (string, error) { return ToStringWith(val) }
// StringOrErr convert value to string, return error on failed
func StringOrErr(val any) (string, error) {
return ToStringWithFunc(val, nil)
}
func StringOrErr(val any) (string, error) { return ToStringWith(val) }
// QuietString convert value to string, will ignore error. same as SafeString()
func QuietString(val any) string {
return SafeString(val)
}
func QuietString(val any) string { return SafeString(val) }
// SafeString convert value to string, will ignore error
func SafeString(in any) string {
val, _ := ToStringWithFunc(in, SprintToStrFunc)
return val
s, _ := AnyToString(in, false)
return s
}
// StringOrPanic convert value to string, will panic on error
func StringOrPanic(val any) string {
return MustString(val)
}
func StringOrPanic(val any) string { return MustString(val) }
// MustString convert value to string, will panic on error
func MustString(val any) string {
s, err := ToStringWithFunc(val, nil)
s, err := ToStringWith(val)
if err != nil {
panic(err)
}
@@ -131,93 +119,34 @@ func MustString(val any) string {
}
// StringOrDefault convert any value to string, return default value on failed
func StringOrDefault(val any, defVal string) string {
return StringOr(val, defVal)
}
func StringOrDefault(val any, defVal string) string { return StringOr(val, defVal) }
// StringOr convert any value to string, return default value on failed
func StringOr(val any, defVal string) string {
s, err := ToStringWithFunc(val, nil)
s, err := ToStringWith(val)
if err != nil {
return defVal
}
return s
}
// SprintToStrFunc convert any value to string by fmt.Sprint
var SprintToStrFunc = func(v any) (string, error) {
if v == nil {
return "", nil
}
return fmt.Sprint(v), nil
}
// AnyToString convert any value to string.
//
// For defaultAsErr:
//
// - False will use fmt.Sprint convert complex type
// - True will return error on fail.
// - False will use fmt.Sprint convert unsupported type
// - True will return error on convert fail.
func AnyToString(val any, defaultAsErr bool) (s string, err error) {
var fbFunc comdef.ToStringFunc
var optFn comfunc.ConvOptionFn
if !defaultAsErr {
fbFunc = SprintToStrFunc
optFn = comfunc.WithUserConvFn(comfunc.StrBySprintFn)
}
return ToStringWithFunc(val, fbFunc)
return ToStringWith(val, optFn)
}
// ToStringWithFunc convert value to string, with a func to fallback handle.
//
// On not convert:
// - If fbFn is nil, will return comdef.ErrConvType.
// - If fbFn is not nil, will call it to convert.
func ToStringWithFunc(val any, fbFn comdef.ToStringFunc) (str string, err error) {
switch value := val.(type) {
case int:
str = strconv.Itoa(value)
case int8:
str = strconv.Itoa(int(value))
case int16:
str = strconv.Itoa(int(value))
case int32: // same as `rune`
str = strconv.Itoa(int(value))
case int64:
str = strconv.FormatInt(value, 10)
case uint:
str = strconv.FormatUint(uint64(value), 10)
case uint8:
str = strconv.FormatUint(uint64(value), 10)
case uint16:
str = strconv.FormatUint(uint64(value), 10)
case uint32:
str = strconv.FormatUint(uint64(value), 10)
case uint64:
str = strconv.FormatUint(value, 10)
case float32:
str = strconv.FormatFloat(float64(value), 'f', -1, 32)
case float64:
str = strconv.FormatFloat(value, 'f', -1, 64)
case bool:
str = strconv.FormatBool(value)
case string:
str = value
case []byte:
str = string(value)
case time.Duration:
str = strconv.FormatInt(int64(value), 10)
case fmt.Stringer:
str = value.String()
case error:
str = value.Error()
default:
if fbFn == nil {
err = comdef.ErrConvType
} else {
str, err = fbFn(value)
}
}
return
// ToStringWith try to convert value to string. can with some option func, more see comfunc.ConvOption.
func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error) {
return comfunc.ToStringWith(in, optFns...)
}
/*************************************************************
@@ -230,9 +159,7 @@ func ToBool(s string) (bool, error) {
}
// QuietBool convert to bool, will ignore error
func QuietBool(s string) bool {
return SafeBool(s)
}
func QuietBool(s string) bool { return SafeBool(s) }
// SafeBool convert to bool, will ignore error
func SafeBool(s string) bool {
@@ -289,14 +216,10 @@ func SafeInt(s string) int {
}
// QuietInt convert string to int, will ignore error
func QuietInt(s string) int {
return SafeInt(s)
}
func QuietInt(s string) int { return SafeInt(s) }
// MustInt convert string to int, will panic on error
func MustInt(s string) int {
return IntOrPanic(s)
}
func MustInt(s string) int { return IntOrPanic(s) }
// IntOrPanic convert value to int, will panic on error
func IntOrPanic(s string) int {
@@ -312,10 +235,10 @@ func IntOrPanic(s string) int {
*************************************************************/
// Int64 convert string to int, will ignore error
func Int64(s string) int64 {
val, _ := Int64OrErr(s)
return val
}
func Int64(s string) int64 { return SafeInt64(s) }
// QuietInt64 convert string to int, will ignore error
func QuietInt64(s string) int64 { return SafeInt64(s) }
// SafeInt64 convert string to int, will ignore error
func SafeInt64(s string) int64 {
@@ -323,11 +246,6 @@ func SafeInt64(s string) int64 {
return val
}
// QuietInt64 convert string to int, will ignore error
func QuietInt64(s string) int64 {
return SafeInt64(s)
}
// ToInt64 convert string to int, return error on fail
func ToInt64(s string) (int64, error) {
return strconv.ParseInt(s, 10, 0)
@@ -353,9 +271,7 @@ func Int64OrErr(s string) (int64, error) {
}
// MustInt64 convert value to int, will panic on error
func MustInt64(s string) int64 {
return Int64OrPanic(s)
}
func MustInt64(s string) int64 { return Int64OrPanic(s) }
// Int64OrPanic convert value to int, will panic on error
func Int64OrPanic(s string) int64 {
@@ -371,10 +287,7 @@ func Int64OrPanic(s string) int64 {
*************************************************************/
// Uint convert string to uint, will ignore error
func Uint(s string) uint64 {
val, _ := UintOrErr(s)
return val
}
func Uint(s string) uint64 { return SafeUint(s) }
// SafeUint convert string to uint, will ignore error
func SafeUint(s string) uint64 {
@@ -393,9 +306,7 @@ func UintOrErr(s string) (uint64, error) {
}
// MustUint convert value to uint, will panic on error. alias of UintOrPanic()
func MustUint(s string) uint64 {
return UintOrPanic(s)
}
func MustUint(s string) uint64 { return UintOrPanic(s) }
// UintOrPanic convert value to uint, will panic on error
func UintOrPanic(s string) uint64 {

View File

@@ -2,12 +2,9 @@
package strutil
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"strings"
"text/template"
"github.com/gookit/goutil/comdef"
)
@@ -92,68 +89,6 @@ func NewReplacer(pairs map[string]string) *strings.Replacer {
return strings.NewReplacer(ss...)
}
// PrettyJSON get pretty Json string
// Deprecated: please use fmtutil.PrettyJSON() or jsonutil.Pretty() instead it
func PrettyJSON(v any) (string, error) {
out, err := json.MarshalIndent(v, "", " ")
return string(out), err
}
var builtInFuncs = template.FuncMap{
// don't escape content
"raw": func(s string) string {
return s
},
"trim": func(s string) string {
return strings.TrimSpace(s)
},
// join strings
"join": func(ss []string, sep string) string {
return strings.Join(ss, sep)
},
// lower first char
"lcFirst": func(s string) string {
return LowerFirst(s)
},
// upper first char
"upFirst": func(s string) string {
return UpperFirst(s)
},
}
// RenderTemplate quickly render text template.
//
// Deprecated: please use textutil.RenderTpl() instead it
func RenderTemplate(input string, data any, fns template.FuncMap, isFile ...bool) string {
return RenderText(input, data, fns, isFile...)
}
// RenderText quickly render text template
//
// Deprecated: please use textutil.RenderTpl() instead it
func RenderText(input string, data any, fns template.FuncMap, isFile ...bool) string {
t := template.New("simple-text")
t.Funcs(builtInFuncs)
// add custom template functions
if len(fns) > 0 {
t.Funcs(fns)
}
if len(isFile) > 0 && isFile[0] {
template.Must(t.ParseFiles(input))
} else {
template.Must(t.Parse(input))
}
// use buffer receive rendered content
buf := new(bytes.Buffer)
if err := t.Execute(buf, data); err != nil {
panic(err)
}
return buf.String()
}
// WrapTag for given string.
func WrapTag(s, tag string) string {
if s == "" {

View File

@@ -5,6 +5,9 @@ issues:
- linters:
- errcheck
text: "Unsubscribe"
- linters:
- errcheck
text: "Drain"
- linters:
- errcheck
text: "msg.Ack"

View File

@@ -14,6 +14,8 @@ A [Go](http://golang.org) client for the [NATS messaging system](https://nats.io
[Coverage-Url]: https://coveralls.io/r/nats-io/nats.go?branch=main
[Coverage-image]: https://coveralls.io/repos/github/nats-io/nats.go/badge.svg?branch=main
**Check out [NATS by example](https://natsbyexample.com) - An evolving collection of runnable, cross-client reference examples for NATS.**
## Installation
```bash
@@ -29,7 +31,7 @@ When using or transitioning to Go modules support:
```bash
# Go client latest or explicit version
go get github.com/nats-io/nats.go/@latest
go get github.com/nats-io/nats.go/@v1.31.0
go get github.com/nats-io/nats.go/@v1.32.0
# For latest NATS Server, add /v2 at the end
go get github.com/nats-io/nats-server/v2

View File

@@ -1,4 +1,4 @@
// Copyright 2016-2022 The NATS Authors
// Copyright 2016-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

View File

@@ -1,4 +1,4 @@
// Copyright 2012-2019 The NATS Authors
// Copyright 2012-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

View File

@@ -1,4 +1,4 @@
// Copyright 2012-2018 The NATS Authors
// Copyright 2012-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

View File

@@ -1,4 +1,4 @@
// Copyright 2013-2018 The NATS Authors
// Copyright 2013-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

View File

@@ -1,4 +1,4 @@
// Copyright 2012-2018 The NATS Authors
// Copyright 2012-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

View File

@@ -4,19 +4,19 @@ go 1.19
require (
github.com/golang/protobuf v1.4.2
github.com/klauspost/compress v1.17.0
github.com/nats-io/nats-server/v2 v2.10.0
github.com/nats-io/nkeys v0.4.5
github.com/klauspost/compress v1.17.4
github.com/nats-io/nats-server/v2 v2.10.7
github.com/nats-io/nkeys v0.4.6
github.com/nats-io/nuid v1.0.1
go.uber.org/goleak v1.2.1
golang.org/x/text v0.13.0
golang.org/x/text v0.14.0
google.golang.org/protobuf v1.23.0
)
require (
github.com/minio/highwayhash v1.0.2 // indirect
github.com/nats-io/jwt/v2 v2.5.2 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/time v0.3.0 // indirect
github.com/nats-io/jwt/v2 v2.5.3 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/time v0.5.0 // indirect
)

View File

@@ -10,32 +10,31 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/nats-io/jwt/v2 v2.5.2 h1:DhGH+nKt+wIkDxM6qnVSKjokq5t59AZV5HRcFW0zJwU=
github.com/nats-io/jwt/v2 v2.5.2/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
github.com/nats-io/nats-server/v2 v2.10.0 h1:rcU++Hzo+wARxtJugrV3J5z5iGdHeVG8tT8Chb3bKDg=
github.com/nats-io/nats-server/v2 v2.10.0/go.mod h1:3PMvMSu2cuK0J9YInRLWdFpFsswKKGUS77zVSAudRto=
github.com/nats-io/nkeys v0.4.5 h1:Zdz2BUlFm4fJlierwvGK+yl20IAKUm7eV6AAZXEhkPk=
github.com/nats-io/nkeys v0.4.5/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
github.com/nats-io/jwt/v2 v2.5.3 h1:/9SWvzc6hTfamcgXJ3uYRpgj+QuY2aLNqRiqrKcrpEo=
github.com/nats-io/jwt/v2 v2.5.3/go.mod h1:iysuPemFcc7p4IoYots3IuELSI4EDe9Y0bQMe+I3Bf4=
github.com/nats-io/nats-server/v2 v2.10.7 h1:f5VDy+GMu7JyuFA0Fef+6TfulfCs5nBTgq7MMkFJx5Y=
github.com/nats-io/nats-server/v2 v2.10.7/go.mod h1:V2JHOvPiPdtfDXTuEUsthUnCvSDeFrK4Xn9hRo6du7c=
github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=

View File

@@ -227,14 +227,16 @@ type js struct {
opts *jsOpts
// For async publish context.
mu sync.RWMutex
rpre string
rsub *Subscription
pafs map[string]*pubAckFuture
stc chan struct{}
dch chan struct{}
rr *rand.Rand
connStatusCh chan (Status)
mu sync.RWMutex
rpre string
rsub *Subscription
pafs map[string]*pubAckFuture
stc chan struct{}
dch chan struct{}
rr *rand.Rand
connStatusCh chan (Status)
replyPrefix string
replyPrefixLen int
}
type jsOpts struct {
@@ -283,6 +285,12 @@ func (nc *Conn) JetStream(opts ...JSOpt) (JetStreamContext, error) {
maxpa: defaultAsyncPubAckInflight,
},
}
inboxPrefix := InboxPrefix
if js.nc.Opts.InboxPrefix != _EMPTY_ {
inboxPrefix = js.nc.Opts.InboxPrefix + "."
}
js.replyPrefix = inboxPrefix
js.replyPrefixLen = len(js.replyPrefix) + aReplyTokensize + 1
for _, opt := range opts {
if err := opt.configureJSContext(js.opts); err != nil {
@@ -537,7 +545,7 @@ func (js *js) PublishMsg(m *Msg, opts ...PubOpt) (*PubAck, error) {
}
if err != nil {
for r, ttl := 0, o.ttl; err == ErrNoResponders && (r < o.rnum || o.rnum < 0); r++ {
for r, ttl := 0, o.ttl; errors.Is(err, ErrNoResponders) && (r < o.rnum || o.rnum < 0); r++ {
// To protect against small blips in leadership changes etc, if we get a no responders here retry.
if o.ctx != nil {
select {
@@ -559,7 +567,7 @@ func (js *js) PublishMsg(m *Msg, opts ...PubOpt) (*PubAck, error) {
}
}
if err != nil {
if err == ErrNoResponders {
if errors.Is(err, ErrNoResponders) {
err = ErrNoStreamResponse
}
return nil, err
@@ -641,7 +649,6 @@ func (paf *pubAckFuture) Msg() *Msg {
}
// For quick token lookup etc.
const aReplyPreLen = 14
const aReplyTokensize = 6
func (js *js) newAsyncReply() string {
@@ -654,11 +661,7 @@ func (js *js) newAsyncReply() string {
for i := 0; i < aReplyTokensize; i++ {
b[i] = rdigits[int(b[i]%base)]
}
inboxPrefix := InboxPrefix
if js.nc.Opts.InboxPrefix != _EMPTY_ {
inboxPrefix = js.nc.Opts.InboxPrefix + "."
}
js.rpre = fmt.Sprintf("%s%s.", inboxPrefix, b[:aReplyTokensize])
js.rpre = fmt.Sprintf("%s%s.", js.replyPrefix, b[:aReplyTokensize])
sub, err := js.nc.Subscribe(fmt.Sprintf("%s*", js.rpre), js.handleAsyncReply)
if err != nil {
js.mu.Unlock()
@@ -767,10 +770,10 @@ func (js *js) asyncStall() <-chan struct{} {
// Handle an async reply from PublishAsync.
func (js *js) handleAsyncReply(m *Msg) {
if len(m.Subject) <= aReplyPreLen {
if len(m.Subject) <= js.replyPrefixLen {
return
}
id := m.Subject[aReplyPreLen:]
id := m.Subject[js.replyPrefixLen:]
js.mu.Lock()
paf := js.getPAF(id)
@@ -916,7 +919,7 @@ func (js *js) PublishMsgAsync(m *Msg, opts ...PubOpt) (PubAckFuture, error) {
return nil, errors.New("nats: error creating async reply handler")
}
id := m.Reply[aReplyPreLen:]
id := m.Reply[js.replyPrefixLen:]
paf := &pubAckFuture{msg: m, st: time.Now()}
numPending, maxPending := js.registerPAF(id, paf)
@@ -1241,6 +1244,10 @@ func (sub *Subscription) deleteConsumer() error {
sub.mu.Unlock()
return nil
}
if jsi.stream == _EMPTY_ || jsi.consumer == _EMPTY_ {
sub.mu.Unlock()
return nil
}
stream, consumer := jsi.stream, jsi.consumer
js := jsi.js
sub.mu.Unlock()
@@ -1594,7 +1601,7 @@ func (js *js) subscribe(subj, queue string, cb MsgHandler, ch chan *Msg, isSync,
if consumer != _EMPTY_ && !o.skipCInfo {
info, err = js.ConsumerInfo(stream, consumer)
notFoundErr = errors.Is(err, ErrConsumerNotFound)
lookupErr = err == ErrJetStreamNotEnabled || err == ErrTimeout || err == context.DeadlineExceeded
lookupErr = err == ErrJetStreamNotEnabled || errors.Is(err, ErrTimeout) || errors.Is(err, context.DeadlineExceeded)
}
switch {
@@ -1808,7 +1815,9 @@ func (js *js) subscribe(subj, queue string, cb MsgHandler, ch chan *Msg, isSync,
if bl < DefaultSubPendingBytesLimit {
bl = DefaultSubPendingBytesLimit
}
sub.SetPendingLimits(maxap, bl)
if err := sub.SetPendingLimits(maxap, bl); err != nil {
return nil, err
}
}
// Do heartbeats last if needed.
@@ -2047,7 +2056,16 @@ func (sub *Subscription) resetOrderedConsumer(sseq uint64) {
js := jsi.js
sub.mu.Unlock()
consName := nuid.Next()
sub.mu.Lock()
// Attempt to delete the existing consumer.
// We don't wait for the response since even if it's unsuccessful,
// inactivity threshold will kick in and delete it.
if jsi.consumer != _EMPTY_ {
go js.DeleteConsumer(jsi.stream, jsi.consumer)
}
jsi.consumer = ""
sub.mu.Unlock()
consName := getHash(nuid.Next())
cinfo, err := js.upsertConsumer(jsi.stream, consName, cfg)
if err != nil {
var apiErr *APIError
@@ -2813,7 +2831,7 @@ func (sub *Subscription) Fetch(batch int, opts ...PullOpt) ([]*Msg, error) {
// are no messages.
msg, err = sub.nextMsgWithContext(ctx, true, false)
if err != nil {
if err == errNoMessages {
if errors.Is(err, errNoMessages) {
err = nil
}
break
@@ -2893,13 +2911,13 @@ func (sub *Subscription) Fetch(batch int, opts ...PullOpt) ([]*Msg, error) {
usrMsg, err = checkMsg(msg, true, noWait)
if err == nil && usrMsg {
msgs = append(msgs, msg)
} else if noWait && (err == errNoMessages || err == errRequestsPending) && len(msgs) == 0 {
} else if noWait && (errors.Is(err, errNoMessages) || errors.Is(err, errRequestsPending)) && len(msgs) == 0 {
// If we have a 404/408 for our "no_wait" request and have
// not collected any message, then resend request to
// wait this time.
noWait = false
err = sendReq()
} else if err == ErrTimeout && len(msgs) == 0 {
} else if errors.Is(err, ErrTimeout) && len(msgs) == 0 {
// If we get a 408, we will bail if we already collected some
// messages, otherwise ignore and go back calling nextMsg.
err = nil
@@ -3082,7 +3100,7 @@ func (sub *Subscription) FetchBatch(batch int, opts ...PullOpt) (MessageBatch, e
// are no messages.
msg, err := sub.nextMsgWithContext(ctx, true, false)
if err != nil {
if err == errNoMessages {
if errors.Is(err, errNoMessages) {
err = nil
}
result.err = err
@@ -3159,7 +3177,7 @@ func (sub *Subscription) FetchBatch(batch int, opts ...PullOpt) (MessageBatch, e
usrMsg, err = checkMsg(msg, true, false)
if err != nil {
if err == ErrTimeout {
if errors.Is(err, ErrTimeout) {
if reqID != "" && !subjectMatchesReqID(msg.Subject, reqID) {
// ignore timeout message from server if it comes from a different pull request
continue
@@ -3188,7 +3206,7 @@ func (sub *Subscription) FetchBatch(batch int, opts ...PullOpt) (MessageBatch, e
// checkCtxErr is used to determine whether ErrTimeout should be returned in case of context timeout
func (o *pullOpts) checkCtxErr(err error) error {
if o.ctx == nil && err == context.DeadlineExceeded {
if o.ctx == nil && errors.Is(err, context.DeadlineExceeded) {
return ErrTimeout
}
return err
@@ -3204,7 +3222,7 @@ func (js *js) getConsumerInfoContext(ctx context.Context, stream, consumer strin
ccInfoSubj := fmt.Sprintf(apiConsumerInfoT, stream, consumer)
resp, err := js.apiRequestWithContext(ctx, js.apiSubj(ccInfoSubj), nil)
if err != nil {
if err == ErrNoResponders {
if errors.Is(err, ErrNoResponders) {
err = ErrJetStreamNotEnabled
}
return nil, err

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2022 The NATS Authors
// Copyright 2020-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

View File

@@ -1,4 +1,4 @@
// Copyright 2021-2022 The NATS Authors
// Copyright 2021-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -252,11 +252,13 @@ type AccountInfo struct {
}
type Tier struct {
Memory uint64 `json:"memory"`
Store uint64 `json:"storage"`
Streams int `json:"streams"`
Consumers int `json:"consumers"`
Limits AccountLimits `json:"limits"`
Memory uint64 `json:"memory"`
Store uint64 `json:"storage"`
ReservedMemory uint64 `json:"reserved_memory"`
ReservedStore uint64 `json:"reserved_storage"`
Streams int `json:"streams"`
Consumers int `json:"consumers"`
Limits AccountLimits `json:"limits"`
}
// APIStats reports on API calls to JetStream for this account.
@@ -297,7 +299,7 @@ func (js *js) AccountInfo(opts ...JSOpt) (*AccountInfo, error) {
resp, err := js.apiRequestWithContext(o.ctx, js.apiSubj(apiAccountInfo), nil)
if err != nil {
// todo maybe nats server should never have no responder on this subject and always respond if they know there is no js to be had
if err == ErrNoResponders {
if errors.Is(err, ErrNoResponders) {
err = ErrJetStreamNotEnabled
}
return nil, err
@@ -415,7 +417,7 @@ func (js *js) upsertConsumer(stream, consumerName string, cfg *ConsumerConfig, o
resp, err := js.apiRequestWithContext(o.ctx, js.apiSubj(ccSubj), req)
if err != nil {
if err == ErrNoResponders {
if errors.Is(err, ErrNoResponders) {
err = ErrJetStreamNotEnabled
}
return nil, err
@@ -1623,7 +1625,7 @@ func (jsc *js) StreamNameBySubject(subj string, opts ...JSOpt) (string, error) {
resp, err := jsc.apiRequestWithContext(o.ctx, jsc.apiSubj(apiStreams), j)
if err != nil {
if err == ErrNoResponders {
if errors.Is(err, ErrNoResponders) {
err = ErrJetStreamNotEnabled
}
return _EMPTY_, err

View File

@@ -1,4 +1,4 @@
// Copyright 2021-2022 The NATS Authors
// Copyright 2021-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -65,7 +65,10 @@ type KeyValue interface {
// WatchAll will invoke the callback for all updates.
WatchAll(opts ...WatchOpt) (KeyWatcher, error)
// Keys will return all keys.
// DEPRECATED: Use ListKeys instead to avoid memory issues.
Keys(opts ...WatchOpt) ([]string, error)
// ListKeys will return all keys in a channel.
ListKeys(opts ...WatchOpt) (KeyLister, error)
// History will return all historical values for the key.
History(key string, opts ...WatchOpt) ([]KeyValueEntry, error)
// Bucket returns the current bucket name.
@@ -95,6 +98,9 @@ type KeyValueStatus interface {
// Bytes returns the size in bytes of the bucket
Bytes() uint64
// IsCompressed indicates if the data is compressed on disk
IsCompressed() bool
}
// KeyWatcher is what is returned when doing a watch.
@@ -107,6 +113,12 @@ type KeyWatcher interface {
Stop() error
}
// KeyLister is used to retrieve a list of key value store keys
type KeyLister interface {
Keys() <-chan string
Stop() error
}
type WatchOpt interface {
configureWatcher(opts *watchOpts) error
}
@@ -249,6 +261,10 @@ type KeyValueConfig struct {
RePublish *RePublish
Mirror *StreamSource
Sources []*StreamSource
// Enable underlying stream compression.
// NOTE: Compression is supported for nats-server 2.10.0+
Compression bool
}
// Used to watch all keys.
@@ -343,7 +359,7 @@ func (js *js) KeyValue(bucket string) (KeyValue, error) {
stream := fmt.Sprintf(kvBucketNameTmpl, bucket)
si, err := js.StreamInfo(stream)
if err != nil {
if err == ErrStreamNotFound {
if errors.Is(err, ErrStreamNotFound) {
err = ErrBucketNotFound
}
return nil, err
@@ -405,6 +421,10 @@ func (js *js) CreateKeyValue(cfg *KeyValueConfig) (KeyValue, error) {
if cfg.TTL > 0 && cfg.TTL < duplicateWindow {
duplicateWindow = cfg.TTL
}
var compression StoreCompression
if cfg.Compression {
compression = S2Compression
}
scfg := &StreamConfig{
Name: fmt.Sprintf(kvBucketNameTmpl, cfg.Bucket),
Description: cfg.Description,
@@ -422,6 +442,7 @@ func (js *js) CreateKeyValue(cfg *KeyValueConfig) (KeyValue, error) {
MaxConsumers: -1,
AllowDirect: true,
RePublish: cfg.RePublish,
Compression: compression,
}
if cfg.Mirror != nil {
// Copy in case we need to make changes so we do not change caller's version.
@@ -465,7 +486,7 @@ func (js *js) CreateKeyValue(cfg *KeyValueConfig) (KeyValue, error) {
// the stream.
// The same logic applies for KVs created pre 2.9.x and
// the AllowDirect setting.
if err == ErrStreamNameAlreadyInUse {
if errors.Is(err, ErrStreamNameAlreadyInUse) {
if si, _ = js.StreamInfo(scfg.Name); si != nil {
// To compare, make the server's stream info discard
// policy same than ours.
@@ -537,7 +558,7 @@ func keyValid(key string) bool {
func (kv *kvs) Get(key string) (KeyValueEntry, error) {
e, err := kv.get(key, kvLatestRevision)
if err != nil {
if err == ErrKeyDeleted {
if errors.Is(err, ErrKeyDeleted) {
return nil, ErrKeyNotFound
}
return nil, err
@@ -550,7 +571,7 @@ func (kv *kvs) Get(key string) (KeyValueEntry, error) {
func (kv *kvs) GetRevision(key string, revision uint64) (KeyValueEntry, error) {
e, err := kv.get(key, revision)
if err != nil {
if err == ErrKeyDeleted {
if errors.Is(err, ErrKeyDeleted) {
return nil, ErrKeyNotFound
}
return nil, err
@@ -587,7 +608,7 @@ func (kv *kvs) get(key string, revision uint64) (KeyValueEntry, error) {
}
}
if err != nil {
if err == ErrMsgNotFound {
if errors.Is(err, ErrMsgNotFound) {
err = ErrKeyNotFound
}
return nil, err
@@ -654,7 +675,7 @@ func (kv *kvs) Create(key string, value []byte) (revision uint64, err error) {
// TODO(dlc) - Since we have tombstones for DEL ops for watchers, this could be from that
// so we need to double check.
if e, err := kv.get(key, kvLatestRevision); err == ErrKeyDeleted {
if e, err := kv.get(key, kvLatestRevision); errors.Is(err, ErrKeyDeleted) {
return kv.Update(key, value, e.Revision())
}
@@ -830,6 +851,41 @@ func (kv *kvs) Keys(opts ...WatchOpt) ([]string, error) {
return keys, nil
}
type keyLister struct {
watcher KeyWatcher
keys chan string
}
// ListKeys will return all keys.
func (kv *kvs) ListKeys(opts ...WatchOpt) (KeyLister, error) {
opts = append(opts, IgnoreDeletes(), MetaOnly())
watcher, err := kv.WatchAll(opts...)
if err != nil {
return nil, err
}
kl := &keyLister{watcher: watcher, keys: make(chan string, 256)}
go func() {
defer close(kl.keys)
defer watcher.Stop()
for entry := range watcher.Updates() {
if entry == nil {
return
}
kl.keys <- entry.Key()
}
}()
return kl, nil
}
func (kl *keyLister) Keys() <-chan string {
return kl.keys
}
func (kl *keyLister) Stop() error {
return kl.watcher.Stop()
}
// History will return all values for the key.
func (kv *kvs) History(key string, opts ...WatchOpt) ([]KeyValueEntry, error) {
opts = append(opts, IncludeHistory())
@@ -1040,6 +1096,9 @@ func (s *KeyValueBucketStatus) StreamInfo() *StreamInfo { return s.nfo }
// Bytes is the size of the stream
func (s *KeyValueBucketStatus) Bytes() uint64 { return s.nfo.State.Bytes }
// IsCompressed indicates if the data is compressed on disk
func (s *KeyValueBucketStatus) IsCompressed() bool { return s.nfo.Config.Compression != NoCompression }
// Status retrieves the status and configuration of a bucket
func (kv *kvs) Status() (KeyValueStatus, error) {
nfo, err := kv.js.StreamInfo(kv.stream)
@@ -1062,7 +1121,7 @@ func (js *js) KeyValueStoreNames() <-chan string {
if !strings.HasPrefix(name, kvBucketNamePre) {
continue
}
ch <- name
ch <- strings.TrimPrefix(name, kvBucketNamePre)
}
}
}()

View File

@@ -47,7 +47,7 @@ import (
// Default Constants
const (
Version = "1.31.0"
Version = "1.32.0"
DefaultURL = "nats://127.0.0.1:4222"
DefaultPort = 4222
DefaultMaxReconnect = 60
@@ -4298,6 +4298,12 @@ func (nc *Conn) removeSub(s *Subscription) {
}
}
if s.typ != AsyncSubscription {
done := s.pDone
if done != nil {
done(s.Subject)
}
}
// Mark as invalid
s.closed = true
if s.pCond != nil {

View File

@@ -1,4 +1,4 @@
// Copyright 2013-2022 The NATS Authors
// Copyright 2013-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

View File

@@ -1,4 +1,4 @@
// Copyright 2021-2022 The NATS Authors
// Copyright 2021-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -377,13 +377,16 @@ func (obs *obs) Put(meta *ObjectMeta, r io.Reader, opts ...ObjectOpt) (*ObjectIn
defer jetStream.(*js).cleanupReplySub()
purgePartial := func() {
purgePartial := func() error {
// wait until all pubs are complete or up to default timeout before attempting purge
select {
case <-jetStream.PublishAsyncComplete():
case <-time.After(obs.js.opts.wait):
}
obs.js.purgeStream(obs.stream, &StreamPurgeRequest{Subject: chunkSubj})
if err := obs.js.purgeStream(obs.stream, &StreamPurgeRequest{Subject: chunkSubj}); err != nil {
return fmt.Errorf("could not cleanup bucket after erronous put operation: %w", err)
}
return nil
}
m, h := NewMsg(chunkSubj), sha256.New()
@@ -404,7 +407,9 @@ func (obs *obs) Put(meta *ObjectMeta, r io.Reader, opts ...ObjectOpt) (*ObjectIn
default:
}
if err != nil {
purgePartial()
if purgeErr := purgePartial(); purgeErr != nil {
return nil, errors.Join(err, purgeErr)
}
return nil, err
}
}
@@ -415,7 +420,9 @@ func (obs *obs) Put(meta *ObjectMeta, r io.Reader, opts ...ObjectOpt) (*ObjectIn
// Handle all non EOF errors
if readErr != nil && readErr != io.EOF {
purgePartial()
if purgeErr := purgePartial(); purgeErr != nil {
return nil, errors.Join(readErr, purgeErr)
}
return nil, readErr
}
@@ -427,11 +434,15 @@ func (obs *obs) Put(meta *ObjectMeta, r io.Reader, opts ...ObjectOpt) (*ObjectIn
// Send msg itself.
if _, err := jetStream.PublishMsgAsync(m); err != nil {
purgePartial()
if purgeErr := purgePartial(); purgeErr != nil {
return nil, errors.Join(err, purgeErr)
}
return nil, err
}
if err := getErr(); err != nil {
purgePartial()
if purgeErr := purgePartial(); purgeErr != nil {
return nil, errors.Join(err, purgeErr)
}
return nil, err
}
// Update totals.
@@ -455,7 +466,9 @@ func (obs *obs) Put(meta *ObjectMeta, r io.Reader, opts ...ObjectOpt) (*ObjectIn
mm.Data, err = json.Marshal(info)
if err != nil {
if r != nil {
purgePartial()
if purgeErr := purgePartial(); purgeErr != nil {
return nil, errors.Join(err, purgeErr)
}
}
return nil, err
}
@@ -464,7 +477,9 @@ func (obs *obs) Put(meta *ObjectMeta, r io.Reader, opts ...ObjectOpt) (*ObjectIn
_, err = jetStream.PublishMsgAsync(mm)
if err != nil {
if r != nil {
purgePartial()
if purgeErr := purgePartial(); purgeErr != nil {
return nil, errors.Join(err, purgeErr)
}
}
return nil, err
}
@@ -474,7 +489,9 @@ func (obs *obs) Put(meta *ObjectMeta, r io.Reader, opts ...ObjectOpt) (*ObjectIn
case <-jetStream.PublishAsyncComplete():
if err := getErr(); err != nil {
if r != nil {
purgePartial()
if purgeErr := purgePartial(); purgeErr != nil {
return nil, errors.Join(err, purgeErr)
}
}
return nil, err
}
@@ -487,7 +504,9 @@ func (obs *obs) Put(meta *ObjectMeta, r io.Reader, opts ...ObjectOpt) (*ObjectIn
// Delete any original chunks.
if einfo != nil && !einfo.Deleted {
echunkSubj := fmt.Sprintf(objChunksPreTmpl, obs.name, einfo.NUID)
obs.js.purgeStream(obs.stream, &StreamPurgeRequest{Subject: echunkSubj})
if err := obs.js.purgeStream(obs.stream, &StreamPurgeRequest{Subject: echunkSubj}); err != nil {
return info, err
}
}
// TODO would it be okay to do this to return the info with the correct time?
@@ -626,7 +645,7 @@ func (obs *obs) Get(name string, opts ...GetObjectOpt) (ObjectResult, error) {
if ctx != nil {
select {
case <-ctx.Done():
if ctx.Err() == context.Canceled {
if errors.Is(ctx.Err(), context.Canceled) {
err = ctx.Err()
} else {
err = ErrTimeout
@@ -926,7 +945,7 @@ func (obs *obs) GetInfo(name string, opts ...GetObjectInfoOpt) (*ObjectInfo, err
m, err := obs.js.GetLastMsg(stream, metaSubj)
if err != nil {
if err == ErrMsgNotFound {
if errors.Is(err, ErrMsgNotFound) {
err = ErrObjectNotFound
}
return nil, err

View File

@@ -29,7 +29,7 @@ type timerPool struct {
// Get returns a timer that completes after the given duration.
func (tp *timerPool) Get(d time.Duration) *time.Timer {
if t, _ := tp.p.Get().(*time.Timer); t != nil {
if t, ok := tp.p.Get().(*time.Timer); ok && t != nil {
t.Reset(d)
return t
}

View File

@@ -79,6 +79,7 @@ Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*ApplicationsApi* | [**GetApplication**](docs/ApplicationsApi.md#getapplication) | **Get** /v1.0/applications/{application-id} | Get application by id
*ApplicationsApi* | [**ListApplications**](docs/ApplicationsApi.md#listapplications) | **Get** /v1.0/applications | Get all applications
*DriveItemApi* | [**DeleteDriveItem**](docs/DriveItemApi.md#deletedriveitem) | **Delete** /v1beta1/drives/{drive-id}/items/{item-id} | Delete a DriveItem.
*DrivesApi* | [**CreateDrive**](docs/DrivesApi.md#createdrive) | **Post** /v1.0/drives | Create a new drive of a specific type
*DrivesApi* | [**DeleteDrive**](docs/DrivesApi.md#deletedrive) | **Delete** /v1.0/drives/{drive-id} | Delete a specific space
*DrivesApi* | [**GetDrive**](docs/DrivesApi.md#getdrive) | **Get** /v1.0/drives/{drive-id} | Get drive by id
@@ -92,6 +93,7 @@ Class | Method | HTTP request | Description
*DrivesPermissionsApi* | [**ListPermissions**](docs/DrivesPermissionsApi.md#listpermissions) | **Get** /v1beta1/drives/{drive-id}/items/{item-id}/permissions | List the effective sharing permissions on a driveItem.
*DrivesPermissionsApi* | [**SetPermissionPassword**](docs/DrivesPermissionsApi.md#setpermissionpassword) | **Post** /v1beta1/drives/{drive-id}/items/{item-id}/permissions/{perm-id}/setPassword | Set sharing link password
*DrivesPermissionsApi* | [**UpdatePermission**](docs/DrivesPermissionsApi.md#updatepermission) | **Patch** /v1beta1/drives/{drive-id}/items/{item-id}/permissions/{perm-id} | Update sharing permission
*DrivesRootApi* | [**CreateDriveItem**](docs/DrivesRootApi.md#createdriveitem) | **Post** /v1beta1/drives/{drive-id}/root/children | Create a drive item
*DrivesRootApi* | [**GetRoot**](docs/DrivesRootApi.md#getroot) | **Get** /v1.0/drives/{drive-id}/root | Get root from arbitrary space
*EducationClassApi* | [**AddUserToClass**](docs/EducationClassApi.md#addusertoclass) | **Post** /v1.0/education/classes/{class-id}/members/$ref | Assign a user to a class
*EducationClassApi* | [**CreateClass**](docs/EducationClassApi.md#createclass) | **Post** /v1.0/education/classes | Add new education class
@@ -180,18 +182,15 @@ Class | Method | HTTP request | Description
- [CollectionOfUser](docs/CollectionOfUser.md)
- [CollectionOfUsers](docs/CollectionOfUsers.md)
- [Deleted](docs/Deleted.md)
- [DirectoryObject](docs/DirectoryObject.md)
- [Drive](docs/Drive.md)
- [DriveItem](docs/DriveItem.md)
- [DriveItemCreateLink](docs/DriveItemCreateLink.md)
- [DriveItemInvite](docs/DriveItemInvite.md)
- [DriveRecipient](docs/DriveRecipient.md)
- [EducationClass](docs/EducationClass.md)
- [EducationOrganization](docs/EducationOrganization.md)
- [EducationSchool](docs/EducationSchool.md)
- [EducationUser](docs/EducationUser.md)
- [EducationUserReference](docs/EducationUserReference.md)
- [Entity](docs/Entity.md)
- [ExportPersonalDataRequest](docs/ExportPersonalDataRequest.md)
- [FileSystemInfo](docs/FileSystemInfo.md)
- [Folder](docs/Folder.md)
@@ -227,6 +226,7 @@ Class | Method | HTTP request | Description
- [UnifiedRoleDefinition](docs/UnifiedRoleDefinition.md)
- [UnifiedRolePermission](docs/UnifiedRolePermission.md)
- [User](docs/User.md)
- [Video](docs/Video.md)
## Documentation For Authorization

View File

@@ -0,0 +1,132 @@
/*
Libre Graph API
Libre Graph is a free API for cloud collaboration inspired by the MS Graph API.
API version: v1.0.4
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package libregraph
import (
"bytes"
"context"
"io"
"net/http"
"net/url"
"strings"
)
// DriveItemApiService DriveItemApi service
type DriveItemApiService service
type ApiDeleteDriveItemRequest struct {
ctx context.Context
ApiService *DriveItemApiService
driveId string
itemId string
}
func (r ApiDeleteDriveItemRequest) Execute() (*http.Response, error) {
return r.ApiService.DeleteDriveItemExecute(r)
}
/*
DeleteDriveItem Delete a DriveItem.
Delete a DriveItem by using its ID.
Deleting items using this method moves the items to the recycle bin instead of permanently deleting the item.
Mounted shares in the share jail are unmounted. The `@client.synchronize` property of the `remoteItem` in the [sharedWithMe](#/me.drive/ListSharedWithMe) endpoint will change to false.
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
@param driveId key: id of drive
@param itemId key: id of item
@return ApiDeleteDriveItemRequest
*/
func (a *DriveItemApiService) DeleteDriveItem(ctx context.Context, driveId string, itemId string) ApiDeleteDriveItemRequest {
return ApiDeleteDriveItemRequest{
ApiService: a,
ctx: ctx,
driveId: driveId,
itemId: itemId,
}
}
// Execute executes the request
func (a *DriveItemApiService) DeleteDriveItemExecute(r ApiDeleteDriveItemRequest) (*http.Response, error) {
var (
localVarHTTPMethod = http.MethodDelete
localVarPostBody interface{}
formFiles []formFile
)
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "DriveItemApiService.DeleteDriveItem")
if err != nil {
return nil, &GenericOpenAPIError{error: err.Error()}
}
localVarPath := localBasePath + "/v1beta1/drives/{drive-id}/items/{item-id}"
localVarPath = strings.Replace(localVarPath, "{"+"drive-id"+"}", url.PathEscape(parameterValueToString(r.driveId, "driveId")), -1)
localVarPath = strings.Replace(localVarPath, "{"+"item-id"+"}", url.PathEscape(parameterValueToString(r.itemId, "itemId")), -1)
localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
localVarFormParams := url.Values{}
// to determine the Content-Type header
localVarHTTPContentTypes := []string{}
// set Content-Type header
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
if localVarHTTPContentType != "" {
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
}
// to determine the Accept header
localVarHTTPHeaderAccepts := []string{"application/json"}
// set Accept header
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
if localVarHTTPHeaderAccept != "" {
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
}
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
if err != nil {
return nil, err
}
localVarHTTPResponse, err := a.client.callAPI(req)
if err != nil || localVarHTTPResponse == nil {
return localVarHTTPResponse, err
}
localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
localVarHTTPResponse.Body.Close()
localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
if err != nil {
return localVarHTTPResponse, err
}
if localVarHTTPResponse.StatusCode >= 300 {
newErr := &GenericOpenAPIError{
body: localVarBody,
error: localVarHTTPResponse.Status,
}
var v OdataError
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return localVarHTTPResponse, newErr
}
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
newErr.model = v
return localVarHTTPResponse, newErr
}
return localVarHTTPResponse, nil
}

View File

@@ -22,6 +22,127 @@ import (
// DrivesRootApiService DrivesRootApi service
type DrivesRootApiService service
type ApiCreateDriveItemRequest struct {
ctx context.Context
ApiService *DrivesRootApiService
driveId string
driveItem *DriveItem
}
// In the request body, provide a JSON object with the following parameters. For mounting a share the necessary remoteItem id and permission id can be taken from the [sharedWithMe](#/me.drive/ListSharedWithMe) endpoint.
func (r ApiCreateDriveItemRequest) DriveItem(driveItem DriveItem) ApiCreateDriveItemRequest {
r.driveItem = &driveItem
return r
}
func (r ApiCreateDriveItemRequest) Execute() (*DriveItem, *http.Response, error) {
return r.ApiService.CreateDriveItemExecute(r)
}
/*
CreateDriveItem Create a drive item
You can use the root childrens endpoint to mount a remoteItem in the share jail. The `@client.synchronize` property of the `remoteItem` in the [sharedWithMe](#/me.drive/ListSharedWithMe) endpoint will change to true.
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
@param driveId key: id of drive
@return ApiCreateDriveItemRequest
*/
func (a *DrivesRootApiService) CreateDriveItem(ctx context.Context, driveId string) ApiCreateDriveItemRequest {
return ApiCreateDriveItemRequest{
ApiService: a,
ctx: ctx,
driveId: driveId,
}
}
// Execute executes the request
// @return DriveItem
func (a *DrivesRootApiService) CreateDriveItemExecute(r ApiCreateDriveItemRequest) (*DriveItem, *http.Response, error) {
var (
localVarHTTPMethod = http.MethodPost
localVarPostBody interface{}
formFiles []formFile
localVarReturnValue *DriveItem
)
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "DrivesRootApiService.CreateDriveItem")
if err != nil {
return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
}
localVarPath := localBasePath + "/v1beta1/drives/{drive-id}/root/children"
localVarPath = strings.Replace(localVarPath, "{"+"drive-id"+"}", url.PathEscape(parameterValueToString(r.driveId, "driveId")), -1)
localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
localVarFormParams := url.Values{}
// to determine the Content-Type header
localVarHTTPContentTypes := []string{"application/json"}
// set Content-Type header
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
if localVarHTTPContentType != "" {
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
}
// to determine the Accept header
localVarHTTPHeaderAccepts := []string{"application/json"}
// set Accept header
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
if localVarHTTPHeaderAccept != "" {
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
}
// body params
localVarPostBody = r.driveItem
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
if err != nil {
return localVarReturnValue, nil, err
}
localVarHTTPResponse, err := a.client.callAPI(req)
if err != nil || localVarHTTPResponse == nil {
return localVarReturnValue, localVarHTTPResponse, err
}
localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
localVarHTTPResponse.Body.Close()
localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
if err != nil {
return localVarReturnValue, localVarHTTPResponse, err
}
if localVarHTTPResponse.StatusCode >= 300 {
newErr := &GenericOpenAPIError{
body: localVarBody,
error: localVarHTTPResponse.Status,
}
var v OdataError
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return localVarReturnValue, localVarHTTPResponse, newErr
}
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
newErr.model = v
return localVarReturnValue, localVarHTTPResponse, newErr
}
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr := &GenericOpenAPIError{
body: localVarBody,
error: err.Error(),
}
return localVarReturnValue, localVarHTTPResponse, newErr
}
return localVarReturnValue, localVarHTTPResponse, nil
}
type ApiGetRootRequest struct {
ctx context.Context
ApiService *DrivesRootApiService

View File

@@ -50,6 +50,8 @@ type APIClient struct {
ApplicationsApi *ApplicationsApiService
DriveItemApi *DriveItemApiService
DrivesApi *DrivesApiService
DrivesGetDrivesApi *DrivesGetDrivesApiService
@@ -110,6 +112,7 @@ func NewAPIClient(cfg *Configuration) *APIClient {
// API Services
c.ApplicationsApi = (*ApplicationsApiService)(&c.common)
c.DriveItemApi = (*DriveItemApiService)(&c.common)
c.DrivesApi = (*DrivesApiService)(&c.common)
c.DrivesGetDrivesApi = (*DrivesGetDrivesApiService)(&c.common)
c.DrivesPermissionsApi = (*DrivesPermissionsApiService)(&c.common)

View File

@@ -1,162 +0,0 @@
/*
Libre Graph API
Libre Graph is a free API for cloud collaboration inspired by the MS Graph API.
API version: v1.0.4
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package libregraph
import (
"encoding/json"
"time"
)
// checks if the DirectoryObject type satisfies the MappedNullable interface at compile time
var _ MappedNullable = &DirectoryObject{}
// DirectoryObject Represents a Directory object. Read-only.
type DirectoryObject struct {
// The unique identifier for the object. 12345678-9abc-def0-1234-56789abcde. The value of the ID property is often, but not exclusively, in the form of a GUID. The value should be treated as an opaque identifier and not based in being a GUID. Null values are not allowed. Read-only.
Id *string `json:"id,omitempty"`
DeletedDateTime *time.Time `json:"deletedDateTime,omitempty"`
}
// NewDirectoryObject instantiates a new DirectoryObject object
// This constructor will assign default values to properties that have it defined,
// and makes sure properties required by API are set, but the set of arguments
// will change when the set of required properties is changed
func NewDirectoryObject() *DirectoryObject {
this := DirectoryObject{}
return &this
}
// NewDirectoryObjectWithDefaults instantiates a new DirectoryObject object
// This constructor will only assign default values to properties that have it defined,
// but it doesn't guarantee that properties required by API are set
func NewDirectoryObjectWithDefaults() *DirectoryObject {
this := DirectoryObject{}
return &this
}
// GetId returns the Id field value if set, zero value otherwise.
func (o *DirectoryObject) GetId() string {
if o == nil || IsNil(o.Id) {
var ret string
return ret
}
return *o.Id
}
// GetIdOk returns a tuple with the Id field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *DirectoryObject) GetIdOk() (*string, bool) {
if o == nil || IsNil(o.Id) {
return nil, false
}
return o.Id, true
}
// HasId returns a boolean if a field has been set.
func (o *DirectoryObject) HasId() bool {
if o != nil && !IsNil(o.Id) {
return true
}
return false
}
// SetId gets a reference to the given string and assigns it to the Id field.
func (o *DirectoryObject) SetId(v string) {
o.Id = &v
}
// GetDeletedDateTime returns the DeletedDateTime field value if set, zero value otherwise.
func (o *DirectoryObject) GetDeletedDateTime() time.Time {
if o == nil || IsNil(o.DeletedDateTime) {
var ret time.Time
return ret
}
return *o.DeletedDateTime
}
// GetDeletedDateTimeOk returns a tuple with the DeletedDateTime field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *DirectoryObject) GetDeletedDateTimeOk() (*time.Time, bool) {
if o == nil || IsNil(o.DeletedDateTime) {
return nil, false
}
return o.DeletedDateTime, true
}
// HasDeletedDateTime returns a boolean if a field has been set.
func (o *DirectoryObject) HasDeletedDateTime() bool {
if o != nil && !IsNil(o.DeletedDateTime) {
return true
}
return false
}
// SetDeletedDateTime gets a reference to the given time.Time and assigns it to the DeletedDateTime field.
func (o *DirectoryObject) SetDeletedDateTime(v time.Time) {
o.DeletedDateTime = &v
}
func (o DirectoryObject) MarshalJSON() ([]byte, error) {
toSerialize, err := o.ToMap()
if err != nil {
return []byte{}, err
}
return json.Marshal(toSerialize)
}
func (o DirectoryObject) ToMap() (map[string]interface{}, error) {
toSerialize := map[string]interface{}{}
if !IsNil(o.Id) {
toSerialize["id"] = o.Id
}
if !IsNil(o.DeletedDateTime) {
toSerialize["deletedDateTime"] = o.DeletedDateTime
}
return toSerialize, nil
}
type NullableDirectoryObject struct {
value *DirectoryObject
isSet bool
}
func (v NullableDirectoryObject) Get() *DirectoryObject {
return v.value
}
func (v *NullableDirectoryObject) Set(val *DirectoryObject) {
v.value = val
v.isSet = true
}
func (v NullableDirectoryObject) IsSet() bool {
return v.isSet
}
func (v *NullableDirectoryObject) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableDirectoryObject(val *DirectoryObject) *NullableDirectoryObject {
return &NullableDirectoryObject{value: val, isSet: true}
}
func (v NullableDirectoryObject) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableDirectoryObject) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

View File

@@ -62,6 +62,7 @@ type DriveItem struct {
// The set of permissions for the item. Read-only. Nullable.
Permissions []Permission `json:"permissions,omitempty"`
Audio *Audio `json:"audio,omitempty"`
Video *Video `json:"video,omitempty"`
}
// NewDriveItem instantiates a new DriveItem object
@@ -977,6 +978,38 @@ func (o *DriveItem) SetAudio(v Audio) {
o.Audio = &v
}
// GetVideo returns the Video field value if set, zero value otherwise.
func (o *DriveItem) GetVideo() Video {
if o == nil || IsNil(o.Video) {
var ret Video
return ret
}
return *o.Video
}
// GetVideoOk returns a tuple with the Video field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *DriveItem) GetVideoOk() (*Video, bool) {
if o == nil || IsNil(o.Video) {
return nil, false
}
return o.Video, true
}
// HasVideo returns a boolean if a field has been set.
func (o *DriveItem) HasVideo() bool {
if o != nil && !IsNil(o.Video) {
return true
}
return false
}
// SetVideo gets a reference to the given Video and assigns it to the Video field.
func (o *DriveItem) SetVideo(v Video) {
o.Video = &v
}
func (o DriveItem) MarshalJSON() ([]byte, error) {
toSerialize, err := o.ToMap()
if err != nil {
@@ -1071,6 +1104,9 @@ func (o DriveItem) ToMap() (map[string]interface{}, error) {
if !IsNil(o.Audio) {
toSerialize["audio"] = o.Audio
}
if !IsNil(o.Video) {
toSerialize["video"] = o.Video
}
return toSerialize, nil
}

View File

@@ -1,162 +0,0 @@
/*
Libre Graph API
Libre Graph is a free API for cloud collaboration inspired by the MS Graph API.
API version: v1.0.4
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package libregraph
import (
"encoding/json"
)
// checks if the EducationOrganization type satisfies the MappedNullable interface at compile time
var _ MappedNullable = &EducationOrganization{}
// EducationOrganization Abstract. Represents an organization in educational context
type EducationOrganization struct {
// The unique idenfier for an entity. Read-only.
Id *string `json:"id,omitempty"`
// The organization name
DisplayName *string `json:"displayName,omitempty"`
}
// NewEducationOrganization instantiates a new EducationOrganization object
// This constructor will assign default values to properties that have it defined,
// and makes sure properties required by API are set, but the set of arguments
// will change when the set of required properties is changed
func NewEducationOrganization() *EducationOrganization {
this := EducationOrganization{}
return &this
}
// NewEducationOrganizationWithDefaults instantiates a new EducationOrganization object
// This constructor will only assign default values to properties that have it defined,
// but it doesn't guarantee that properties required by API are set
func NewEducationOrganizationWithDefaults() *EducationOrganization {
this := EducationOrganization{}
return &this
}
// GetId returns the Id field value if set, zero value otherwise.
func (o *EducationOrganization) GetId() string {
if o == nil || IsNil(o.Id) {
var ret string
return ret
}
return *o.Id
}
// GetIdOk returns a tuple with the Id field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *EducationOrganization) GetIdOk() (*string, bool) {
if o == nil || IsNil(o.Id) {
return nil, false
}
return o.Id, true
}
// HasId returns a boolean if a field has been set.
func (o *EducationOrganization) HasId() bool {
if o != nil && !IsNil(o.Id) {
return true
}
return false
}
// SetId gets a reference to the given string and assigns it to the Id field.
func (o *EducationOrganization) SetId(v string) {
o.Id = &v
}
// GetDisplayName returns the DisplayName field value if set, zero value otherwise.
func (o *EducationOrganization) GetDisplayName() string {
if o == nil || IsNil(o.DisplayName) {
var ret string
return ret
}
return *o.DisplayName
}
// GetDisplayNameOk returns a tuple with the DisplayName field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *EducationOrganization) GetDisplayNameOk() (*string, bool) {
if o == nil || IsNil(o.DisplayName) {
return nil, false
}
return o.DisplayName, true
}
// HasDisplayName returns a boolean if a field has been set.
func (o *EducationOrganization) HasDisplayName() bool {
if o != nil && !IsNil(o.DisplayName) {
return true
}
return false
}
// SetDisplayName gets a reference to the given string and assigns it to the DisplayName field.
func (o *EducationOrganization) SetDisplayName(v string) {
o.DisplayName = &v
}
func (o EducationOrganization) MarshalJSON() ([]byte, error) {
toSerialize, err := o.ToMap()
if err != nil {
return []byte{}, err
}
return json.Marshal(toSerialize)
}
func (o EducationOrganization) ToMap() (map[string]interface{}, error) {
toSerialize := map[string]interface{}{}
if !IsNil(o.Id) {
toSerialize["id"] = o.Id
}
if !IsNil(o.DisplayName) {
toSerialize["displayName"] = o.DisplayName
}
return toSerialize, nil
}
type NullableEducationOrganization struct {
value *EducationOrganization
isSet bool
}
func (v NullableEducationOrganization) Get() *EducationOrganization {
return v.value
}
func (v *NullableEducationOrganization) Set(val *EducationOrganization) {
v.value = val
v.isSet = true
}
func (v NullableEducationOrganization) IsSet() bool {
return v.isSet
}
func (v *NullableEducationOrganization) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableEducationOrganization(val *EducationOrganization) *NullableEducationOrganization {
return &NullableEducationOrganization{value: val, isSet: true}
}
func (v NullableEducationOrganization) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableEducationOrganization) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

View File

@@ -1,125 +0,0 @@
/*
Libre Graph API
Libre Graph is a free API for cloud collaboration inspired by the MS Graph API.
API version: v1.0.4
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package libregraph
import (
"encoding/json"
)
// checks if the Entity type satisfies the MappedNullable interface at compile time
var _ MappedNullable = &Entity{}
// Entity Represents an entity.
type Entity struct {
// The unique idenfier for an entity. Read-only.
Id *string `json:"id,omitempty"`
}
// NewEntity instantiates a new Entity object
// This constructor will assign default values to properties that have it defined,
// and makes sure properties required by API are set, but the set of arguments
// will change when the set of required properties is changed
func NewEntity() *Entity {
this := Entity{}
return &this
}
// NewEntityWithDefaults instantiates a new Entity object
// This constructor will only assign default values to properties that have it defined,
// but it doesn't guarantee that properties required by API are set
func NewEntityWithDefaults() *Entity {
this := Entity{}
return &this
}
// GetId returns the Id field value if set, zero value otherwise.
func (o *Entity) GetId() string {
if o == nil || IsNil(o.Id) {
var ret string
return ret
}
return *o.Id
}
// GetIdOk returns a tuple with the Id field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Entity) GetIdOk() (*string, bool) {
if o == nil || IsNil(o.Id) {
return nil, false
}
return o.Id, true
}
// HasId returns a boolean if a field has been set.
func (o *Entity) HasId() bool {
if o != nil && !IsNil(o.Id) {
return true
}
return false
}
// SetId gets a reference to the given string and assigns it to the Id field.
func (o *Entity) SetId(v string) {
o.Id = &v
}
func (o Entity) MarshalJSON() ([]byte, error) {
toSerialize, err := o.ToMap()
if err != nil {
return []byte{}, err
}
return json.Marshal(toSerialize)
}
func (o Entity) ToMap() (map[string]interface{}, error) {
toSerialize := map[string]interface{}{}
if !IsNil(o.Id) {
toSerialize["id"] = o.Id
}
return toSerialize, nil
}
type NullableEntity struct {
value *Entity
isSet bool
}
func (v NullableEntity) Get() *Entity {
return v.value
}
func (v *NullableEntity) Set(val *Entity) {
v.value = val
v.isSet = true
}
func (v NullableEntity) IsSet() bool {
return v.isSet
}
func (v *NullableEntity) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableEntity(val *Entity) *NullableEntity {
return &NullableEntity{value: val, isSet: true}
}
func (v NullableEntity) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableEntity) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

View File

@@ -34,8 +34,10 @@ type Permission struct {
GrantedToIdentities []IdentitySet `json:"grantedToIdentities,omitempty"`
// Use this to create a permission with custom actions.
LibreGraphPermissionsActions []string `json:"@libre.graph.permissions.actions,omitempty"`
// Indicates if the item is synchronized with the underlying storage provider. Read-only.
ClientSynchronize *bool `json:"@client.synchronize,omitempty"`
// Properties or facets (see UI.Facet) annotated with this term will not be rendered if the annotation evaluates to true. Users can set this to hide permissons.
UIHidden *bool `json:"@UI.Hidden,omitempty"`
UiHidden *bool `json:"@ui.hidden,omitempty"`
}
// NewPermission instantiates a new Permission object
@@ -325,36 +327,68 @@ func (o *Permission) SetLibreGraphPermissionsActions(v []string) {
o.LibreGraphPermissionsActions = v
}
// GetUIHidden returns the UIHidden field value if set, zero value otherwise.
func (o *Permission) GetUIHidden() bool {
if o == nil || IsNil(o.UIHidden) {
// GetClientSynchronize returns the ClientSynchronize field value if set, zero value otherwise.
func (o *Permission) GetClientSynchronize() bool {
if o == nil || IsNil(o.ClientSynchronize) {
var ret bool
return ret
}
return *o.UIHidden
return *o.ClientSynchronize
}
// GetUIHiddenOk returns a tuple with the UIHidden field value if set, nil otherwise
// GetClientSynchronizeOk returns a tuple with the ClientSynchronize field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Permission) GetUIHiddenOk() (*bool, bool) {
if o == nil || IsNil(o.UIHidden) {
func (o *Permission) GetClientSynchronizeOk() (*bool, bool) {
if o == nil || IsNil(o.ClientSynchronize) {
return nil, false
}
return o.UIHidden, true
return o.ClientSynchronize, true
}
// HasUIHidden returns a boolean if a field has been set.
func (o *Permission) HasUIHidden() bool {
if o != nil && !IsNil(o.UIHidden) {
// HasClientSynchronize returns a boolean if a field has been set.
func (o *Permission) HasClientSynchronize() bool {
if o != nil && !IsNil(o.ClientSynchronize) {
return true
}
return false
}
// SetUIHidden gets a reference to the given bool and assigns it to the UIHidden field.
func (o *Permission) SetUIHidden(v bool) {
o.UIHidden = &v
// SetClientSynchronize gets a reference to the given bool and assigns it to the ClientSynchronize field.
func (o *Permission) SetClientSynchronize(v bool) {
o.ClientSynchronize = &v
}
// GetUiHidden returns the UiHidden field value if set, zero value otherwise.
func (o *Permission) GetUiHidden() bool {
if o == nil || IsNil(o.UiHidden) {
var ret bool
return ret
}
return *o.UiHidden
}
// GetUiHiddenOk returns a tuple with the UiHidden field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Permission) GetUiHiddenOk() (*bool, bool) {
if o == nil || IsNil(o.UiHidden) {
return nil, false
}
return o.UiHidden, true
}
// HasUiHidden returns a boolean if a field has been set.
func (o *Permission) HasUiHidden() bool {
if o != nil && !IsNil(o.UiHidden) {
return true
}
return false
}
// SetUiHidden gets a reference to the given bool and assigns it to the UiHidden field.
func (o *Permission) SetUiHidden(v bool) {
o.UiHidden = &v
}
func (o Permission) MarshalJSON() ([]byte, error) {
@@ -391,8 +425,11 @@ func (o Permission) ToMap() (map[string]interface{}, error) {
if !IsNil(o.LibreGraphPermissionsActions) {
toSerialize["@libre.graph.permissions.actions"] = o.LibreGraphPermissionsActions
}
if !IsNil(o.UIHidden) {
toSerialize["@UI.Hidden"] = o.UIHidden
if !IsNil(o.ClientSynchronize) {
toSerialize["@client.synchronize"] = o.ClientSynchronize
}
if !IsNil(o.UiHidden) {
toSerialize["@ui.hidden"] = o.UiHidden
}
return toSerialize, nil
}

View File

@@ -46,6 +46,8 @@ type RemoteItem struct {
CTag *string `json:"cTag,omitempty"`
ParentReference *ItemReference `json:"parentReference,omitempty"`
Shared *Shared `json:"shared,omitempty"`
// The set of permissions for the item. Read-only. Nullable.
Permissions []Permission `json:"permissions,omitempty"`
// Size of the remote item. Read-only.
Size *int64 `json:"size,omitempty"`
SpecialFolder *SpecialFolder `json:"specialFolder,omitempty"`
@@ -616,6 +618,38 @@ func (o *RemoteItem) SetShared(v Shared) {
o.Shared = &v
}
// GetPermissions returns the Permissions field value if set, zero value otherwise.
func (o *RemoteItem) GetPermissions() []Permission {
if o == nil || IsNil(o.Permissions) {
var ret []Permission
return ret
}
return o.Permissions
}
// GetPermissionsOk returns a tuple with the Permissions field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *RemoteItem) GetPermissionsOk() ([]Permission, bool) {
if o == nil || IsNil(o.Permissions) {
return nil, false
}
return o.Permissions, true
}
// HasPermissions returns a boolean if a field has been set.
func (o *RemoteItem) HasPermissions() bool {
if o != nil && !IsNil(o.Permissions) {
return true
}
return false
}
// SetPermissions gets a reference to the given []Permission and assigns it to the Permissions field.
func (o *RemoteItem) SetPermissions(v []Permission) {
o.Permissions = v
}
// GetSize returns the Size field value if set, zero value otherwise.
func (o *RemoteItem) GetSize() int64 {
if o == nil || IsNil(o.Size) {
@@ -805,6 +839,9 @@ func (o RemoteItem) ToMap() (map[string]interface{}, error) {
if !IsNil(o.Shared) {
toSerialize["shared"] = o.Shared
}
if !IsNil(o.Permissions) {
toSerialize["permissions"] = o.Permissions
}
if !IsNil(o.Size) {
toSerialize["size"] = o.Size
}

View File

@@ -0,0 +1,458 @@
/*
Libre Graph API
Libre Graph is a free API for cloud collaboration inspired by the MS Graph API.
API version: v1.0.4
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package libregraph
import (
"encoding/json"
)
// checks if the Video type satisfies the MappedNullable interface at compile time
var _ MappedNullable = &Video{}
// Video The video resource groups video-related data items into a single structure. If a driveItem has a non-null video facet, the item represents a video file. The properties of the video resource are populated by extracting metadata from the file.
type Video struct {
// Number of audio bits per sample.
AudioBitsPerSample *int32 `json:"audioBitsPerSample,omitempty"`
// Number of audio channels.
AudioChannels *int32 `json:"audioChannels,omitempty"`
// Name of the audio format (AAC, MP3, etc.).
AudioFormat *string `json:"audioFormat,omitempty"`
// Number of audio samples per second.
AudioSamplesPerSecond *int32 `json:"audioSamplesPerSecond,omitempty"`
// Bit rate of the video in bits per second.
Bitrate *int32 `json:"bitrate,omitempty"`
// Duration of the file in milliseconds.
Duration *int64 `json:"duration,omitempty"`
// \\\"Four character code\\\" name of the video format.
FourCC *string `json:"fourCC,omitempty"`
// Frame rate of the video.
FrameRate *float64 `json:"frameRate,omitempty"`
// Height of the video, in pixels.
Height *int32 `json:"height,omitempty"`
// Width of the video, in pixels.
Width *int32 `json:"width,omitempty"`
}
// NewVideo instantiates a new Video object
// This constructor will assign default values to properties that have it defined,
// and makes sure properties required by API are set, but the set of arguments
// will change when the set of required properties is changed
func NewVideo() *Video {
this := Video{}
return &this
}
// NewVideoWithDefaults instantiates a new Video object
// This constructor will only assign default values to properties that have it defined,
// but it doesn't guarantee that properties required by API are set
func NewVideoWithDefaults() *Video {
this := Video{}
return &this
}
// GetAudioBitsPerSample returns the AudioBitsPerSample field value if set, zero value otherwise.
func (o *Video) GetAudioBitsPerSample() int32 {
if o == nil || IsNil(o.AudioBitsPerSample) {
var ret int32
return ret
}
return *o.AudioBitsPerSample
}
// GetAudioBitsPerSampleOk returns a tuple with the AudioBitsPerSample field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Video) GetAudioBitsPerSampleOk() (*int32, bool) {
if o == nil || IsNil(o.AudioBitsPerSample) {
return nil, false
}
return o.AudioBitsPerSample, true
}
// HasAudioBitsPerSample returns a boolean if a field has been set.
func (o *Video) HasAudioBitsPerSample() bool {
if o != nil && !IsNil(o.AudioBitsPerSample) {
return true
}
return false
}
// SetAudioBitsPerSample gets a reference to the given int32 and assigns it to the AudioBitsPerSample field.
func (o *Video) SetAudioBitsPerSample(v int32) {
o.AudioBitsPerSample = &v
}
// GetAudioChannels returns the AudioChannels field value if set, zero value otherwise.
func (o *Video) GetAudioChannels() int32 {
if o == nil || IsNil(o.AudioChannels) {
var ret int32
return ret
}
return *o.AudioChannels
}
// GetAudioChannelsOk returns a tuple with the AudioChannels field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Video) GetAudioChannelsOk() (*int32, bool) {
if o == nil || IsNil(o.AudioChannels) {
return nil, false
}
return o.AudioChannels, true
}
// HasAudioChannels returns a boolean if a field has been set.
func (o *Video) HasAudioChannels() bool {
if o != nil && !IsNil(o.AudioChannels) {
return true
}
return false
}
// SetAudioChannels gets a reference to the given int32 and assigns it to the AudioChannels field.
func (o *Video) SetAudioChannels(v int32) {
o.AudioChannels = &v
}
// GetAudioFormat returns the AudioFormat field value if set, zero value otherwise.
func (o *Video) GetAudioFormat() string {
if o == nil || IsNil(o.AudioFormat) {
var ret string
return ret
}
return *o.AudioFormat
}
// GetAudioFormatOk returns a tuple with the AudioFormat field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Video) GetAudioFormatOk() (*string, bool) {
if o == nil || IsNil(o.AudioFormat) {
return nil, false
}
return o.AudioFormat, true
}
// HasAudioFormat returns a boolean if a field has been set.
func (o *Video) HasAudioFormat() bool {
if o != nil && !IsNil(o.AudioFormat) {
return true
}
return false
}
// SetAudioFormat gets a reference to the given string and assigns it to the AudioFormat field.
func (o *Video) SetAudioFormat(v string) {
o.AudioFormat = &v
}
// GetAudioSamplesPerSecond returns the AudioSamplesPerSecond field value if set, zero value otherwise.
func (o *Video) GetAudioSamplesPerSecond() int32 {
if o == nil || IsNil(o.AudioSamplesPerSecond) {
var ret int32
return ret
}
return *o.AudioSamplesPerSecond
}
// GetAudioSamplesPerSecondOk returns a tuple with the AudioSamplesPerSecond field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Video) GetAudioSamplesPerSecondOk() (*int32, bool) {
if o == nil || IsNil(o.AudioSamplesPerSecond) {
return nil, false
}
return o.AudioSamplesPerSecond, true
}
// HasAudioSamplesPerSecond returns a boolean if a field has been set.
func (o *Video) HasAudioSamplesPerSecond() bool {
if o != nil && !IsNil(o.AudioSamplesPerSecond) {
return true
}
return false
}
// SetAudioSamplesPerSecond gets a reference to the given int32 and assigns it to the AudioSamplesPerSecond field.
func (o *Video) SetAudioSamplesPerSecond(v int32) {
o.AudioSamplesPerSecond = &v
}
// GetBitrate returns the Bitrate field value if set, zero value otherwise.
func (o *Video) GetBitrate() int32 {
if o == nil || IsNil(o.Bitrate) {
var ret int32
return ret
}
return *o.Bitrate
}
// GetBitrateOk returns a tuple with the Bitrate field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Video) GetBitrateOk() (*int32, bool) {
if o == nil || IsNil(o.Bitrate) {
return nil, false
}
return o.Bitrate, true
}
// HasBitrate returns a boolean if a field has been set.
func (o *Video) HasBitrate() bool {
if o != nil && !IsNil(o.Bitrate) {
return true
}
return false
}
// SetBitrate gets a reference to the given int32 and assigns it to the Bitrate field.
func (o *Video) SetBitrate(v int32) {
o.Bitrate = &v
}
// GetDuration returns the Duration field value if set, zero value otherwise.
func (o *Video) GetDuration() int64 {
if o == nil || IsNil(o.Duration) {
var ret int64
return ret
}
return *o.Duration
}
// GetDurationOk returns a tuple with the Duration field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Video) GetDurationOk() (*int64, bool) {
if o == nil || IsNil(o.Duration) {
return nil, false
}
return o.Duration, true
}
// HasDuration returns a boolean if a field has been set.
func (o *Video) HasDuration() bool {
if o != nil && !IsNil(o.Duration) {
return true
}
return false
}
// SetDuration gets a reference to the given int64 and assigns it to the Duration field.
func (o *Video) SetDuration(v int64) {
o.Duration = &v
}
// GetFourCC returns the FourCC field value if set, zero value otherwise.
func (o *Video) GetFourCC() string {
if o == nil || IsNil(o.FourCC) {
var ret string
return ret
}
return *o.FourCC
}
// GetFourCCOk returns a tuple with the FourCC field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Video) GetFourCCOk() (*string, bool) {
if o == nil || IsNil(o.FourCC) {
return nil, false
}
return o.FourCC, true
}
// HasFourCC returns a boolean if a field has been set.
func (o *Video) HasFourCC() bool {
if o != nil && !IsNil(o.FourCC) {
return true
}
return false
}
// SetFourCC gets a reference to the given string and assigns it to the FourCC field.
func (o *Video) SetFourCC(v string) {
o.FourCC = &v
}
// GetFrameRate returns the FrameRate field value if set, zero value otherwise.
func (o *Video) GetFrameRate() float64 {
if o == nil || IsNil(o.FrameRate) {
var ret float64
return ret
}
return *o.FrameRate
}
// GetFrameRateOk returns a tuple with the FrameRate field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Video) GetFrameRateOk() (*float64, bool) {
if o == nil || IsNil(o.FrameRate) {
return nil, false
}
return o.FrameRate, true
}
// HasFrameRate returns a boolean if a field has been set.
func (o *Video) HasFrameRate() bool {
if o != nil && !IsNil(o.FrameRate) {
return true
}
return false
}
// SetFrameRate gets a reference to the given float64 and assigns it to the FrameRate field.
func (o *Video) SetFrameRate(v float64) {
o.FrameRate = &v
}
// GetHeight returns the Height field value if set, zero value otherwise.
func (o *Video) GetHeight() int32 {
if o == nil || IsNil(o.Height) {
var ret int32
return ret
}
return *o.Height
}
// GetHeightOk returns a tuple with the Height field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Video) GetHeightOk() (*int32, bool) {
if o == nil || IsNil(o.Height) {
return nil, false
}
return o.Height, true
}
// HasHeight returns a boolean if a field has been set.
func (o *Video) HasHeight() bool {
if o != nil && !IsNil(o.Height) {
return true
}
return false
}
// SetHeight gets a reference to the given int32 and assigns it to the Height field.
func (o *Video) SetHeight(v int32) {
o.Height = &v
}
// GetWidth returns the Width field value if set, zero value otherwise.
func (o *Video) GetWidth() int32 {
if o == nil || IsNil(o.Width) {
var ret int32
return ret
}
return *o.Width
}
// GetWidthOk returns a tuple with the Width field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *Video) GetWidthOk() (*int32, bool) {
if o == nil || IsNil(o.Width) {
return nil, false
}
return o.Width, true
}
// HasWidth returns a boolean if a field has been set.
func (o *Video) HasWidth() bool {
if o != nil && !IsNil(o.Width) {
return true
}
return false
}
// SetWidth gets a reference to the given int32 and assigns it to the Width field.
func (o *Video) SetWidth(v int32) {
o.Width = &v
}
func (o Video) MarshalJSON() ([]byte, error) {
toSerialize, err := o.ToMap()
if err != nil {
return []byte{}, err
}
return json.Marshal(toSerialize)
}
func (o Video) ToMap() (map[string]interface{}, error) {
toSerialize := map[string]interface{}{}
if !IsNil(o.AudioBitsPerSample) {
toSerialize["audioBitsPerSample"] = o.AudioBitsPerSample
}
if !IsNil(o.AudioChannels) {
toSerialize["audioChannels"] = o.AudioChannels
}
if !IsNil(o.AudioFormat) {
toSerialize["audioFormat"] = o.AudioFormat
}
if !IsNil(o.AudioSamplesPerSecond) {
toSerialize["audioSamplesPerSecond"] = o.AudioSamplesPerSecond
}
if !IsNil(o.Bitrate) {
toSerialize["bitrate"] = o.Bitrate
}
if !IsNil(o.Duration) {
toSerialize["duration"] = o.Duration
}
if !IsNil(o.FourCC) {
toSerialize["fourCC"] = o.FourCC
}
if !IsNil(o.FrameRate) {
toSerialize["frameRate"] = o.FrameRate
}
if !IsNil(o.Height) {
toSerialize["height"] = o.Height
}
if !IsNil(o.Width) {
toSerialize["width"] = o.Width
}
return toSerialize, nil
}
type NullableVideo struct {
value *Video
isSet bool
}
func (v NullableVideo) Get() *Video {
return v.value
}
func (v *NullableVideo) Set(val *Video) {
v.value = val
v.isSet = true
}
func (v NullableVideo) IsSet() bool {
return v.isSet
}
func (v *NullableVideo) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableVideo(val *Video) *NullableVideo {
return &NullableVideo{value: val, isSet: true}
}
func (v NullableVideo) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableVideo) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

8
vendor/modules.txt vendored
View File

@@ -1107,11 +1107,11 @@ github.com/google/uuid
# github.com/gookit/color v1.5.4
## explicit; go 1.18
github.com/gookit/color
# github.com/gookit/config/v2 v2.2.4
# github.com/gookit/config/v2 v2.2.5
## explicit; go 1.19
github.com/gookit/config/v2
github.com/gookit/config/v2/yaml
# github.com/gookit/goutil v0.6.14
# github.com/gookit/goutil v0.6.15
## explicit; go 1.19
github.com/gookit/goutil
github.com/gookit/goutil/arrutil
@@ -1401,7 +1401,7 @@ github.com/nats-io/nats-server/v2/server/certidp
github.com/nats-io/nats-server/v2/server/certstore
github.com/nats-io/nats-server/v2/server/pse
github.com/nats-io/nats-server/v2/server/sysmem
# github.com/nats-io/nats.go v1.31.0
# github.com/nats-io/nats.go v1.32.0
## explicit; go 1.20
github.com/nats-io/nats.go
github.com/nats-io/nats.go/encoders/builtin
@@ -1590,7 +1590,7 @@ github.com/opentracing/opentracing-go/log
# github.com/orcaman/concurrent-map v1.0.0
## explicit
github.com/orcaman/concurrent-map
# github.com/owncloud/libre-graph-api-go v1.0.5-0.20231201125350-a08244876423
# github.com/owncloud/libre-graph-api-go v1.0.5-0.20240115110609-b018a896364e
## explicit; go 1.18
github.com/owncloud/libre-graph-api-go
# github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c