mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-28 11:12:25 -05:00
This disables ffmpeg / ffprobe support on platforms where the wazero compiler is not available. The slowness introduced is hard to pindown for admins (and us!), so it's easier to just return an error message linking to docs on attempted media processing. It still allows the instance to run, just erroring if anything other than a jpeg is attempted to be processed. This should hopefully make it easier for users to notice these issues. Also further locks down our wazero 'allowFiles' fs and other media code to address: https://codeberg.org/superseriousbusiness/gotosocial/issues/4408 relates to: https://codeberg.org/superseriousbusiness/gotosocial/issues/4427 also relates to issues raised in #gotosocial-help on matrix closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4408 Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4454 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
160 lines
4.3 KiB
Go
160 lines
4.3 KiB
Go
// 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/>.
|
|
|
|
//go:build !nowasmffmpeg && !nowasm
|
|
|
|
package ffmpeg
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"runtime"
|
|
"sync/atomic"
|
|
"unsafe"
|
|
|
|
"codeberg.org/gruf/go-ffmpreg/embed"
|
|
"codeberg.org/gruf/go-ffmpreg/wasm"
|
|
"github.com/tetratelabs/wazero"
|
|
"golang.org/x/sys/cpu"
|
|
)
|
|
|
|
// ffmpreg is a concurrency-safe pointer
|
|
// to our necessary WebAssembly runtime
|
|
// and compiled ffmpreg module instance.
|
|
var ffmpreg atomic.Pointer[struct {
|
|
run wazero.Runtime
|
|
mod wazero.CompiledModule
|
|
}]
|
|
|
|
// initWASM safely prepares new WebAssembly runtime
|
|
// and compiles ffmpreg module instance, if the global
|
|
// pointer has not been already. else, is a no-op.
|
|
func initWASM(ctx context.Context) error {
|
|
if ffmpreg.Load() != nil {
|
|
return nil
|
|
}
|
|
|
|
// Check at runtime whether Wazero compiler support is available,
|
|
// interpreter mode is too slow for a usable gotosocial experience.
|
|
if reason, supported := isCompilerSupported(); !supported {
|
|
return errors.New("!!! WAZERO COMPILER SUPPORT NOT AVAILABLE !!!" +
|
|
" Reason: " + reason + "." +
|
|
" Wazero in interpreter mode is too slow to use ffmpeg" +
|
|
" (this will also affect SQLite if in use)." +
|
|
" For more info and possible workarounds, please check: https://docs.gotosocial.org/en/latest/getting_started/releases/#supported-platforms")
|
|
}
|
|
|
|
// Allocate new runtime compiler config.
|
|
cfg := wazero.NewRuntimeConfigCompiler()
|
|
|
|
if dir := os.Getenv("GTS_WAZERO_COMPILATION_CACHE"); dir != "" {
|
|
// Use on-filesystem compilation cache given by env.
|
|
cache, err := wazero.NewCompilationCacheWithDir(dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Update runtime config with cache.
|
|
cfg = cfg.WithCompilationCache(cache)
|
|
}
|
|
|
|
var (
|
|
run wazero.Runtime
|
|
mod wazero.CompiledModule
|
|
err error
|
|
set bool
|
|
)
|
|
|
|
defer func() {
|
|
if err == nil && set {
|
|
// Drop binary.
|
|
embed.B = nil
|
|
return
|
|
}
|
|
|
|
// Close module.
|
|
if !isNil(mod) {
|
|
mod.Close(ctx)
|
|
}
|
|
|
|
// Close runtime.
|
|
if !isNil(run) {
|
|
run.Close(ctx)
|
|
}
|
|
}()
|
|
|
|
// Initialize new runtime from config.
|
|
run, err = wasm.NewRuntime(ctx, cfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Compile ffmpreg WebAssembly into memory.
|
|
mod, err = run.CompileModule(ctx, embed.B)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Try set global WASM runtime and module,
|
|
// or if beaten to it defer will handle close.
|
|
set = ffmpreg.CompareAndSwap(nil, &struct {
|
|
run wazero.Runtime
|
|
mod wazero.CompiledModule
|
|
}{
|
|
run: run,
|
|
mod: mod,
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
func isCompilerSupported() (string, bool) {
|
|
switch runtime.GOOS {
|
|
case "linux", "android",
|
|
"windows", "darwin",
|
|
"freebsd", "netbsd", "dragonfly",
|
|
"solaris", "illumos":
|
|
break
|
|
default:
|
|
return "unsupported OS", false
|
|
}
|
|
switch runtime.GOARCH {
|
|
case "amd64":
|
|
// NOTE: wazero in the future may decouple the
|
|
// requirement of simd (sse4_1+2) from requirements
|
|
// for compiler support in the future, but even
|
|
// still our module go-ffmpreg makes use of them.
|
|
return "amd64 x86-64-v2 required (see: https://en.wikipedia.org/wiki/X86-64-v2)",
|
|
cpu.Initialized && cpu.X86.HasSSE3 && cpu.X86.HasSSE41 && cpu.X86.HasSSE42
|
|
case "arm64":
|
|
// NOTE: this particular check may change if we
|
|
// later update go-ffmpreg to a version that makes
|
|
// use of threads, i.e. v7.x.x. in that case we would
|
|
// need to check for cpu.ARM64.HasATOMICS.
|
|
return "", true
|
|
default:
|
|
return "unsupported ARCH", false
|
|
}
|
|
}
|
|
|
|
// isNil will safely check if 'v' is nil without
|
|
// dealing with weird Go interface nil bullshit.
|
|
func isNil(i interface{}) bool {
|
|
type eface struct{ Type, Data unsafe.Pointer }
|
|
return (*eface)(unsafe.Pointer(&i)).Data == nil
|
|
}
|