diff options
Diffstat (limited to 'internal/processing/admin/actions.go')
-rw-r--r-- | internal/processing/admin/actions.go | 170 |
1 files changed, 0 insertions, 170 deletions
diff --git a/internal/processing/admin/actions.go b/internal/processing/admin/actions.go deleted file mode 100644 index 968e45baa..000000000 --- a/internal/processing/admin/actions.go +++ /dev/null @@ -1,170 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. - -package admin - -import ( - "context" - "slices" - "sync" - "time" - - "github.com/superseriousbusiness/gotosocial/internal/gtscontext" - "github.com/superseriousbusiness/gotosocial/internal/gtserror" - "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" - "github.com/superseriousbusiness/gotosocial/internal/log" - "github.com/superseriousbusiness/gotosocial/internal/state" -) - -func errActionConflict(action *gtsmodel.AdminAction) gtserror.WithCode { - err := gtserror.NewfAt( - 4, // Include caller's function name. - "an action (%s) is currently running (duration %s) which conflicts with the attempted action", - action.Key(), time.Since(action.CreatedAt), - ) - - const help = "wait until this action is complete and try again" - return gtserror.NewErrorConflict(err, err.Error(), help) -} - -type Actions struct { - r map[string]*gtsmodel.AdminAction - state *state.State - - // Not embedded struct, - // to shield from access - // by outside packages. - m sync.Mutex -} - -// Run runs the given admin action by executing the supplied function. -// -// Run handles locking, action insertion and updating, so you don't have to! -// -// If an action is already running which overlaps/conflicts with the -// given action, an ErrorWithCode 409 will be returned. -// -// If execution of the provided function returns errors, the errors -// will be updated on the provided admin action in the database. -func (a *Actions) Run( - ctx context.Context, - action *gtsmodel.AdminAction, - f func(context.Context) gtserror.MultiError, -) gtserror.WithCode { - actionKey := action.Key() - - // LOCK THE MAP HERE, since we're - // going to do some operations on it. - a.m.Lock() - - // Bail if an action with - // this key is already running. - running, ok := a.r[actionKey] - if ok { - a.m.Unlock() - return errActionConflict(running) - } - - // Action with this key not - // yet running, create it. - if err := a.state.DB.PutAdminAction(ctx, action); err != nil { - err = gtserror.Newf("db error putting admin action %s: %w", actionKey, err) - - // Don't store in map - // if there's an error. - a.m.Unlock() - return gtserror.NewErrorInternalError(err) - } - - // Action was inserted, - // store in map. - a.r[actionKey] = action - - // UNLOCK THE MAP HERE, since - // we're done modifying it for now. - a.m.Unlock() - - go func() { - // Use a background context with existing values. - ctx = gtscontext.WithValues(context.Background(), ctx) - - // Run the thing and collect errors. - if errs := f(ctx); errs != nil { - action.Errors = make([]string, 0, len(errs)) - for _, err := range errs { - action.Errors = append(action.Errors, err.Error()) - } - } - - // Action is no longer running: - // remove from running map. - a.m.Lock() - delete(a.r, actionKey) - a.m.Unlock() - - // Mark as completed in the db, - // storing errors for later review. - action.CompletedAt = time.Now() - if err := a.state.DB.UpdateAdminAction(ctx, action, "completed_at", "errors"); err != nil { - log.Errorf(ctx, "db error marking action %s as completed: %q", actionKey, err) - } - }() - - return nil -} - -// GetRunning sounds like a threat, but it actually just -// returns all of the currently running actions held by -// the Actions struct, ordered by ID descending. -func (a *Actions) GetRunning() []*gtsmodel.AdminAction { - a.m.Lock() - defer a.m.Unlock() - - // Assemble all currently running actions. - running := make([]*gtsmodel.AdminAction, 0, len(a.r)) - for _, action := range a.r { - running = append(running, action) - } - - // Order by ID descending (creation date). - slices.SortFunc( - running, - func(a *gtsmodel.AdminAction, b *gtsmodel.AdminAction) int { - const k = -1 - switch { - case a.ID > b.ID: - return +k - case a.ID < b.ID: - return -k - default: - return 0 - } - }, - ) - - return running -} - -// TotalRunning is a sequel to the classic -// 1972 environmental-themed science fiction -// film Silent Running, starring Bruce Dern. -func (a *Actions) TotalRunning() int { - a.m.Lock() - defer a.m.Unlock() - - return len(a.r) -} |