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
@@ -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
} }
+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)
+14 -4
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
}
+35 -7
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 {
+1 -1
View File
@@ -12,8 +12,8 @@ package filecmd
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"time"
"fmt" "fmt"
"time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
-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) {
-5
View File
@@ -26,8 +26,6 @@ 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
} }
@@ -56,8 +54,6 @@ 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 {
@@ -65,4 +61,3 @@ func (fi *Files) List() []string {
} }
return list return list
} }
-2
View File
@@ -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 {
@@ -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
@@ -3,8 +3,8 @@ package filecli
import ( import (
"net/url" "net/url"
"path" "path"
"strings"
"strconv" "strconv"
"strings"
) )
const ( const (
+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"
) )
+3 -3
View File
@@ -15,10 +15,10 @@ 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"
@@ -79,11 +79,11 @@ 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)