diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/gotosocial/action/server/server.go | 47 | ||||
-rw-r--r-- | cmd/process-emoji/main.go | 122 | ||||
-rw-r--r-- | cmd/process-media/main.go | 124 |
3 files changed, 285 insertions, 8 deletions
diff --git a/cmd/gotosocial/action/server/server.go b/cmd/gotosocial/action/server/server.go index 14db67795..828b9c875 100644 --- a/cmd/gotosocial/action/server/server.go +++ b/cmd/gotosocial/action/server/server.go @@ -24,12 +24,14 @@ import ( "net/http" "os" "os/signal" + "runtime" "strings" "syscall" "time" "github.com/KimMachineGun/automemlimit/memlimit" "github.com/gin-gonic/gin" + "github.com/ncruces/go-sqlite3" "github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action" "github.com/superseriousbusiness/gotosocial/internal/api" apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" @@ -37,6 +39,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/filter/spam" "github.com/superseriousbusiness/gotosocial/internal/filter/visibility" "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/media/ffmpeg" "github.com/superseriousbusiness/gotosocial/internal/messages" "github.com/superseriousbusiness/gotosocial/internal/metrics" "github.com/superseriousbusiness/gotosocial/internal/middleware" @@ -66,14 +69,15 @@ import ( // Start creates and starts a gotosocial server var Start action.GTSAction = func(ctx context.Context) error { - if _, err := maxprocs.Set(maxprocs.Logger(nil)); err != nil { - log.Warnf(ctx, "could not set CPU limits from cgroup: %s", err) - } - - if _, err := memlimit.SetGoMemLimitWithOpts(); err != nil { - if !strings.Contains(err.Error(), "cgroup mountpoint does not exist") { - log.Warnf(ctx, "could not set Memory limits from cgroup: %s", err) - } + // Set GOMAXPROCS / GOMEMLIMIT + // to match container limits. + setLimits(ctx) + + // Compile WASM modules ahead of first use + // to prevent unexpected initial slowdowns. + log.Info(ctx, "precompiling WebAssembly") + if err := precompileWASM(ctx); err != nil { + return err } var ( @@ -429,3 +433,30 @@ var Start action.GTSAction = func(ctx context.Context) error { return nil } + +func setLimits(ctx context.Context) { + if _, err := maxprocs.Set(maxprocs.Logger(nil)); err != nil { + log.Warnf(ctx, "could not set CPU limits from cgroup: %s", err) + } + + if _, err := memlimit.SetGoMemLimitWithOpts(); err != nil { + if !strings.Contains(err.Error(), "cgroup mountpoint does not exist") { + log.Warnf(ctx, "could not set Memory limits from cgroup: %s", err) + } + } +} + +func precompileWASM(ctx context.Context) error { + // TODO: make max number instances configurable + maxprocs := runtime.GOMAXPROCS(0) + if err := sqlite3.Initialize(); err != nil { + return gtserror.Newf("error compiling sqlite3: %w", err) + } + if err := ffmpeg.InitFfmpeg(ctx, maxprocs); err != nil { + return gtserror.Newf("error compiling ffmpeg: %w", err) + } + if err := ffmpeg.InitFfprobe(ctx, maxprocs); err != nil { + return gtserror.Newf("error compiling ffprobe: %w", err) + } + return nil +} diff --git a/cmd/process-emoji/main.go b/cmd/process-emoji/main.go new file mode 100644 index 000000000..62253bbdf --- /dev/null +++ b/cmd/process-emoji/main.go @@ -0,0 +1,122 @@ +// 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 main + +import ( + "context" + "io" + "os" + "os/signal" + "syscall" + + "codeberg.org/gruf/go-storage/memory" + "github.com/superseriousbusiness/gotosocial/internal/config" + "github.com/superseriousbusiness/gotosocial/internal/db/bundb" + "github.com/superseriousbusiness/gotosocial/internal/log" + "github.com/superseriousbusiness/gotosocial/internal/media" + "github.com/superseriousbusiness/gotosocial/internal/state" + "github.com/superseriousbusiness/gotosocial/internal/storage" + "github.com/superseriousbusiness/gotosocial/internal/util" +) + +func main() { + ctx := context.Background() + ctx, cncl := signal.NotifyContext(ctx, syscall.SIGTERM, syscall.SIGINT) + defer cncl() + + if len(os.Args) != 3 { + log.Panic(ctx, "Usage: go run ./cmd/process-emoji <input-file> <output-static>") + } + + var st storage.Driver + st.Storage = memory.Open(10, true) + + var state state.State + state.Storage = &st + + state.Caches.Init() + + var err error + + config.SetHost("example.com") + config.SetStorageBackend("disk") + config.SetStorageLocalBasePath("/tmp/gotosocial") + config.SetDbType("sqlite") + config.SetDbAddress(":memory:") + + state.DB, err = bundb.NewBunDBService(ctx, &state) + if err != nil { + log.Panic(ctx, err) + } + + if err := state.DB.CreateInstanceAccount(ctx); err != nil { + log.Panicf(ctx, "error creating instance account: %s", err) + } + + if err := state.DB.CreateInstanceInstance(ctx); err != nil { + log.Panicf(ctx, "error creating instance instance: %s", err) + } + + if err := state.DB.CreateInstanceApplication(ctx); err != nil { + log.Panicf(ctx, "error creating instance application: %s", err) + } + + mgr := media.NewManager(&state) + + processing, err := mgr.CreateEmoji(ctx, + "emoji", + "example.com", + func(ctx context.Context) (reader io.ReadCloser, err error) { + return os.Open(os.Args[1]) + }, + media.AdditionalEmojiInfo{ + URI: util.Ptr("example.com/emoji"), + }, + ) + if err != nil { + log.Panic(ctx, err) + } + + emoji, err := processing.Load(ctx) + if err != nil { + log.Panic(ctx, err) + } + + copyFile(ctx, &st, emoji.ImageStaticPath, os.Args[2]) +} + +func copyFile(ctx context.Context, st *storage.Driver, key string, path string) { + rc, err := st.GetStream(ctx, key) + if err != nil { + log.Panic(ctx, err) + } + defer rc.Close() + + _ = os.Remove(path) + + output, err := os.Create(path) + if err != nil { + log.Panic(ctx, err) + } + defer output.Close() + + _, err = io.Copy(output, rc) + if err != nil { + log.Panic(ctx, err) + } +} diff --git a/cmd/process-media/main.go b/cmd/process-media/main.go new file mode 100644 index 000000000..2f5a43f31 --- /dev/null +++ b/cmd/process-media/main.go @@ -0,0 +1,124 @@ +// 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 main + +import ( + "context" + "io" + "os" + "os/signal" + "syscall" + + "codeberg.org/gruf/go-storage/memory" + "github.com/superseriousbusiness/gotosocial/internal/config" + "github.com/superseriousbusiness/gotosocial/internal/db/bundb" + "github.com/superseriousbusiness/gotosocial/internal/log" + "github.com/superseriousbusiness/gotosocial/internal/media" + "github.com/superseriousbusiness/gotosocial/internal/state" + "github.com/superseriousbusiness/gotosocial/internal/storage" +) + +func main() { + ctx := context.Background() + ctx, cncl := signal.NotifyContext(ctx, syscall.SIGTERM, syscall.SIGINT) + defer cncl() + + if len(os.Args) != 4 { + log.Panic(ctx, "Usage: go run ./cmd/process-media <input-file> <output-processed> <output-thumbnail>") + } + + var st storage.Driver + st.Storage = memory.Open(10, true) + + var state state.State + state.Storage = &st + + state.Caches.Init() + + var err error + + config.SetHost("example.com") + config.SetStorageBackend("disk") + config.SetStorageLocalBasePath("/tmp/gotosocial") + config.SetDbType("sqlite") + config.SetDbAddress(":memory:") + + state.DB, err = bundb.NewBunDBService(ctx, &state) + if err != nil { + log.Panic(ctx, err) + } + + if err := state.DB.CreateInstanceAccount(ctx); err != nil { + log.Panicf(ctx, "error creating instance account: %s", err) + } + + if err := state.DB.CreateInstanceInstance(ctx); err != nil { + log.Panicf(ctx, "error creating instance instance: %s", err) + } + + if err := state.DB.CreateInstanceApplication(ctx); err != nil { + log.Panicf(ctx, "error creating instance application: %s", err) + } + + account, err := state.DB.GetInstanceAccount(ctx, "") + if err != nil { + log.Panic(ctx, err) + } + + mgr := media.NewManager(&state) + + processing, err := mgr.CreateMedia(ctx, + account.ID, + func(ctx context.Context) (reader io.ReadCloser, err error) { + return os.Open(os.Args[1]) + }, + media.AdditionalMediaInfo{}, + ) + if err != nil { + log.Panic(ctx, err) + } + + media, err := processing.Load(ctx) + if err != nil { + log.Panic(ctx, err) + } + + copyFile(ctx, &st, media.File.Path, os.Args[2]) + copyFile(ctx, &st, media.Thumbnail.Path, os.Args[3]) +} + +func copyFile(ctx context.Context, st *storage.Driver, key string, path string) { + rc, err := st.GetStream(ctx, key) + if err != nil { + log.Panic(ctx, err) + } + defer rc.Close() + + _ = os.Remove(path) + + output, err := os.Create(path) + if err != nil { + log.Panic(ctx, err) + } + defer output.Close() + + _, err = io.Copy(output, rc) + if err != nil { + log.Panic(ctx, err) + } +} |