splitted one operator module to file, account, image operators; splitted operator functions; etc

This commit is contained in:
2026-03-05 11:32:32 +02:00
parent 9ecd25ed0b
commit 80d6a244cf
54 changed files with 1049 additions and 826 deletions
-2
View File
@@ -68,7 +68,6 @@ EXTRA_mstored_SOURCES += \
\ \
app/operator/account.go \ app/operator/account.go \
app/operator/blob.go \ app/operator/blob.go \
app/operator/file.go \
app/operator/grant.go \ app/operator/grant.go \
app/operator/imgaux.go \ app/operator/imgaux.go \
app/operator/manifest.go \ app/operator/manifest.go \
@@ -103,7 +102,6 @@ EXTRA_mstored_SOURCES += \
pkg/client/account.go \ pkg/client/account.go \
pkg/client/client.go \ pkg/client/client.go \
pkg/client/fileaux.go \ pkg/client/fileaux.go \
pkg/client/file.go \
pkg/client/grant.go \ pkg/client/grant.go \
pkg/client/httpcall.go \ pkg/client/httpcall.go \
pkg/client/imageaux.go \ pkg/client/imageaux.go \
+19 -19
View File
@@ -376,26 +376,26 @@ EXTRA_mstored_SOURCES = cmd/mstored/starter/starter.go \
app/maindb/grant.go app/maindb/init.go app/maindb/maindb.go \ app/maindb/grant.go app/maindb/init.go app/maindb/maindb.go \
app/maindb/manifest.go app/maindb/scheme.go \ app/maindb/manifest.go app/maindb/scheme.go \
app/operator/account.go app/operator/blob.go \ app/operator/account.go app/operator/blob.go \
app/operator/file.go app/operator/grant.go \ app/operator/grant.go app/operator/imgaux.go \
app/operator/imgaux.go app/operator/manifest.go \ app/operator/manifest.go app/operator/ociaux.go \
app/operator/ociaux.go app/operator/operator.go \ app/operator/operator.go app/operator/service.go \
app/operator/service.go app/operator/version.go \ app/operator/version.go app/router/bindobj.go \
app/router/bindobj.go app/router/context.go \ app/router/context.go app/router/corsmw.go \
app/router/corsmw.go app/router/loggingmw.go \ app/router/loggingmw.go app/router/pathc.go \
app/router/pathc.go app/router/recovermw.go \ app/router/recovermw.go app/router/router.go \
app/router/router.go app/server/server.go \ app/server/server.go app/service/service.go \
app/service/service.go app/storage/storage.go \ app/storage/storage.go pkg/auxhttp/basic.go \
pkg/auxhttp/basic.go pkg/auxhttp/crange.go \ pkg/auxhttp/crange.go pkg/auxoci/ociaux.go \
pkg/auxoci/ociaux.go pkg/auxpwd/passwd.go \ pkg/auxpwd/passwd.go pkg/auxtool/cleandir.go \
pkg/auxtool/cleandir.go pkg/auxtool/fileex.go \ pkg/auxtool/fileex.go pkg/auxtool/randstr.go \
pkg/auxtool/randstr.go pkg/auxtool/tmpfile.go \ pkg/auxtool/tmpfile.go pkg/auxtool/unixnow.go \
pkg/auxtool/unixnow.go pkg/auxutar/utar.go pkg/auxuuid/uuid.go \ pkg/auxutar/utar.go pkg/auxuuid/uuid.go \
pkg/auxx509/x509cert.go pkg/client/account.go \ pkg/auxx509/x509cert.go pkg/client/account.go \
pkg/client/client.go pkg/client/fileaux.go pkg/client/file.go \ pkg/client/client.go pkg/client/fileaux.go pkg/client/grant.go \
pkg/client/grant.go pkg/client/httpcall.go \ pkg/client/httpcall.go pkg/client/imageaux.go \
pkg/client/imageaux.go pkg/client/imagedelete.go \ pkg/client/imagedelete.go pkg/client/imageinfo.go \
pkg/client/imageinfo.go pkg/client/imagepull.go \ pkg/client/imagepull.go pkg/client/imagepush.go \
pkg/client/imagepush.go pkg/client/service.go pkg/client/service.go
CWD = $(shell pwd) CWD = $(shell pwd)
EXTRA_DIST = vendor/ \ EXTRA_DIST = vendor/ \
\ \
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package accoper
import (
"context"
"fmt"
"mstore/pkg/auxpwd"
"mstore/pkg/auxtool"
"mstore/pkg/auxuuid"
"mstore/pkg/descr"
)
type CreateAccountParams struct {
Username string `json:"username"`
Password string `json:"password"`
}
type CreateAccountResult struct {
AccountID string `json:"accountId"`
}
func (oper *Operator) CreateAccount(ctx context.Context, operatorID string, params *CreateAccountParams) (*CreateAccountResult, error) {
var err error
res := &CreateAccountResult{}
if params.Username == "" {
err := fmt.Errorf("Empty username parameters")
return res, err
}
if params.Password == "" {
err := fmt.Errorf("Empty password parameter")
return res, err
}
accountExists, _, err := oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if accountExists {
err := fmt.Errorf("Account with thist name already exists")
return res, err
}
now := auxtool.TimeNow()
passhash := auxpwd.MakeSHA256Hash([]byte(params.Password))
accountDescr := &descr.Account{
ID: auxuuid.NewUUID(),
Username: params.Username,
Passhash: passhash,
Disabled: false,
CreatedAt: now,
UpdatedAt: now,
CreatedBy: operatorID,
UpdatedBy: operatorID,
}
err = oper.mdb.InsertAccount(ctx, accountDescr)
if err != nil {
return res, err
}
res.AccountID = accountDescr.ID
return res, err
}
+98
View File
@@ -0,0 +1,98 @@
package accoper
import (
"context"
"fmt"
"regexp"
"mstore/pkg/auxtool"
"mstore/pkg/auxuuid"
"mstore/pkg/descr"
)
// CreateGrant
type CreateGrantParams struct {
AccountID string `json:"accountID"`
Username string `json:"username"`
Right string `json:"operation"`
Pattern string `json:"pattern"`
}
type CreateGrantResult struct {
GrantID string `json:"grantId"`
}
func (oper *Operator) CreateGrant(ctx context.Context, operatorID string, params *CreateGrantParams) (*CreateGrantResult, error) {
var err error
res := &CreateGrantResult{}
if params.AccountID == "" {
err := fmt.Errorf("Empty accountId parameters")
return res, err
}
if params.Right == "" {
err := fmt.Errorf("Empty operation parameter")
return res, err
}
if params.Pattern == "" {
err := fmt.Errorf("Empty pattern parameter")
return res, err
}
_, err = regexp.Compile(params.Pattern)
if err != nil {
err := fmt.Errorf("Cannot compile regexp %s: %v", err)
return res, err
}
var accountDescr *descr.Account
var accountExists bool
switch {
case params.AccountID != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
return res, err
}
case params.Username != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with name %s dont exists", params.Username)
return res, err
}
default:
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
grantExists, _, err := oper.mdb.GetGrantByAccoundIDRightPattern(ctx, params.AccountID, params.Right, params.Pattern)
if err != nil {
return res, err
}
if grantExists {
err := fmt.Errorf("Grant with this right already exists")
return res, err
}
oper.logg.Debugf("Call CreateGrant")
now := auxtool.TimeNow()
grantDescr := &descr.Grant{
ID: auxuuid.NewUUID(),
AccountID: accountDescr.ID,
Right: params.Right,
Pattern: params.Pattern,
CreatedAt: now,
UpdatedAt: now,
CreatedBy: operatorID,
UpdatedBy: operatorID,
}
err = oper.mdb.InsertGrant(ctx, grantDescr)
if err != nil {
return res, err
}
res.GrantID = grantDescr.ID
return res, err
}
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package accoper
import (
"context"
"fmt"
"mstore/pkg/descr"
)
type DeleteAccountParams struct {
Username string `json:"username"`
AccountID string `json:"accountId"`
}
type DeleteAccountResult struct{}
func (oper *Operator) DeleteAccount(ctx context.Context, operatorID string, params *DeleteAccountParams) (*DeleteAccountResult, error) {
var err error
res := &DeleteAccountResult{}
if params.Username == "" && params.AccountID == "" {
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
var accountDescr *descr.Account
var accountExists bool
switch {
case params.AccountID != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
return res, err
}
case params.Username != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with name %s dont exists", params.Username)
return res, err
}
default:
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
if accountDescr == nil {
err := fmt.Errorf("Null account desriptor")
return res, err
}
err = oper.mdb.DeleteAllGrantsForAccountID(ctx, accountDescr.ID)
if err != nil {
return res, err
}
err = oper.mdb.DeleteAccountByID(ctx, accountDescr.ID)
if err != nil {
return res, err
}
return res, err
}
+41
View File
@@ -0,0 +1,41 @@
package accoper
import (
"context"
"fmt"
"mstore/pkg/descr"
)
// DeleteGrant
type DeleteGrantParams struct {
GrantID string `json:"grantId"`
}
type DeleteGrantResult struct{}
func (oper *Operator) DeleteGrant(ctx context.Context, operatorID string, params *DeleteGrantParams) (*DeleteGrantResult, error) {
var err error
res := &DeleteGrantResult{}
if params.GrantID == "" {
err := fmt.Errorf("Empty grantId parameter")
return res, err
}
var grantDescr *descr.Grant
var grantExists bool
grantExists, grantDescr, err = oper.mdb.GetGrantByID(ctx, params.GrantID)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Grant with ID %s dont exists", params.GrantID)
return res, err
}
err = oper.mdb.DeleteGrantByID(ctx, grantDescr.ID)
if err != nil {
return res, err
}
return res, err
}
+84
View File
@@ -0,0 +1,84 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package accoper
import (
"context"
"fmt"
"mstore/pkg/descr"
)
// GetAccount
type GetAccountParams struct {
Username string `json:"username"`
AccountID string `json:"accountId"`
}
type GetAccountResult struct {
Account *descr.AccountShort `json:"account"`
}
func (oper *Operator) GetAccount(ctx context.Context, operatorID string, params *GetAccountParams) (*GetAccountResult, error) {
var err error
res := &GetAccountResult{}
if params.Username == "" && params.AccountID == "" {
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
var accountDescr *descr.Account
var accountExists bool
switch {
case params.AccountID != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
return res, err
}
case params.Username != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with name %s dont exists", params.Username)
return res, err
}
default:
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
if accountDescr == nil {
err := fmt.Errorf("Null account desriptor")
return res, err
}
accountShort := &descr.AccountShort{
ID: accountDescr.ID,
Username: accountDescr.Username,
CreatedAt: accountDescr.CreatedAt,
UpdatedAt: accountDescr.UpdatedAt,
CreatedBy: accountDescr.CreatedBy,
UpdatedBy: accountDescr.UpdatedBy,
Disabled: accountDescr.Disabled,
Grants: make([]descr.Grant, 0),
}
grantDescrs, err := oper.mdb.ListGrantsByAccountID(ctx, accountDescr.ID)
if err != nil {
return res, err
}
accountShort.Grants = grantDescrs
res.Account = accountShort
return res, err
}
+40
View File
@@ -0,0 +1,40 @@
package accoper
import (
"context"
"fmt"
"mstore/pkg/descr"
)
// Get Grants
type GetGrantParams struct {
GrantID string `json:"grantId"`
}
type GetGrantResult struct {
Grant *descr.Grant `json:"grant"`
}
func (oper *Operator) GetGrant(ctx context.Context, operatorID string, params *GetGrantParams) (*GetGrantResult, error) {
var err error
res := &GetGrantResult{}
if params.GrantID == "" {
err := fmt.Errorf("Empty grantId parameter")
return res, err
}
var grantDescr *descr.Grant
var grantExists bool
grantExists, grantDescr, err = oper.mdb.GetGrantByID(ctx, params.GrantID)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Grant with ID %s dont exists", params.GrantID)
return res, err
}
res.Grant = grantDescr
return res, err
}
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package accoper
import (
"context"
"mstore/pkg/descr"
)
type ListAccountsParams struct{}
type ListAccountsResult struct {
Accounts []descr.AccountShort `json:"accounts"`
}
func (oper *Operator) ListAccounts(ctx context.Context, params *ListAccountsParams) (*ListAccountsResult, error) {
var err error
res := &ListAccountsResult{}
accountDescrs, err := oper.mdb.ReducedListAccounts(ctx)
if err != nil {
return res, err
}
for _, accountDescr := range accountDescrs {
accountShort := descr.AccountShort{
ID: accountDescr.ID,
Username: accountDescr.Username,
Disabled: accountDescr.Disabled,
CreatedAt: accountDescr.CreatedAt,
UpdatedAt: accountDescr.UpdatedAt,
CreatedBy: accountDescr.CreatedBy,
UpdatedBy: accountDescr.UpdatedBy,
Grants: make([]descr.Grant, 0),
}
grantDescrs, err := oper.mdb.ListGrantsByAccountID(ctx, accountDescr.ID)
if err != nil {
return res, err
}
accountShort.Grants = grantDescrs
res.Accounts = append(res.Accounts, accountShort)
}
return res, err
}
+56
View File
@@ -0,0 +1,56 @@
package accoper
import (
"context"
"fmt"
"mstore/pkg/descr"
)
// ListGrants
type ListGrantsParams struct {
Username string
AccountID string
}
type ListGrantsResult struct {
Grants []descr.Grant `json:"grants"`
}
func (oper *Operator) ListGrants(ctx context.Context, operatorID string, params *ListGrantsParams) (*ListGrantsResult, error) {
var err error
res := &ListGrantsResult{
Grants: make([]descr.Grant, 0),
}
var accountDescr *descr.Account
var accountExists bool
switch {
case params.AccountID != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
return res, err
}
case params.Username != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with name %s dont exists", params.Username)
return res, err
}
default:
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
accountID := accountDescr.ID
grantDescrs, err := oper.mdb.ListGrantsByAccountID(ctx, accountID)
if err != nil {
return res, err
}
res.Grants = grantDescrs
return res, err
}
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package accoper
import ( import (
"mstore/app/locker" "mstore/app/locker"
@@ -37,6 +37,6 @@ func NewOperator(params *OperatorParams) (*Operator, error) {
} }
oper.iLock = locker.NewLocker() oper.iLock = locker.NewLocker()
oper.fLock = locker.NewLocker() oper.fLock = locker.NewLocker()
oper.logg = logger.NewLoggerWithSubject("operator") oper.logg = logger.NewLoggerWithSubject("imageoper")
return oper, err return oper, err
} }
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package accoper
import (
"context"
"fmt"
"mstore/pkg/auxpwd"
"mstore/pkg/auxtool"
"mstore/pkg/descr"
)
type UpdateAccountParams struct {
Username string `json:"username"`
AccountID string `json:"accountId"`
NewUsername string `json:"newUsername"`
NewPassword string `json:"newPassword"`
Disabled bool `json:"disabled"`
}
type UpdateAccountResult struct{}
func (oper *Operator) UpdateAccount(ctx context.Context, operatorID string, params *UpdateAccountParams) (*UpdateAccountResult, error) {
var err error
res := &UpdateAccountResult{}
if params.Username == "" && params.AccountID == "" {
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
var accountDescr *descr.Account
var accountExists bool
switch {
case params.AccountID != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
return res, err
}
case params.Username != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with name %s dont exists", params.Username)
return res, err
}
default:
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
if accountDescr == nil {
err := fmt.Errorf("Null account desriptor")
return res, err
}
now := auxtool.TimeNow()
if params.NewUsername != "" {
accountDescr.UpdatedAt = now
accountDescr.Username = params.NewUsername
}
if params.NewPassword != "" {
accountDescr.UpdatedAt = now
passhash := auxpwd.MakeSHA256Hash([]byte(params.NewPassword))
accountDescr.Passhash = passhash
}
if params.Disabled != accountDescr.Disabled {
accountDescr.UpdatedAt = now
accountDescr.Disabled = params.Disabled
}
err = oper.mdb.UpdateAccountByID(ctx, accountDescr.ID, accountDescr)
if err != nil {
return res, err
}
return res, err
}
+52
View File
@@ -0,0 +1,52 @@
package accoper
import (
"context"
"fmt"
"mstore/pkg/auxtool"
"mstore/pkg/descr"
)
// UpdateGrant
type UpdateGrantParams struct {
GrantID string
NewPattern string
}
type UpdateGrantResult struct{}
func (oper *Operator) UpdateGrant(ctx context.Context, operatorID string, params *UpdateGrantParams) (*UpdateGrantResult, error) {
var err error
res := &UpdateGrantResult{}
if params.NewPattern == "" {
err := fmt.Errorf("Empty newPattern parameter")
return res, err
}
if params.GrantID == "" {
err := fmt.Errorf("Empty grantId parameter")
return res, err
}
var grantDescr *descr.Grant
var grantExists bool
grantExists, grantDescr, err = oper.mdb.GetGrantByID(ctx, params.GrantID)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Grant with ID %s dont exists", params.GrantID)
return res, err
}
now := auxtool.TimeNow()
if params.NewPattern != "" {
grantDescr.UpdatedAt = now
grantDescr.UpdatedBy = operatorID
grantDescr.Pattern = params.NewPattern
}
err = oper.mdb.UpdateGrantByID(ctx, grantDescr.ID, grantDescr)
if err != nil {
return res, err
}
return res, err
}
+10
View File
@@ -0,0 +1,10 @@
package config
const (
confdir = "/home/ziggi/Projects/mstore/etc/mstore"
rundir = "/home/ziggi/Projects/mstore/tmp/run"
logdir = "/home/ziggi/Projects/mstore/tmp/log"
datadir = "/home/ziggi/Projects/mstore/tmp/data"
version = "0.2.0"
srvname = "mstored"
)
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package fileoper
import ( import (
"context" "context"
@@ -17,7 +17,6 @@ import (
"mstore/pkg/filecli" "mstore/pkg/filecli"
) )
// DeleteColletion // DeleteColletion
type DeleteColletionParams struct { type DeleteColletionParams struct {
Path string Path string
@@ -100,7 +99,7 @@ func (oper *Operator) deleteFilesInCollection(ctx context.Context, collection st
} }
for _, file := range files { for _, file := range files {
if !dryRun { if !dryRun {
oper.logg.Debugf("Delete file %s/%s", file.Collection, file.Name) oper.logg.Debugf("Delete file %s/%s", file.Collection, file.Name)
err = oper.store.DeleteFile(file.Collection, file.Name) err = oper.store.DeleteFile(file.Collection, file.Name)
if err != nil { if err != nil {
oper.logg.Warningf("%v", err) oper.logg.Warningf("%v", err)
@@ -116,5 +115,3 @@ func (oper *Operator) deleteFilesInCollection(ctx context.Context, collection st
} }
return res, err return res, err
} }
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package fileoper
import ( import (
"context" "context"
@@ -15,7 +15,6 @@ import (
"path" "path"
) )
// DeleteFile // DeleteFile
type DeleteFileParams struct { type DeleteFileParams struct {
Filepath string Filepath string
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package fileoper
import ( import (
"context" "context"
@@ -81,4 +81,3 @@ func (oper *Operator) FileInfo(ctx context.Context, operatorID string, params *F
} }
return code, res, err return code, res, err
} }
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package fileoper
import ( import (
"context" "context"
@@ -77,4 +77,3 @@ func (oper *Operator) GetFile(ctx context.Context, operatorID string, params *Ge
code := http.StatusOK code := http.StatusOK
return code, res, err return code, res, err
} }
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package fileoper
import ( import (
"context" "context"
@@ -150,4 +150,3 @@ func (oper *Operator) listAllCollections(ctx context.Context) ([]string, error)
slices.Sort(res) slices.Sort(res)
return res, err return res, err
} }
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package fileoper
import ( import (
"context" "context"
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package fileoper
import (
"mstore/app/locker"
"mstore/app/logger"
"mstore/app/maindb"
"mstore/app/storage"
)
type OperatorParams struct {
MainDB *maindb.Database
Store *storage.Storage
}
type Operator struct {
mdb *maindb.Database
store *storage.Storage
logg *logger.Logger
iLock *locker.Locker
fLock *locker.Locker
}
func NewOperator(params *OperatorParams) (*Operator, error) {
var err error
oper := &Operator{
mdb: params.MainDB,
store: params.Store,
}
oper.iLock = locker.NewLocker()
oper.fLock = locker.NewLocker()
oper.logg = logger.NewLoggerWithSubject("fileoper")
return oper, err
}
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package fileoper
import ( import (
"context" "context"
@@ -118,4 +118,3 @@ func (oper *Operator) PutFile(ctx context.Context, operatorID string, params *Pu
code := http.StatusOK code := http.StatusOK
return code, res, err return code, res, err
} }
+2 -2
View File
@@ -52,9 +52,9 @@ func (hand *Handler) CheckAccess(rctx *router.Context) (bool, string, error) {
accountID = terms.AnonymousID accountID = terms.AnonymousID
hand.logg.Debugf("URL: %s", rctx.URL().String()) hand.logg.Debugf("URL: %s", rctx.URL().String())
authHeader := rctx.GetHeader("Authorization") authHeader := rctx.GetHeader("Authorization")
hand.logg.Debugf("Authorization: %s", authHeader) hand.logg.Debugf("Authorization: %s", authHeader)
if authHeader != "" { if authHeader != "" {
username, password, err = auxhttp.ParseBasicAuth(authHeader) username, password, err = auxhttp.ParseBasicAuth(authHeader)
if err != nil { if err != nil {
+11 -11
View File
@@ -12,7 +12,7 @@ package handler
import ( import (
"fmt" "fmt"
"mstore/app/operator" "mstore/app/accoper"
"mstore/app/router" "mstore/app/router"
"mstore/pkg/terms" "mstore/pkg/terms"
) )
@@ -21,7 +21,7 @@ import (
func (hand *Handler) CreateAccount(rctx *router.Context) { func (hand *Handler) CreateAccount(rctx *router.Context) {
var err error var err error
params := &operator.CreateAccountParams{} params := &accoper.CreateAccountParams{}
err = rctx.BindJSON(params) err = rctx.BindJSON(params)
if err != nil { if err != nil {
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -41,7 +41,7 @@ func (hand *Handler) CreateAccount(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, err := hand.oper.CreateAccount(rctx.Ctx, operatorID, params) res, err := hand.acop.CreateAccount(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("Operation error: %v", err) hand.logg.Errorf("Operation error: %v", err)
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -54,7 +54,7 @@ func (hand *Handler) CreateAccount(rctx *router.Context) {
func (hand *Handler) GetAccount(rctx *router.Context) { func (hand *Handler) GetAccount(rctx *router.Context) {
var err error var err error
params := &operator.GetAccountParams{} params := &accoper.GetAccountParams{}
err = rctx.BindJSON(params) err = rctx.BindJSON(params)
if err != nil { if err != nil {
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -74,7 +74,7 @@ func (hand *Handler) GetAccount(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, err := hand.oper.GetAccount(rctx.Ctx, operatorID, params) res, err := hand.acop.GetAccount(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("Operation error: %v", err) hand.logg.Errorf("Operation error: %v", err)
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -87,7 +87,7 @@ func (hand *Handler) GetAccount(rctx *router.Context) {
func (hand *Handler) ListAccounts(rctx *router.Context) { func (hand *Handler) ListAccounts(rctx *router.Context) {
var err error var err error
params := &operator.ListAccountsParams{} params := &accoper.ListAccountsParams{}
err = rctx.BindJSON(params) err = rctx.BindJSON(params)
if err != nil { if err != nil {
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -107,7 +107,7 @@ func (hand *Handler) ListAccounts(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, err := hand.oper.ListAccounts(rctx.Ctx, params) res, err := hand.acop.ListAccounts(rctx.Ctx, params)
if err != nil { if err != nil {
hand.logg.Errorf("ListAccounts error: %v", err) hand.logg.Errorf("ListAccounts error: %v", err)
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -120,7 +120,7 @@ func (hand *Handler) ListAccounts(rctx *router.Context) {
func (hand *Handler) UpdateAccount(rctx *router.Context) { func (hand *Handler) UpdateAccount(rctx *router.Context) {
var err error var err error
params := &operator.UpdateAccountParams{} params := &accoper.UpdateAccountParams{}
err = rctx.BindJSON(params) err = rctx.BindJSON(params)
if err != nil { if err != nil {
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -140,7 +140,7 @@ func (hand *Handler) UpdateAccount(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, err := hand.oper.UpdateAccount(rctx.Ctx, operatorID, params) res, err := hand.acop.UpdateAccount(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("UpdateAccount error: %v", err) hand.logg.Errorf("UpdateAccount error: %v", err)
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -153,7 +153,7 @@ func (hand *Handler) UpdateAccount(rctx *router.Context) {
func (hand *Handler) DeleteAccount(rctx *router.Context) { func (hand *Handler) DeleteAccount(rctx *router.Context) {
var err error var err error
params := &operator.DeleteAccountParams{} params := &accoper.DeleteAccountParams{}
err = rctx.BindJSON(params) err = rctx.BindJSON(params)
if err != nil { if err != nil {
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -173,7 +173,7 @@ func (hand *Handler) DeleteAccount(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, err := hand.oper.DeleteAccount(rctx.Ctx, operatorID, params) res, err := hand.acop.DeleteAccount(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("DeleteAccount error: %v", err) hand.logg.Errorf("DeleteAccount error: %v", err)
hand.SendError(rctx, err) hand.SendError(rctx, err)
+13 -15
View File
@@ -14,7 +14,7 @@ import (
"io" "io"
"net/http" "net/http"
"mstore/app/operator" "mstore/app/imageoper"
"mstore/app/router" "mstore/app/router"
"mstore/pkg/terms" "mstore/pkg/terms"
) )
@@ -26,7 +26,7 @@ func (hand *Handler) BlobExists(rctx *router.Context) {
//hand.DumpHeaders("BlobExists", rctx) //hand.DumpHeaders("BlobExists", rctx)
params := &operator.BlobExistsParams{ params := &imageoper.BlobExistsParams{
Name: name, Name: name,
Digest: digest, Digest: digest,
} }
@@ -43,7 +43,7 @@ func (hand *Handler) BlobExists(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
res, code, err := hand.oper.BlobExists(ctx, operatorID, params) res, code, err := hand.imop.BlobExists(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("BlobExist error: %v", err) hand.logg.Errorf("BlobExist error: %v", err)
} }
@@ -75,7 +75,7 @@ func (hand *Handler) PostUpload(rctx *router.Context) {
mount := rctx.GetQuery("mount") mount := rctx.GetQuery("mount")
from := rctx.GetQuery("from") from := rctx.GetQuery("from")
params := &operator.PostUploadParams{ params := &imageoper.PostUploadParams{
Name: name, Name: name,
Digest: digest, Digest: digest,
Mount: mount, Mount: mount,
@@ -93,7 +93,7 @@ func (hand *Handler) PostUpload(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, code, err := hand.oper.PostUpload(rctx.Ctx, operatorID, params) res, code, err := hand.imop.PostUpload(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("PostUpload error: %v", err) hand.logg.Errorf("PostUpload error: %v", err)
} else { } else {
@@ -104,8 +104,6 @@ func (hand *Handler) PostUpload(rctx *router.Context) {
rctx.SetStatus(code) rctx.SetStatus(code)
} }
// PATCH /v2/<name>/blobs/uploads/<reference> 202 404/416 // PATCH /v2/<name>/blobs/uploads/<reference> 202 404/416
func (hand *Handler) PatchUpload(rctx *router.Context) { func (hand *Handler) PatchUpload(rctx *router.Context) {
@@ -117,7 +115,7 @@ func (hand *Handler) PatchUpload(rctx *router.Context) {
reference, _ := rctx.GetSubpath("reference") reference, _ := rctx.GetSubpath("reference")
reader := rctx.Request.Body reader := rctx.Request.Body
params := &operator.PatchUploadParams{ params := &imageoper.PatchUploadParams{
ContentLength: contentLength, ContentLength: contentLength,
ContentType: contentType, ContentType: contentType,
ContentRange: contentRange, ContentRange: contentRange,
@@ -138,7 +136,7 @@ func (hand *Handler) PatchUpload(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
res, code, err := hand.oper.PatchUpload(ctx, operatorID, params) res, code, err := hand.imop.PatchUpload(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("PatchUpload error: %v", err) hand.logg.Errorf("PatchUpload error: %v", err)
} }
@@ -162,7 +160,7 @@ func (hand *Handler) PutUpload(rctx *router.Context) {
digest := rctx.GetQuery("digest") digest := rctx.GetQuery("digest")
reader := rctx.Request.Body reader := rctx.Request.Body
params := &operator.PutUploadParams{ params := &imageoper.PutUploadParams{
ContentLength: contentLength, ContentLength: contentLength,
ContentType: contentType, ContentType: contentType,
ContentRange: contentRange, ContentRange: contentRange,
@@ -183,7 +181,7 @@ func (hand *Handler) PutUpload(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, code, err := hand.oper.PutUpload(rctx.Ctx, operatorID, params) res, code, err := hand.imop.PutUpload(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("PutUpload error: %v", err) hand.logg.Errorf("PutUpload error: %v", err)
} }
@@ -197,7 +195,7 @@ func (hand *Handler) GetBlob(rctx *router.Context) {
name, _ := rctx.GetSubpath("name") name, _ := rctx.GetSubpath("name")
digest, _ := rctx.GetSubpath("digest") digest, _ := rctx.GetSubpath("digest")
params := &operator.GetBlobParams{ params := &imageoper.GetBlobParams{
Name: name, Name: name,
Digest: digest, Digest: digest,
} }
@@ -214,7 +212,7 @@ func (hand *Handler) GetBlob(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
res, code, err := hand.oper.GetBlob(ctx, operatorID, params) res, code, err := hand.imop.GetBlob(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("GetBlob error: %v", err) hand.logg.Errorf("GetBlob error: %v", err)
} }
@@ -243,7 +241,7 @@ func (hand *Handler) DeleteBlob(rctx *router.Context) {
name, _ := rctx.GetSubpath("name") name, _ := rctx.GetSubpath("name")
digest, _ := rctx.GetSubpath("digest") digest, _ := rctx.GetSubpath("digest")
params := &operator.DeleteBlobParams{ params := &imageoper.DeleteBlobParams{
Name: name, Name: name,
Digest: digest, Digest: digest,
} }
@@ -260,7 +258,7 @@ func (hand *Handler) DeleteBlob(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
_, code, err := hand.oper.DeleteBlob(ctx, operatorID, params) _, code, err := hand.imop.DeleteBlob(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("DeleteBlob error: %v", err) hand.logg.Errorf("DeleteBlob error: %v", err)
} }
+15 -15
View File
@@ -13,7 +13,7 @@ import (
"io" "io"
"net/http" "net/http"
"mstore/app/operator" "mstore/app/fileoper"
"mstore/app/router" "mstore/app/router"
"mstore/pkg/terms" "mstore/pkg/terms"
) )
@@ -23,7 +23,7 @@ const zeroContentLength = "0"
func (hand *Handler) FileInfo(rctx *router.Context) { func (hand *Handler) FileInfo(rctx *router.Context) {
filepath, _ := rctx.GetSubpath("filepath") filepath, _ := rctx.GetSubpath("filepath")
params := &operator.FileInfoParams{ params := &fileoper.FileInfoParams{
Filepath: filepath, Filepath: filepath,
} }
// Rigth checking // Rigth checking
@@ -39,7 +39,7 @@ func (hand *Handler) FileInfo(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
code, res, err := hand.oper.FileInfo(ctx, operatorID, params) code, res, err := hand.fiop.FileInfo(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("FileInfo error: %v", err) hand.logg.Errorf("FileInfo error: %v", err)
rctx.SetStatus(code) rctx.SetStatus(code)
@@ -65,7 +65,7 @@ func (hand *Handler) PutFile(rctx *router.Context) {
contentType := rctx.GetHeader("Content-Type") contentType := rctx.GetHeader("Content-Type")
filepath, _ := rctx.GetSubpath("filepath") filepath, _ := rctx.GetSubpath("filepath")
params := &operator.PutFileParams{ params := &fileoper.PutFileParams{
Filepath: filepath, Filepath: filepath,
ContentType: contentType, ContentType: contentType,
ContentSize: contentSize, ContentSize: contentSize,
@@ -84,7 +84,7 @@ func (hand *Handler) PutFile(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
code, _, err := hand.oper.PutFile(ctx, operatorID, params) code, _, err := hand.fiop.PutFile(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("PutFile error: %v", err) hand.logg.Errorf("PutFile error: %v", err)
rctx.SetStatus(code) rctx.SetStatus(code)
@@ -96,7 +96,7 @@ func (hand *Handler) PutFile(rctx *router.Context) {
func (hand *Handler) GetFile(rctx *router.Context) { func (hand *Handler) GetFile(rctx *router.Context) {
filepath, _ := rctx.GetSubpath("filepath") filepath, _ := rctx.GetSubpath("filepath")
params := &operator.GetFileParams{ params := &fileoper.GetFileParams{
Filepath: filepath, Filepath: filepath,
} }
// Rigth checking // Rigth checking
@@ -112,7 +112,7 @@ func (hand *Handler) GetFile(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
code, res, err := hand.oper.GetFile(ctx, operatorID, params) code, res, err := hand.fiop.GetFile(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("PutFile error: %v", err) hand.logg.Errorf("PutFile error: %v", err)
rctx.SetStatus(code) rctx.SetStatus(code)
@@ -144,7 +144,7 @@ func (hand *Handler) GetFile(rctx *router.Context) {
func (hand *Handler) DeleteFile(rctx *router.Context) { func (hand *Handler) DeleteFile(rctx *router.Context) {
filepath, _ := rctx.GetSubpath("filepath") filepath, _ := rctx.GetSubpath("filepath")
params := &operator.DeleteFileParams{ params := &fileoper.DeleteFileParams{
Filepath: filepath, Filepath: filepath,
} }
// Rigth checking // Rigth checking
@@ -160,7 +160,7 @@ func (hand *Handler) DeleteFile(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
code, _, err := hand.oper.DeleteFile(ctx, operatorID, params) code, _, err := hand.fiop.DeleteFile(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("DeleteFIle error: %v", err) hand.logg.Errorf("DeleteFIle error: %v", err)
} }
@@ -174,7 +174,7 @@ func (hand *Handler) ListFiles(rctx *router.Context) {
if filepath == "" { if filepath == "" {
filepath = "/" filepath = "/"
} }
params := &operator.ListFilesParams{ params := &fileoper.ListFilesParams{
Filepath: filepath, Filepath: filepath,
} }
err := rctx.BindQuery(params) err := rctx.BindQuery(params)
@@ -197,7 +197,7 @@ func (hand *Handler) ListFiles(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
code, res, err := hand.oper.ListFiles(ctx, operatorID, params) code, res, err := hand.fiop.ListFiles(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("ListFiles error: %v", err) hand.logg.Errorf("ListFiles error: %v", err)
rctx.SetStatus(code) rctx.SetStatus(code)
@@ -212,7 +212,7 @@ func (hand *Handler) ListCollections(rctx *router.Context) {
if cpath == "" { if cpath == "" {
cpath = "/" cpath = "/"
} }
params := &operator.ListCollectionsParams{ params := &fileoper.ListCollectionsParams{
Path: cpath, Path: cpath,
} }
err := rctx.BindQuery(params) err := rctx.BindQuery(params)
@@ -234,7 +234,7 @@ func (hand *Handler) ListCollections(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
code, res, err := hand.oper.ListCollections(ctx, operatorID, params) code, res, err := hand.fiop.ListCollections(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("ListCollections error: %v", err) hand.logg.Errorf("ListCollections error: %v", err)
rctx.SetStatus(code) rctx.SetStatus(code)
@@ -249,7 +249,7 @@ func (hand *Handler) DeleteCollection(rctx *router.Context) {
if cpath == "" { if cpath == "" {
cpath = "/" cpath = "/"
} }
params := &operator.DeleteColletionParams{ params := &fileoper.DeleteColletionParams{
Path: cpath, Path: cpath,
} }
err := rctx.BindQuery(params) err := rctx.BindQuery(params)
@@ -272,7 +272,7 @@ func (hand *Handler) DeleteCollection(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
code, res, err := hand.oper.DeleteColletion(ctx, operatorID, params) code, res, err := hand.fiop.DeleteColletion(ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("DeleteColletion error: %v", err) hand.logg.Errorf("DeleteColletion error: %v", err)
rctx.SetStatus(code) rctx.SetStatus(code)
+11 -11
View File
@@ -12,7 +12,7 @@ package handler
import ( import (
"fmt" "fmt"
"mstore/app/operator" "mstore/app/accoper"
"mstore/app/router" "mstore/app/router"
"mstore/pkg/terms" "mstore/pkg/terms"
) )
@@ -21,7 +21,7 @@ import (
func (hand *Handler) CreateGrant(rctx *router.Context) { func (hand *Handler) CreateGrant(rctx *router.Context) {
var err error var err error
params := &operator.CreateGrantParams{} params := &accoper.CreateGrantParams{}
err = rctx.BindJSON(params) err = rctx.BindJSON(params)
if err != nil { if err != nil {
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -41,7 +41,7 @@ func (hand *Handler) CreateGrant(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, err := hand.oper.CreateGrant(rctx.Ctx, operatorID, params) res, err := hand.acop.CreateGrant(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("CreateGrant error: %v", err) hand.logg.Errorf("CreateGrant error: %v", err)
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -54,7 +54,7 @@ func (hand *Handler) CreateGrant(rctx *router.Context) {
func (hand *Handler) GetGrant(rctx *router.Context) { func (hand *Handler) GetGrant(rctx *router.Context) {
var err error var err error
params := &operator.GetGrantParams{} params := &accoper.GetGrantParams{}
err = rctx.BindJSON(params) err = rctx.BindJSON(params)
if err != nil { if err != nil {
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -74,7 +74,7 @@ func (hand *Handler) GetGrant(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, err := hand.oper.GetGrant(rctx.Ctx, operatorID, params) res, err := hand.acop.GetGrant(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("CreateGrant error: %v", err) hand.logg.Errorf("CreateGrant error: %v", err)
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -87,7 +87,7 @@ func (hand *Handler) GetGrant(rctx *router.Context) {
func (hand *Handler) ListGrants(rctx *router.Context) { func (hand *Handler) ListGrants(rctx *router.Context) {
var err error var err error
params := &operator.ListGrantsParams{} params := &accoper.ListGrantsParams{}
err = rctx.BindJSON(params) err = rctx.BindJSON(params)
if err != nil { if err != nil {
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -107,7 +107,7 @@ func (hand *Handler) ListGrants(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, err := hand.oper.ListGrants(rctx.Ctx, operatorID, params) res, err := hand.acop.ListGrants(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("ListGrants error: %v", err) hand.logg.Errorf("ListGrants error: %v", err)
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -120,7 +120,7 @@ func (hand *Handler) ListGrants(rctx *router.Context) {
func (hand *Handler) UpdateGrant(rctx *router.Context) { func (hand *Handler) UpdateGrant(rctx *router.Context) {
var err error var err error
params := &operator.UpdateGrantParams{} params := &accoper.UpdateGrantParams{}
err = rctx.BindJSON(params) err = rctx.BindJSON(params)
if err != nil { if err != nil {
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -140,7 +140,7 @@ func (hand *Handler) UpdateGrant(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, err := hand.oper.UpdateGrant(rctx.Ctx, operatorID, params) res, err := hand.acop.UpdateGrant(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("UpdateGrant error: %v", err) hand.logg.Errorf("UpdateGrant error: %v", err)
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -153,7 +153,7 @@ func (hand *Handler) UpdateGrant(rctx *router.Context) {
func (hand *Handler) DeleteGrant(rctx *router.Context) { func (hand *Handler) DeleteGrant(rctx *router.Context) {
var err error var err error
params := &operator.DeleteGrantParams{} params := &accoper.DeleteGrantParams{}
err = rctx.BindJSON(params) err = rctx.BindJSON(params)
if err != nil { if err != nil {
hand.SendError(rctx, err) hand.SendError(rctx, err)
@@ -173,7 +173,7 @@ func (hand *Handler) DeleteGrant(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, err := hand.oper.DeleteGrant(rctx.Ctx, operatorID, params) res, err := hand.acop.DeleteGrant(rctx.Ctx, operatorID, params)
if err != nil { if err != nil {
hand.logg.Errorf("DeleteGrant error: %v", err) hand.logg.Errorf("DeleteGrant error: %v", err)
hand.SendError(rctx, err) hand.SendError(rctx, err)
+15 -5
View File
@@ -12,28 +12,38 @@ package handler
import ( import (
"mstore/app/logger" "mstore/app/logger"
"mstore/app/maindb" "mstore/app/maindb"
"mstore/app/operator"
"mstore/app/router" "mstore/app/router"
"mstore/app/accoper"
"mstore/app/fileoper"
"mstore/app/imageoper"
yaml "go.yaml.in/yaml/v4" yaml "go.yaml.in/yaml/v4"
) )
type HandlerParams struct { type HandlerParams struct {
Operator *operator.Operator MainDB *maindb.Database
MainDB *maindb.Database FileOper *fileoper.Operator
AccOper *accoper.Operator
ImageOper *imageoper.Operator
} }
type Handler struct { type Handler struct {
oper *operator.Operator
mdb *maindb.Database mdb *maindb.Database
logg *logger.Logger logg *logger.Logger
fiop *fileoper.Operator
acop *accoper.Operator
imop *imageoper.Operator
} }
func NewHandler(params *HandlerParams) (*Handler, error) { func NewHandler(params *HandlerParams) (*Handler, error) {
var err error var err error
hand := &Handler{ hand := &Handler{
oper: params.Operator,
mdb: params.MainDB, mdb: params.MainDB,
fiop: params.FileOper,
acop: params.AccOper,
imop: params.ImageOper,
} }
hand.logg = logger.NewLoggerWithSubject("handler") hand.logg = logger.NewLoggerWithSubject("handler")
return hand, err return hand, err
+15 -15
View File
@@ -12,7 +12,7 @@ package handler
import ( import (
"net/http" "net/http"
"mstore/app/operator" "mstore/app/imageoper"
"mstore/app/router" "mstore/app/router"
"mstore/pkg/terms" "mstore/pkg/terms"
) )
@@ -23,7 +23,7 @@ func (hand *Handler) ManifestExists(rctx *router.Context) {
//hand.DumpHeaders("ManigestExists:\n", rctx) //hand.DumpHeaders("ManigestExists:\n", rctx)
params := &operator.ManifestExistsParams{ params := &imageoper.ManifestExistsParams{
Name: name, Name: name,
Reference: reference, Reference: reference,
} }
@@ -40,7 +40,7 @@ func (hand *Handler) ManifestExists(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
res, code, err := hand.oper.ManifestExists(ctx, params) res, code, err := hand.imop.ManifestExists(ctx, params)
if err != nil { if err != nil {
hand.logg.Errorf("ManifestExist error: %v", err) hand.logg.Errorf("ManifestExist error: %v", err)
} else if code == http.StatusOK { } else if code == http.StatusOK {
@@ -62,7 +62,7 @@ func (hand *Handler) PutManifest(rctx *router.Context) {
name, _ := rctx.GetSubpath("name") name, _ := rctx.GetSubpath("name")
reference, _ := rctx.GetSubpath("reference") reference, _ := rctx.GetSubpath("reference")
params := &operator.PutManifestParams{ params := &imageoper.PutManifestParams{
ContentType: contentType, ContentType: contentType,
ContentLength: contentLength, ContentLength: contentLength,
Name: name, Name: name,
@@ -82,7 +82,7 @@ func (hand *Handler) PutManifest(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
res, code, err := hand.oper.PutManifest(ctx, params) res, code, err := hand.imop.PutManifest(ctx, params)
if err != nil { if err != nil {
hand.logg.Errorf("PutManifest error: %v", err) hand.logg.Errorf("PutManifest error: %v", err)
} else { } else {
@@ -98,7 +98,7 @@ func (hand *Handler) GetManifest(rctx *router.Context) {
//hand.DumpHeaders("GetManigest", rctx) //hand.DumpHeaders("GetManigest", rctx)
params := &operator.GetManifestParams{ params := &imageoper.GetManifestParams{
Name: name, Name: name,
Reference: reference, Reference: reference,
} }
@@ -115,7 +115,7 @@ func (hand *Handler) GetManifest(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
res, code, err := hand.oper.GetManifest(ctx, params) res, code, err := hand.imop.GetManifest(ctx, params)
if err != nil { if err != nil {
hand.logg.Errorf("GetManifest error: %v", err) hand.logg.Errorf("GetManifest error: %v", err)
rctx.SetStatus(code) rctx.SetStatus(code)
@@ -138,7 +138,7 @@ func (hand *Handler) DeleteManifest(rctx *router.Context) {
name, _ := rctx.GetSubpath("name") name, _ := rctx.GetSubpath("name")
reference, _ := rctx.GetSubpath("reference") reference, _ := rctx.GetSubpath("reference")
params := &operator.DeleteManifestParams{ params := &imageoper.DeleteManifestParams{
Name: name, Name: name,
Reference: reference, Reference: reference,
} }
@@ -155,7 +155,7 @@ func (hand *Handler) DeleteManifest(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
_, code, err := hand.oper.DeleteManifest(ctx, params) _, code, err := hand.imop.DeleteManifest(ctx, params)
if err != nil { if err != nil {
hand.logg.Errorf("DeleteManifest error: %v", err) hand.logg.Errorf("DeleteManifest error: %v", err)
} }
@@ -167,7 +167,7 @@ func (hand *Handler) DeleteManifest(rctx *router.Context) {
func (hand *Handler) GetReferer(rctx *router.Context) { func (hand *Handler) GetReferer(rctx *router.Context) {
name, _ := rctx.GetSubpath("name") name, _ := rctx.GetSubpath("name")
digest, _ := rctx.GetSubpath("digest") digest, _ := rctx.GetSubpath("digest")
params := &operator.GetRefererParams{ params := &imageoper.GetRefererParams{
Name: name, Name: name,
Digest: digest, Digest: digest,
} }
@@ -183,7 +183,7 @@ func (hand *Handler) GetReferer(rctx *router.Context) {
return return
} }
// Execution of the operation // Execution of the operation
res, code, err := hand.oper.GetReferer(rctx.Ctx, params) res, code, err := hand.imop.GetReferer(rctx.Ctx, params)
if err != nil { if err != nil {
hand.logg.Errorf("GetReferer error: %v", err) hand.logg.Errorf("GetReferer error: %v", err)
} }
@@ -194,7 +194,7 @@ func (hand *Handler) GetReferer(rctx *router.Context) {
// GET /v2/<name>/tags/list?n=<integer>&last=<integer> // GET /v2/<name>/tags/list?n=<integer>&last=<integer>
func (hand *Handler) GetTags(rctx *router.Context) { func (hand *Handler) GetTags(rctx *router.Context) {
name, _ := rctx.GetSubpath("name") name, _ := rctx.GetSubpath("name")
params := &operator.GetTagsParams{ params := &imageoper.GetTagsParams{
Name: name, Name: name,
} }
// Rigth checking // Rigth checking
@@ -210,7 +210,7 @@ func (hand *Handler) GetTags(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
res, code, err := hand.oper.GetTags(ctx, params) res, code, err := hand.imop.GetTags(ctx, params)
if err != nil { if err != nil {
hand.logg.Errorf("GetTags error: %v", err) hand.logg.Errorf("GetTags error: %v", err)
} }
@@ -219,7 +219,7 @@ func (hand *Handler) GetTags(rctx *router.Context) {
// GET /v2/_catalog?n=1000 200 404 // GET /v2/_catalog?n=1000 200 404
func (hand *Handler) ListManifests(rctx *router.Context) { func (hand *Handler) ListManifests(rctx *router.Context) {
params := &operator.ListManifestsParams{} params := &imageoper.ListManifestsParams{}
// Rigth checking // Rigth checking
operatorID, _ := rctx.GetString(userTag) operatorID, _ := rctx.GetString(userTag)
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, "_catalog") opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, "_catalog")
@@ -233,7 +233,7 @@ func (hand *Handler) ListManifests(rctx *router.Context) {
} }
// Execution of the operation // Execution of the operation
ctx := rctx.GetContext() ctx := rctx.GetContext()
res, code, err := hand.oper.ListManifests(ctx, params) res, code, err := hand.imop.ListManifests(ctx, params)
if err != nil { if err != nil {
hand.logg.Errorf("ListManifests error: %v", err) hand.logg.Errorf("ListManifests error: %v", err)
} }
+3 -3
View File
@@ -10,12 +10,12 @@
package handler package handler
import ( import (
"mstore/app/operator" "mstore/app/imageoper"
"mstore/app/router" "mstore/app/router"
) )
func (hand *Handler) SendHello(rctx *router.Context) { func (hand *Handler) SendHello(rctx *router.Context) {
params := &operator.SendHelloParams{} params := &imageoper.SendHelloParams{}
res, _ := hand.oper.SendHello(params) res, _ := hand.imop.SendHello(params)
hand.SendResult(rctx, res) hand.SendResult(rctx, res)
} }
+3 -3
View File
@@ -12,13 +12,13 @@ package handler
import ( import (
"net/http" "net/http"
"mstore/app/operator" "mstore/app/imageoper"
"mstore/app/router" "mstore/app/router"
) )
// GET /v2/ 200 404/401 // GET /v2/ 200 404/401
func (hand *Handler) GetVersion(rctx *router.Context) { func (hand *Handler) GetVersion(rctx *router.Context) {
params := &operator.GetVersionParams{} params := &imageoper.GetVersionParams{}
//hand.DumpHeaders("GetVersion", rctx) //hand.DumpHeaders("GetVersion", rctx)
authorization := rctx.GetHeader("Authorization") authorization := rctx.GetHeader("Authorization")
@@ -28,7 +28,7 @@ func (hand *Handler) GetVersion(rctx *router.Context) {
return return
} }
ctx := rctx.GetContext() ctx := rctx.GetContext()
_, code, err := hand.oper.GetVersion(ctx, params) _, code, err := hand.imop.GetVersion(ctx, params)
if err != nil { if err != nil {
hand.logg.Errorf("GetVersion error: %v", err) hand.logg.Errorf("GetVersion error: %v", err)
} }
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package imageoper
import ( import (
"context" "context"
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package imageoper
import ( import (
"encoding/hex" "encoding/hex"
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package imageoper
import ( import (
"bytes" "bytes"
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package imageoper
import ( import (
"encoding/json" "encoding/json"
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package imageoper
import (
"mstore/app/locker"
"mstore/app/logger"
"mstore/app/maindb"
"mstore/app/storage"
)
type OperatorParams struct {
MainDB *maindb.Database
Store *storage.Storage
}
type Operator struct {
mdb *maindb.Database
store *storage.Storage
logg *logger.Logger
iLock *locker.Locker
fLock *locker.Locker
}
func NewOperator(params *OperatorParams) (*Operator, error) {
var err error
oper := &Operator{
mdb: params.MainDB,
store: params.Store,
}
oper.iLock = locker.NewLocker()
oper.fLock = locker.NewLocker()
oper.logg = logger.NewLoggerWithSubject("imageoper")
return oper, err
}
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package imageoper
type SendHelloParams struct{} type SendHelloParams struct{}
@@ -7,7 +7,7 @@
* Distribution of this work is permitted, but commercial use and * Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited. * modifications are strictly prohibited.
*/ */
package operator package imageoper
import ( import (
"context" "context"
-284
View File
@@ -1,284 +0,0 @@
package operator
import (
"context"
"fmt"
"mstore/pkg/auxpwd"
"mstore/pkg/auxtool"
"mstore/pkg/auxuuid"
"mstore/pkg/descr"
)
type CreateAccountParams struct {
Username string `json:"username"`
Password string `json:"password"`
}
type CreateAccountResult struct {
AccountID string `json:"accountId"`
}
func (oper *Operator) CreateAccount(ctx context.Context, operatorID string, params *CreateAccountParams) (*CreateAccountResult, error) {
var err error
res := &CreateAccountResult{}
if params.Username == "" {
err := fmt.Errorf("Empty username parameters")
return res, err
}
if params.Password == "" {
err := fmt.Errorf("Empty password parameter")
return res, err
}
accountExists, _, err := oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if accountExists {
err := fmt.Errorf("Account with thist name already exists")
return res, err
}
now := auxtool.TimeNow()
passhash := auxpwd.MakeSHA256Hash([]byte(params.Password))
accountDescr := &descr.Account{
ID: auxuuid.NewUUID(),
Username: params.Username,
Passhash: passhash,
Disabled: false,
CreatedAt: now,
UpdatedAt: now,
CreatedBy: operatorID,
UpdatedBy: operatorID,
}
err = oper.mdb.InsertAccount(ctx, accountDescr)
if err != nil {
return res, err
}
res.AccountID = accountDescr.ID
return res, err
}
// GetAccount
type GetAccountParams struct {
Username string `json:"username"`
AccountID string `json:"accountId"`
}
type GetAccountResult struct {
Account *descr.AccountShort `json:"account"`
}
func (oper *Operator) GetAccount(ctx context.Context, operatorID string, params *GetAccountParams) (*GetAccountResult, error) {
var err error
res := &GetAccountResult{}
if params.Username == "" && params.AccountID == "" {
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
var accountDescr *descr.Account
var accountExists bool
switch {
case params.AccountID != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
return res, err
}
case params.Username != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with name %s dont exists", params.Username)
return res, err
}
default:
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
if accountDescr == nil {
err := fmt.Errorf("Null account desriptor")
return res, err
}
accountShort := &descr.AccountShort{
ID: accountDescr.ID,
Username: accountDescr.Username,
CreatedAt: accountDescr.CreatedAt,
UpdatedAt: accountDescr.UpdatedAt,
CreatedBy: accountDescr.CreatedBy,
UpdatedBy: accountDescr.UpdatedBy,
Disabled: accountDescr.Disabled,
Grants: make([]descr.Grant, 0),
}
grantDescrs, err := oper.mdb.ListGrantsByAccountID(ctx, accountDescr.ID)
if err != nil {
return res, err
}
accountShort.Grants = grantDescrs
res.Account = accountShort
return res, err
}
type UpdateAccountParams struct {
Username string `json:"username"`
AccountID string `json:"accountId"`
NewUsername string `json:"newUsername"`
NewPassword string `json:"newPassword"`
Disabled bool `json:"disabled"`
}
type UpdateAccountResult struct{}
func (oper *Operator) UpdateAccount(ctx context.Context, operatorID string, params *UpdateAccountParams) (*UpdateAccountResult, error) {
var err error
res := &UpdateAccountResult{}
if params.Username == "" && params.AccountID == "" {
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
var accountDescr *descr.Account
var accountExists bool
switch {
case params.AccountID != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
return res, err
}
case params.Username != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with name %s dont exists", params.Username)
return res, err
}
default:
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
if accountDescr == nil {
err := fmt.Errorf("Null account desriptor")
return res, err
}
now := auxtool.TimeNow()
if params.NewUsername != "" {
accountDescr.UpdatedAt = now
accountDescr.Username = params.NewUsername
}
if params.NewPassword != "" {
accountDescr.UpdatedAt = now
passhash := auxpwd.MakeSHA256Hash([]byte(params.NewPassword))
accountDescr.Passhash = passhash
}
if params.Disabled != accountDescr.Disabled {
accountDescr.UpdatedAt = now
accountDescr.Disabled = params.Disabled
}
err = oper.mdb.UpdateAccountByID(ctx, accountDescr.ID, accountDescr)
if err != nil {
return res, err
}
return res, err
}
type DeleteAccountParams struct {
Username string `json:"username"`
AccountID string `json:"accountId"`
}
type DeleteAccountResult struct{}
func (oper *Operator) DeleteAccount(ctx context.Context, operatorID string, params *DeleteAccountParams) (*DeleteAccountResult, error) {
var err error
res := &DeleteAccountResult{}
if params.Username == "" && params.AccountID == "" {
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
var accountDescr *descr.Account
var accountExists bool
switch {
case params.AccountID != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
return res, err
}
case params.Username != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with name %s dont exists", params.Username)
return res, err
}
default:
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
if accountDescr == nil {
err := fmt.Errorf("Null account desriptor")
return res, err
}
err = oper.mdb.DeleteAllGrantsForAccountID(ctx, accountDescr.ID)
if err != nil {
return res, err
}
err = oper.mdb.DeleteAccountByID(ctx, accountDescr.ID)
if err != nil {
return res, err
}
return res, err
}
type ListAccountsParams struct{}
type ListAccountsResult struct {
Accounts []descr.AccountShort `json:"accounts"`
}
func (oper *Operator) ListAccounts(ctx context.Context, params *ListAccountsParams) (*ListAccountsResult, error) {
var err error
res := &ListAccountsResult{}
accountDescrs, err := oper.mdb.ReducedListAccounts(ctx)
if err != nil {
return res, err
}
for _, accountDescr := range accountDescrs {
accountShort := descr.AccountShort{
ID: accountDescr.ID,
Username: accountDescr.Username,
Disabled: accountDescr.Disabled,
CreatedAt: accountDescr.CreatedAt,
UpdatedAt: accountDescr.UpdatedAt,
CreatedBy: accountDescr.CreatedBy,
UpdatedBy: accountDescr.UpdatedBy,
Grants: make([]descr.Grant, 0),
}
grantDescrs, err := oper.mdb.ListGrantsByAccountID(ctx, accountDescr.ID)
if err != nil {
return res, err
}
accountShort.Grants = grantDescrs
res.Accounts = append(res.Accounts, accountShort)
}
return res, err
}
-254
View File
@@ -1,254 +0,0 @@
package operator
import (
"context"
"fmt"
"regexp"
"mstore/pkg/auxtool"
"mstore/pkg/auxuuid"
"mstore/pkg/descr"
)
// CreateGrant
type CreateGrantParams struct {
AccountID string `json:"accountID"`
Username string `json:"username"`
Right string `json:"operation"`
Pattern string `json:"pattern"`
}
type CreateGrantResult struct {
GrantID string `json:"grantId"`
}
func (oper *Operator) CreateGrant(ctx context.Context, operatorID string, params *CreateGrantParams) (*CreateGrantResult, error) {
var err error
res := &CreateGrantResult{}
if params.AccountID == "" {
err := fmt.Errorf("Empty accountId parameters")
return res, err
}
if params.Right == "" {
err := fmt.Errorf("Empty operation parameter")
return res, err
}
if params.Pattern == "" {
err := fmt.Errorf("Empty pattern parameter")
return res, err
}
_, err = regexp.Compile(params.Pattern)
if err != nil {
err := fmt.Errorf("Cannot compile regexp %s: %v", err)
return res, err
}
var accountDescr *descr.Account
var accountExists bool
switch {
case params.AccountID != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
return res, err
}
case params.Username != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with name %s dont exists", params.Username)
return res, err
}
default:
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
grantExists, _, err := oper.mdb.GetGrantByAccoundIDRightPattern(ctx, params.AccountID, params.Right, params.Pattern)
if err != nil {
return res, err
}
if grantExists {
err := fmt.Errorf("Grant with this right already exists")
return res, err
}
oper.logg.Debugf("Call CreateGrant")
now := auxtool.TimeNow()
grantDescr := &descr.Grant{
ID: auxuuid.NewUUID(),
AccountID: accountDescr.ID,
Right: params.Right,
Pattern: params.Pattern,
CreatedAt: now,
UpdatedAt: now,
CreatedBy: operatorID,
UpdatedBy: operatorID,
}
err = oper.mdb.InsertGrant(ctx, grantDescr)
if err != nil {
return res, err
}
res.GrantID = grantDescr.ID
return res, err
}
// UpdateGrant
type UpdateGrantParams struct {
GrantID string
NewPattern string
}
type UpdateGrantResult struct{}
func (oper *Operator) UpdateGrant(ctx context.Context, operatorID string, params *UpdateGrantParams) (*UpdateGrantResult, error) {
var err error
res := &UpdateGrantResult{}
if params.NewPattern == "" {
err := fmt.Errorf("Empty newPattern parameter")
return res, err
}
if params.GrantID == "" {
err := fmt.Errorf("Empty grantId parameter")
return res, err
}
var grantDescr *descr.Grant
var grantExists bool
grantExists, grantDescr, err = oper.mdb.GetGrantByID(ctx, params.GrantID)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Grant with ID %s dont exists", params.GrantID)
return res, err
}
now := auxtool.TimeNow()
if params.NewPattern != "" {
grantDescr.UpdatedAt = now
grantDescr.UpdatedBy = operatorID
grantDescr.Pattern = params.NewPattern
}
err = oper.mdb.UpdateGrantByID(ctx, grantDescr.ID, grantDescr)
if err != nil {
return res, err
}
return res, err
}
// DeleteGrant
type DeleteGrantParams struct {
GrantID string `json:"grantId"`
}
type DeleteGrantResult struct{}
func (oper *Operator) DeleteGrant(ctx context.Context, operatorID string, params *DeleteGrantParams) (*DeleteGrantResult, error) {
var err error
res := &DeleteGrantResult{}
if params.GrantID == "" {
err := fmt.Errorf("Empty grantId parameter")
return res, err
}
var grantDescr *descr.Grant
var grantExists bool
grantExists, grantDescr, err = oper.mdb.GetGrantByID(ctx, params.GrantID)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Grant with ID %s dont exists", params.GrantID)
return res, err
}
err = oper.mdb.DeleteGrantByID(ctx, grantDescr.ID)
if err != nil {
return res, err
}
return res, err
}
// ListGrants
type ListGrantsParams struct {
Username string
AccountID string
}
type ListGrantsResult struct {
Grants []descr.Grant `json:"grants"`
}
func (oper *Operator) ListGrants(ctx context.Context, operatorID string, params *ListGrantsParams) (*ListGrantsResult, error) {
var err error
res := &ListGrantsResult{
Grants: make([]descr.Grant, 0),
}
var accountDescr *descr.Account
var accountExists bool
switch {
case params.AccountID != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
return res, err
}
case params.Username != "":
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
if err != nil {
return res, err
}
if !accountExists {
err := fmt.Errorf("Account with name %s dont exists", params.Username)
return res, err
}
default:
err := fmt.Errorf("Empty username and accountId parameter")
return res, err
}
accountID := accountDescr.ID
grantDescrs, err := oper.mdb.ListGrantsByAccountID(ctx, accountID)
if err != nil {
return res, err
}
res.Grants = grantDescrs
return res, err
}
// Get Grants
type GetGrantParams struct {
GrantID string `json:"grantId"`
}
type GetGrantResult struct {
Grant *descr.Grant `json:"grant"`
}
func (oper *Operator) GetGrant(ctx context.Context, operatorID string, params *GetGrantParams) (*GetGrantResult, error) {
var err error
res := &GetGrantResult{}
if params.GrantID == "" {
err := fmt.Errorf("Empty grantId parameter")
return res, err
}
var grantDescr *descr.Grant
var grantExists bool
grantExists, grantDescr, err = oper.mdb.GetGrantByID(ctx, params.GrantID)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Grant with ID %s dont exists", params.GrantID)
return res, err
}
res.Grant = grantDescr
return res, err
}
+1 -1
View File
@@ -15,7 +15,7 @@ import (
"encoding/json" "encoding/json"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
) )
+36 -8
View File
@@ -25,18 +25,23 @@ import (
"mstore/app/handler" "mstore/app/handler"
"mstore/app/logger" "mstore/app/logger"
"mstore/app/maindb" "mstore/app/maindb"
"mstore/app/operator"
"mstore/app/service" "mstore/app/service"
"mstore/app/storage" "mstore/app/storage"
"mstore/pkg/auxtool" "mstore/pkg/auxtool"
"mstore/pkg/descr" "mstore/pkg/descr"
"mstore/app/accoper"
"mstore/app/fileoper"
"mstore/app/imageoper"
yaml "go.yaml.in/yaml/v4" yaml "go.yaml.in/yaml/v4"
) )
type Server struct { type Server struct {
conf *config.Config conf *config.Config
oper *operator.Operator fiop *fileoper.Operator
acop *accoper.Operator
imop *imageoper.Operator
svc *service.Service svc *service.Service
mdb *maindb.Database mdb *maindb.Database
hand *handler.Handler hand *handler.Handler
@@ -248,21 +253,44 @@ func (srv *Server) Build() error {
store := storage.NewStorage(datadir) store := storage.NewStorage(datadir)
srv.stor = store srv.stor = store
// Creating operator // Creating account operator
srv.logg.Infof("Creating operator") srv.logg.Infof("Creating account operator")
operatorParams := &operator.OperatorParams{ accoperParams := &accoper.OperatorParams{
MainDB: srv.mdb, MainDB: srv.mdb,
Store: srv.stor, Store: srv.stor,
} }
srv.oper, err = operator.NewOperator(operatorParams) srv.acop, err = accoper.NewOperator(accoperParams)
if err != nil { if err != nil {
return err return err
} }
// Creating file operator
srv.logg.Infof("Creating file operator")
fileoperParams := &fileoper.OperatorParams{
MainDB: srv.mdb,
Store: srv.stor,
}
srv.fiop, err = fileoper.NewOperator(fileoperParams)
if err != nil {
return err
}
// Creating operator
srv.logg.Infof("Creating operator")
imageoperParams := &imageoper.OperatorParams{
MainDB: srv.mdb,
Store: srv.stor,
}
srv.imop, err = imageoper.NewOperator(imageoperParams)
if err != nil {
return err
}
// Creating handler // Creating handler
srv.logg.Infof("Creating handler") srv.logg.Infof("Creating handler")
handlerParams := &handler.HandlerParams{ handlerParams := &handler.HandlerParams{
Operator: srv.oper, MainDB: srv.mdb,
MainDB: srv.mdb, FileOper: srv.fiop,
AccOper: srv.acop,
ImageOper: srv.imop,
} }
srv.hand, err = handler.NewHandler(handlerParams) srv.hand, err = handler.NewHandler(handlerParams)
if err != nil { if err != nil {
+2 -2
View File
@@ -54,8 +54,8 @@ func (util *FileUtil) deleteCollection(common *CommonFileParams, params *DeleteC
} }
ref.SetUserinfo(common.Username, common.Password) ref.SetUserinfo(common.Username, common.Password)
mw := filecli.NewBasicAuthMiddleware(ref.Userinfo()) mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
ref.PathType(pathType(params.Regexp, params.Prefix)) ref.PathType(pathType(params.Regexp, params.Prefix))
ref.DryRun(params.DryRun) ref.DryRun(params.DryRun)
cli := filecli.NewClient(nil, mw) cli := filecli.NewClient(nil, mw)
list, err := cli.DeleteCollection(ctx, ref.Raw()) list, err := cli.DeleteCollection(ctx, ref.Raw())
if err != nil { if err != nil {
+7 -7
View File
@@ -68,9 +68,9 @@ func (util *FileUtil) importFiles(common *CommonFileParams, params *ImportFilesP
putErrors = append(putErrors, err) putErrors = append(putErrors, err)
return nil return nil
} }
ref.JoinResource(relpath) ref.JoinResource(relpath)
//fmt.Printf("====%s %s\n", relpath, ref.Raw()) //fmt.Printf("====%s %s\n", relpath, ref.Raw())
//return nil //return nil
file, err := os.OpenFile(walkpath, os.O_RDONLY, 0) file, err := os.OpenFile(walkpath, os.O_RDONLY, 0)
if err != nil { if err != nil {
putErrors = append(putErrors, err) putErrors = append(putErrors, err)
@@ -100,10 +100,10 @@ func (util *FileUtil) importFiles(common *CommonFileParams, params *ImportFilesP
} }
return nil return nil
} }
err = filepath.Walk(params.Source, walcFunc) err = filepath.Walk(params.Source, walcFunc)
if err != nil { if err != nil {
return res, err return res, err
} }
for _, item := range putErrors { for _, item := range putErrors {
err = errors.Join(err, item) err = errors.Join(err, item)
+1 -1
View File
@@ -49,7 +49,7 @@ func (util *FileUtil) listCollections(common *CommonFileParams, params *ListColl
return res, err return res, err
} }
ref.SetUserinfo(common.Username, common.Password) ref.SetUserinfo(common.Username, common.Password)
ref.PathType(pathType(params.Regexp, params.Prefix)) ref.PathType(pathType(params.Regexp, params.Prefix))
mw := filecli.NewBasicAuthMiddleware(ref.Userinfo()) mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
cli := filecli.NewClient(nil, mw) cli := filecli.NewClient(nil, mw)
list, err := cli.ListCollections(ctx, ref.Raw()) list, err := cli.ListCollections(ctx, ref.Raw())
+11 -11
View File
@@ -12,8 +12,8 @@ package filecmd
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"time" "time"
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -50,7 +50,7 @@ func (util *FileUtil) listFiles(common *CommonFileParams, params *ListFilesParam
return res, err return res, err
} }
ref.SetUserinfo(common.Username, common.Password) ref.SetUserinfo(common.Username, common.Password)
ref.PathType(pathType(params.Regexp, params.Prefix)) ref.PathType(pathType(params.Regexp, params.Prefix))
mw := filecli.NewBasicAuthMiddleware(ref.Userinfo()) mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
cli := filecli.NewClient(nil, mw) cli := filecli.NewClient(nil, mw)
@@ -58,7 +58,7 @@ func (util *FileUtil) listFiles(common *CommonFileParams, params *ListFilesParam
if err != nil { if err != nil {
return res, err return res, err
} }
fmt.Printf("====%s\n", list) fmt.Printf("====%s\n", list)
files := descr.NewFiles() files := descr.NewFiles()
err = json.Unmarshal(list, files.ArrayPtr()) err = json.Unmarshal(list, files.ArrayPtr())
if err != nil { if err != nil {
@@ -73,12 +73,12 @@ func (util *FileUtil) listFiles(common *CommonFileParams, params *ListFilesParam
} }
func pathType(regex, prefix bool) string { func pathType(regex, prefix bool) string {
switch { switch {
case regex: case regex:
return filecli.PathTypeRegexp return filecli.PathTypeRegexp
case prefix: case prefix:
return filecli.PathTypePrefix return filecli.PathTypePrefix
default: default:
} }
return filecli.PathTypeIdentic return filecli.PathTypeIdentic
} }
-1
View File
@@ -26,7 +26,6 @@ import (
const ( const (
indexMediaType = "application/vnd.oci.image.index.v1+json" indexMediaType = "application/vnd.oci.image.index.v1+json"
manifestMediaType = "application/vnd.oci.image.manifest.v1+json" manifestMediaType = "application/vnd.oci.image.manifest.v1+json"
) )
func (cli *Client) ImageManifest(ctx context.Context, imagepath string) (any, error) { func (cli *Client) ImageManifest(ctx context.Context, imagepath string) (any, error) {
+16 -21
View File
@@ -10,7 +10,7 @@
package descr package descr
import ( import (
"path" "path"
) )
type File struct { type File struct {
@@ -26,43 +26,38 @@ type File struct {
UpdatedBy string `db:"updated_by" json:"updatedBy,omitempty" yaml:"updatedBy,omitempty"` UpdatedBy string `db:"updated_by" json:"updatedBy,omitempty" yaml:"updatedBy,omitempty"`
} }
type Files struct { type Files struct {
files []File files []File
} }
func NewFiles() *Files { func NewFiles() *Files {
return &Files{ return &Files{
files: make([]File, 0), files: make([]File, 0),
} }
} }
func xxxNewFiles(files []File) *Files { func xxxNewFiles(files []File) *Files {
return &Files{ return &Files{
files: files, files: files,
} }
} }
func (fi *Files) Set(files []File) { func (fi *Files) Set(files []File) {
fi.files = files fi.files = files
} }
func (fi *Files) ArrayPtr() *[]File { func (fi *Files) ArrayPtr() *[]File {
return &fi.files return &fi.files
} }
func (fi *Files) Array() []File { func (fi *Files) Array() []File {
return fi.files return fi.files
} }
func (fi *Files) List() []string { func (fi *Files) List() []string {
list := make([]string, 0) list := make([]string, 0)
for _, file := range fi.files { for _, file := range fi.files {
list = append(list, path.Join(file.Collection, file.Name)) list = append(list, path.Join(file.Collection, file.Name))
} }
return list return list
} }
+7 -9
View File
@@ -15,9 +15,9 @@ func NewClient(transport http.RoundTripper, mwFuncs ...MiddlewareFunc) *Client {
if transport == nil { if transport == nil {
transport = NewDefaultTransport() transport = NewDefaultTransport()
} }
for _, mwFunc := range mwFuncs { for _, mwFunc := range mwFuncs {
transport = mwFunc(transport) transport = mwFunc(transport)
} }
httpClient := &http.Client{ httpClient := &http.Client{
Transport: transport, Transport: transport,
} }
@@ -38,7 +38,6 @@ func (cli *Client) UseMiddleware(mwFunc MiddlewareFunc) {
cli.httpClient.Transport = mwFunc(cli.httpClient.Transport) cli.httpClient.Transport = mwFunc(cli.httpClient.Transport)
} }
// BasicAuthMiddleware // BasicAuthMiddleware
func NewBasicAuthMiddleware(user, pass string) MiddlewareFunc { func NewBasicAuthMiddleware(user, pass string) MiddlewareFunc {
return func(next http.RoundTripper) http.RoundTripper { return func(next http.RoundTripper) http.RoundTripper {
@@ -60,10 +59,10 @@ func newBasicAuthMW(next http.RoundTripper, user, pass string) *BasicAuthMW {
} }
func (tran BasicAuthMW) RoundTrip(req *http.Request) (*http.Response, error) { func (tran BasicAuthMW) RoundTrip(req *http.Request) (*http.Response, error) {
if tran.user != "" && tran.pass != "" { if tran.user != "" && tran.pass != "" {
pair := base64.StdEncoding.EncodeToString([]byte(tran.user + ":" + tran.pass)) pair := base64.StdEncoding.EncodeToString([]byte(tran.user + ":" + tran.pass))
req.Header.Set("Authorization", "Basic "+pair) req.Header.Set("Authorization", "Basic "+pair)
} }
return tran.next.RoundTrip(req) return tran.next.RoundTrip(req)
} }
@@ -110,7 +109,6 @@ func (wrap *DefaultTransport) RoundTrip(req *http.Request) (*http.Response, erro
return wrap.transport.RoundTrip(req) return wrap.transport.RoundTrip(req)
} }
// ExampleMiddleware // ExampleMiddleware
func NewExampleMiddleware() MiddlewareFunc { func NewExampleMiddleware() MiddlewareFunc {
return func(next http.RoundTripper) http.RoundTripper { return func(next http.RoundTripper) http.RoundTripper {
+1 -1
View File
@@ -11,7 +11,7 @@ func (cli *Client) FileInfo(ctx context.Context, rawpath string) (bool, int64, s
var err error var err error
var exist bool var exist bool
var size int64 var size int64
var digest string var digest string
ref, err := ParsePath(rawpath) ref, err := ParsePath(rawpath)
if err != nil { if err != nil {
+12 -12
View File
@@ -3,8 +3,8 @@ package filecli
import ( import (
"net/url" "net/url"
"path" "path"
"strconv"
"strings" "strings"
"strconv"
) )
const ( const (
@@ -17,13 +17,13 @@ type Repository struct {
urlobj *url.URL urlobj *url.URL
user, pass string user, pass string
resource string resource string
values url.Values values url.Values
} }
func ParsePath(rawpath string) (*Repository, error) { func ParsePath(rawpath string) (*Repository, error) {
repo := &Repository{ repo := &Repository{
values: url.Values{}, values: url.Values{},
} }
if !strings.Contains(rawpath, "://") { if !strings.Contains(rawpath, "://") {
rawpath = "https://" + rawpath rawpath = "https://" + rawpath
} }
@@ -39,17 +39,17 @@ func ParsePath(rawpath string) (*Repository, error) {
repo.resource = path.Join("/", urlobj.Path) repo.resource = path.Join("/", urlobj.Path)
urlobj.Path = "/" urlobj.Path = "/"
repo.urlobj = urlobj repo.urlobj = urlobj
repo.values = urlobj.Query() repo.values = urlobj.Query()
return repo, err return repo, err
} }
func (repo *Repository) Raw() string { func (repo *Repository) Raw() string {
res := path.Join(repo.urlobj.Host, repo.resource) res := path.Join(repo.urlobj.Host, repo.resource)
query := repo.values.Encode() query := repo.values.Encode()
if query != "" { if query != "" {
return res + "?" + query return res + "?" + query
} }
return res return res
} }
func (repo *Repository) SetResource(resource string) { func (repo *Repository) SetResource(resource string) {
@@ -61,11 +61,11 @@ func (repo *Repository) JoinResource(resource string) {
} }
func (repo *Repository) PathType(typ string) { func (repo *Repository) PathType(typ string) {
repo.values.Set("pathType", typ) repo.values.Set("pathType", typ)
} }
func (repo *Repository) DryRun(yesno bool) { func (repo *Repository) DryRun(yesno bool) {
repo.values.Set("dryRun", strconv.FormatBool(yesno)) repo.values.Set("dryRun", strconv.FormatBool(yesno))
} }
func (repo *Repository) File() string { func (repo *Repository) File() string {
+4 -4
View File
@@ -87,10 +87,10 @@ func newBasicAuthMW(next http.RoundTripper, user, pass string) *BasicAuthMW {
} }
func (tran BasicAuthMW) RoundTrip(req *http.Request) (*http.Response, error) { func (tran BasicAuthMW) RoundTrip(req *http.Request) (*http.Response, error) {
if tran.user != "" && tran.pass != "" { if tran.user != "" && tran.pass != "" {
pair := base64.StdEncoding.EncodeToString([]byte(tran.user + ":" + tran.pass)) pair := base64.StdEncoding.EncodeToString([]byte(tran.user + ":" + tran.pass))
req.Header.Set("Authorization", "Basic "+pair) req.Header.Set("Authorization", "Basic "+pair)
} }
return tran.next.RoundTrip(req) return tran.next.RoundTrip(req)
} }
+2 -2
View File
@@ -1,6 +1,6 @@
package repocli package repocli
const ( const (
//MediaTypeDDMLv2 = "application/vnd.docker.distribution.manifest.list.v2+json" // MediaTypeDDMLv2 = "application/vnd.docker.distribution.manifest.list.v2+json"
//MediaTypeDDMv2 = "application/vnd.docker.distribution.manifest.v2+json" // MediaTypeDDMv2 = "application/vnd.docker.distribution.manifest.v2+json"
) )
+83 -83
View File
@@ -15,14 +15,14 @@ import (
//"math/rand" //"math/rand"
//"os" //"os"
//"path/filepath" //"path/filepath"
"bytes"
"sync" "sync"
"testing" "testing"
"time" "time"
"bytes"
"mstore/app/server" "mstore/app/server"
"mstore/pkg/client" "mstore/pkg/client"
"mstore/pkg/filecli" "mstore/pkg/filecli"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -79,114 +79,114 @@ func TestFileLife(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.True(t, helloRes) require.True(t, helloRes)
} }
fileaddr := srvaddr+"/foo2/bare.bin" fileaddr := srvaddr + "/foo2/bare.bin"
filedata := []byte("Hello, World") filedata := []byte("Hello, World")
filesize := int64(len(filedata)) filesize := int64(len(filedata))
user, pass := "mstore", "mstore" user, pass := "mstore", "mstore"
diraddr := srvaddr+"/foo" diraddr := srvaddr + "/foo"
{ {
// PutFile // PutFile
file := bytes.NewReader(filedata) file := bytes.NewReader(filedata)
size := int64(len(filedata)) size := int64(len(filedata))
fmt.Printf("=== PutFile ===\n") fmt.Printf("=== PutFile ===\n")
timeout := 10 * time.Second timeout := 10 * time.Second
ctx, _ := context.WithTimeout(context.Background(), timeout) ctx, _ := context.WithTimeout(context.Background(), timeout)
ref, err := filecli.ParsePath(fileaddr) ref, err := filecli.ParsePath(fileaddr)
require.NoError(t, err) require.NoError(t, err)
fmt.Printf("Raw: %s\n", ref.Raw()) fmt.Printf("Raw: %s\n", ref.Raw())
ref.SetUserinfo(user, pass) ref.SetUserinfo(user, pass)
mw := filecli.NewBasicAuthMiddleware(ref.Userinfo()) mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
cli := filecli.NewClient(nil, mw) cli := filecli.NewClient(nil, mw)
err = cli.PutFile(ctx, ref.Raw(), file, size) err = cli.PutFile(ctx, ref.Raw(), file, size)
require.NoError(t, err) require.NoError(t, err)
} }
{ {
// GetFile // GetFile
file := bytes.NewBuffer(nil) file := bytes.NewBuffer(nil)
fmt.Printf("=== GetFile ===\n") fmt.Printf("=== GetFile ===\n")
timeout := 10 * time.Second timeout := 10 * time.Second
ctx, _ := context.WithTimeout(context.Background(), timeout) ctx, _ := context.WithTimeout(context.Background(), timeout)
ref, err := filecli.ParsePath(fileaddr) ref, err := filecli.ParsePath(fileaddr)
require.NoError(t, err) require.NoError(t, err)
fmt.Printf("Raw: %s\n", ref.Raw()) fmt.Printf("Raw: %s\n", ref.Raw())
ref.SetUserinfo(user, pass) ref.SetUserinfo(user, pass)
mw := filecli.NewBasicAuthMiddleware(ref.Userinfo()) mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
cli := filecli.NewClient(nil, mw) cli := filecli.NewClient(nil, mw)
exist, err := cli.GetFile(ctx, ref.Raw(), file) exist, err := cli.GetFile(ctx, ref.Raw(), file)
require.NoError(t, err) require.NoError(t, err)
require.True(t, exist) require.True(t, exist)
} }
{ {
// FileInfo // FileInfo
fmt.Printf("=== FileInfo ===\n") fmt.Printf("=== FileInfo ===\n")
timeout := 10 * time.Second timeout := 10 * time.Second
ctx, _ := context.WithTimeout(context.Background(), timeout) ctx, _ := context.WithTimeout(context.Background(), timeout)
ref, err := filecli.ParsePath(fileaddr) ref, err := filecli.ParsePath(fileaddr)
require.NoError(t, err) require.NoError(t, err)
fmt.Printf("Raw: %s\n", ref.Raw()) fmt.Printf("Raw: %s\n", ref.Raw())
ref.SetUserinfo(user, pass) ref.SetUserinfo(user, pass)
mw := filecli.NewBasicAuthMiddleware(ref.Userinfo()) mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
cli := filecli.NewClient(nil, mw) cli := filecli.NewClient(nil, mw)
exist, size, digest, err := cli.FileInfo(ctx, ref.Raw()) exist, size, digest, err := cli.FileInfo(ctx, ref.Raw())
require.NoError(t, err) require.NoError(t, err)
require.True(t, exist) require.True(t, exist)
require.Equal(t, size, filesize) require.Equal(t, size, filesize)
fmt.Printf("Digest: %s\n", digest) fmt.Printf("Digest: %s\n", digest)
} }
{ {
// FileList // FileList
fmt.Printf("=== FileList ===\n") fmt.Printf("=== FileList ===\n")
timeout := 10 * time.Second timeout := 10 * time.Second
ctx, _ := context.WithTimeout(context.Background(), timeout) ctx, _ := context.WithTimeout(context.Background(), timeout)
ref, err := filecli.ParsePath(diraddr) ref, err := filecli.ParsePath(diraddr)
require.NoError(t, err) require.NoError(t, err)
ref.SetUserinfo(user, pass) ref.SetUserinfo(user, pass)
ref.PathType(filecli.PathTypePrefix) ref.PathType(filecli.PathTypePrefix)
fmt.Printf("Raw: %s\n", ref.Raw()) fmt.Printf("Raw: %s\n", ref.Raw())
mw := filecli.NewBasicAuthMiddleware(ref.Userinfo()) mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
cli := filecli.NewClient(nil, mw) cli := filecli.NewClient(nil, mw)
list, err := cli.ListFiles(ctx, ref.Raw()) list, err := cli.ListFiles(ctx, ref.Raw())
require.NoError(t, err) require.NoError(t, err)
fmt.Printf("List: %s\n", list) fmt.Printf("List: %s\n", list)
} }
{ {
// DeleteFile // DeleteFile
fmt.Printf("=== FileList ===\n") fmt.Printf("=== FileList ===\n")
timeout := 10 * time.Second timeout := 10 * time.Second
ctx, _ := context.WithTimeout(context.Background(), timeout) ctx, _ := context.WithTimeout(context.Background(), timeout)
ref, err := filecli.ParsePath(fileaddr) ref, err := filecli.ParsePath(fileaddr)
require.NoError(t, err) require.NoError(t, err)
ref.SetUserinfo(user, pass) ref.SetUserinfo(user, pass)
//ref.PathType(filecli.PathTypePrefix) //ref.PathType(filecli.PathTypePrefix)
fmt.Printf("Raw: %s\n", ref.Raw()) fmt.Printf("Raw: %s\n", ref.Raw())
mw := filecli.NewBasicAuthMiddleware(ref.Userinfo()) mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
cli := filecli.NewClient(nil, mw) cli := filecli.NewClient(nil, mw)
exist, err := cli.DeleteFile(ctx, ref.Raw()) exist, err := cli.DeleteFile(ctx, ref.Raw())
require.NoError(t, err) require.NoError(t, err)
fmt.Printf("Exist: %v\n", exist) fmt.Printf("Exist: %v\n", exist)
require.True(t, exist) require.True(t, exist)
} }
{ {
// DeleteFile // DeleteFile
fmt.Printf("=== FileList ===\n") fmt.Printf("=== FileList ===\n")
timeout := 10 * time.Second timeout := 10 * time.Second
ctx, _ := context.WithTimeout(context.Background(), timeout) ctx, _ := context.WithTimeout(context.Background(), timeout)
ref, err := filecli.ParsePath(fileaddr) ref, err := filecli.ParsePath(fileaddr)
require.NoError(t, err) require.NoError(t, err)
ref.SetUserinfo(user, pass) ref.SetUserinfo(user, pass)
//ref.PathType(filecli.PathTypePrefix) //ref.PathType(filecli.PathTypePrefix)
fmt.Printf("Raw: %s\n", ref.Raw()) fmt.Printf("Raw: %s\n", ref.Raw())
mw := filecli.NewBasicAuthMiddleware(ref.Userinfo()) mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
cli := filecli.NewClient(nil, mw) cli := filecli.NewClient(nil, mw)
exist, err := cli.DeleteFile(ctx, ref.Raw()) exist, err := cli.DeleteFile(ctx, ref.Raw())
require.NoError(t, err) require.NoError(t, err)
fmt.Printf("Exist: %v\n", exist) fmt.Printf("Exist: %v\n", exist)
require.False(t, exist) require.False(t, exist)
} }
} }