mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-22 11:46:40 +00:00
Compare commits
4 commits
dafa35a311
...
4f1ffc1bfd
Author | SHA1 | Date | |
---|---|---|---|
4f1ffc1bfd | |||
45e1609377 | |||
b84637801a | |||
2cd5abfdcf |
4
go.mod
4
go.mod
|
@ -12,7 +12,7 @@ require (
|
||||||
codeberg.org/gruf/go-debug v1.3.0
|
codeberg.org/gruf/go-debug v1.3.0
|
||||||
codeberg.org/gruf/go-errors/v2 v2.3.2
|
codeberg.org/gruf/go-errors/v2 v2.3.2
|
||||||
codeberg.org/gruf/go-fastcopy v1.1.3
|
codeberg.org/gruf/go-fastcopy v1.1.3
|
||||||
codeberg.org/gruf/go-ffmpreg v0.4.2
|
codeberg.org/gruf/go-ffmpreg v0.6.0
|
||||||
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
|
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
|
||||||
codeberg.org/gruf/go-kv v1.6.5
|
codeberg.org/gruf/go-kv v1.6.5
|
||||||
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
|
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
|
||||||
|
@ -43,7 +43,7 @@ require (
|
||||||
github.com/miekg/dns v1.1.62
|
github.com/miekg/dns v1.1.62
|
||||||
github.com/minio/minio-go/v7 v7.0.80
|
github.com/minio/minio-go/v7 v7.0.80
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/ncruces/go-sqlite3 v0.20.0
|
github.com/ncruces/go-sqlite3 v0.20.2
|
||||||
github.com/oklog/ulid v1.3.1
|
github.com/oklog/ulid v1.3.1
|
||||||
github.com/prometheus/client_golang v1.20.5
|
github.com/prometheus/client_golang v1.20.5
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
|
|
8
go.sum
generated
8
go.sum
generated
|
@ -46,8 +46,8 @@ codeberg.org/gruf/go-fastcopy v1.1.3 h1:Jo9VTQjI6KYimlw25PPc7YLA3Xm+XMQhaHwKnM7x
|
||||||
codeberg.org/gruf/go-fastcopy v1.1.3/go.mod h1:GDDYR0Cnb3U/AIfGM3983V/L+GN+vuwVMvrmVABo21s=
|
codeberg.org/gruf/go-fastcopy v1.1.3/go.mod h1:GDDYR0Cnb3U/AIfGM3983V/L+GN+vuwVMvrmVABo21s=
|
||||||
codeberg.org/gruf/go-fastpath/v2 v2.0.0 h1:iAS9GZahFhyWEH0KLhFEJR+txx1ZhMXxYzu2q5Qo9c0=
|
codeberg.org/gruf/go-fastpath/v2 v2.0.0 h1:iAS9GZahFhyWEH0KLhFEJR+txx1ZhMXxYzu2q5Qo9c0=
|
||||||
codeberg.org/gruf/go-fastpath/v2 v2.0.0/go.mod h1:3pPqu5nZjpbRrOqvLyAK7puS1OfEtQvjd6342Cwz56Q=
|
codeberg.org/gruf/go-fastpath/v2 v2.0.0/go.mod h1:3pPqu5nZjpbRrOqvLyAK7puS1OfEtQvjd6342Cwz56Q=
|
||||||
codeberg.org/gruf/go-ffmpreg v0.4.2 h1:HKkPapm/PWkxsnUdjyQOGpwl5Qoa2EBrUQ09s4R4/FA=
|
codeberg.org/gruf/go-ffmpreg v0.6.0 h1:/cfUJ9bFKEoXT9LDYZy3eZ0HF60YWcO+0nGciepJKMw=
|
||||||
codeberg.org/gruf/go-ffmpreg v0.4.2/go.mod h1:Ar5nbt3tB2Wr0uoaqV3wDBNwAx+H+AB/mV7Kw7NlZTI=
|
codeberg.org/gruf/go-ffmpreg v0.6.0/go.mod h1:Ar5nbt3tB2Wr0uoaqV3wDBNwAx+H+AB/mV7Kw7NlZTI=
|
||||||
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf h1:84s/ii8N6lYlskZjHH+DG6jyia8w2mXMZlRwFn8Gs3A=
|
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf h1:84s/ii8N6lYlskZjHH+DG6jyia8w2mXMZlRwFn8Gs3A=
|
||||||
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf/go.mod h1:zZAICsp5rY7+hxnws2V0ePrWxE0Z2Z/KXcN3p/RQCfk=
|
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf/go.mod h1:zZAICsp5rY7+hxnws2V0ePrWxE0Z2Z/KXcN3p/RQCfk=
|
||||||
codeberg.org/gruf/go-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0=
|
codeberg.org/gruf/go-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0=
|
||||||
|
@ -432,8 +432,8 @@ github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
|
||||||
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/ncruces/go-sqlite3 v0.20.0 h1:/nBLvYxj7sk9S6y57nmMFvoQ/KJtGo0pNi8J80s8oJU=
|
github.com/ncruces/go-sqlite3 v0.20.2 h1:cMLIwrLZQuCWVCEOowSqlIlpzgbag3jnYVW4NM5u01M=
|
||||||
github.com/ncruces/go-sqlite3 v0.20.0/go.mod h1:yL4ZNWGsr1/8pcLfpPW1RT1WFdvyeHonrgIwwi4rvkg=
|
github.com/ncruces/go-sqlite3 v0.20.2/go.mod h1:yL4ZNWGsr1/8pcLfpPW1RT1WFdvyeHonrgIwwi4rvkg=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
|
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
|
||||||
|
|
|
@ -181,6 +181,10 @@ func ffmpeg(ctx context.Context, inpath string, outpath string, args ...string)
|
||||||
}
|
}
|
||||||
fscfg = fscfg.WithFSMount(shared, path.Dir(inpath))
|
fscfg = fscfg.WithFSMount(shared, path.Dir(inpath))
|
||||||
|
|
||||||
|
// Set anonymous module name.
|
||||||
|
modcfg = modcfg.WithName("")
|
||||||
|
|
||||||
|
// Update with prepared fs config.
|
||||||
return modcfg.WithFSConfig(fscfg)
|
return modcfg.WithFSConfig(fscfg)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -247,6 +251,10 @@ func ffprobe(ctx context.Context, filepath string) (*result, error) {
|
||||||
}
|
}
|
||||||
fscfg = fscfg.WithFSMount(in, path.Dir(filepath))
|
fscfg = fscfg.WithFSMount(in, path.Dir(filepath))
|
||||||
|
|
||||||
|
// Set anonymous module name.
|
||||||
|
modcfg = modcfg.WithName("")
|
||||||
|
|
||||||
|
// Update with prepared fs config.
|
||||||
return modcfg.WithFSConfig(fscfg)
|
return modcfg.WithFSConfig(fscfg)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"codeberg.org/gruf/go-ffmpreg/wasm"
|
"codeberg.org/gruf/go-ffmpreg/wasm"
|
||||||
)
|
)
|
||||||
|
@ -35,12 +36,25 @@
|
||||||
// prepares the runner to only allow max given concurrent running instances.
|
// prepares the runner to only allow max given concurrent running instances.
|
||||||
func InitFfmpeg(ctx context.Context, max int) error {
|
func InitFfmpeg(ctx context.Context, max int) error {
|
||||||
ffmpegRunner.Init(max)
|
ffmpegRunner.Init(max)
|
||||||
return compileFfmpeg(ctx)
|
return initWASM(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ffmpeg runs the given arguments with an instance of ffmpeg.
|
// Ffmpeg runs the given arguments with an instance of ffmpeg.
|
||||||
func Ffmpeg(ctx context.Context, args Args) (uint32, error) {
|
func Ffmpeg(ctx context.Context, args Args) (uint32, error) {
|
||||||
return ffmpegRunner.Run(ctx, func() (uint32, error) {
|
return ffmpegRunner.Run(ctx, func() (uint32, error) {
|
||||||
return wasm.Run(ctx, runtime, ffmpeg, args)
|
|
||||||
|
// Load WASM rt and module.
|
||||||
|
ffmpreg := ffmpreg.Load()
|
||||||
|
if ffmpreg == nil {
|
||||||
|
return 0, errors.New("wasm not initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call into ffmpeg.
|
||||||
|
args.Name = "ffmpeg"
|
||||||
|
return wasm.Run(ctx,
|
||||||
|
ffmpreg.run,
|
||||||
|
ffmpreg.mod,
|
||||||
|
args,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"codeberg.org/gruf/go-ffmpreg/wasm"
|
"codeberg.org/gruf/go-ffmpreg/wasm"
|
||||||
)
|
)
|
||||||
|
@ -35,12 +36,25 @@
|
||||||
// prepares the runner to only allow max given concurrent running instances.
|
// prepares the runner to only allow max given concurrent running instances.
|
||||||
func InitFfprobe(ctx context.Context, max int) error {
|
func InitFfprobe(ctx context.Context, max int) error {
|
||||||
ffprobeRunner.Init(max)
|
ffprobeRunner.Init(max)
|
||||||
return compileFfprobe(ctx)
|
return initWASM(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ffprobe runs the given arguments with an instance of ffprobe.
|
// Ffprobe runs the given arguments with an instance of ffprobe.
|
||||||
func Ffprobe(ctx context.Context, args Args) (uint32, error) {
|
func Ffprobe(ctx context.Context, args Args) (uint32, error) {
|
||||||
return ffprobeRunner.Run(ctx, func() (uint32, error) {
|
return ffprobeRunner.Run(ctx, func() (uint32, error) {
|
||||||
return wasm.Run(ctx, runtime, ffprobe, args)
|
|
||||||
|
// Load WASM rt and module.
|
||||||
|
ffmpreg := ffmpreg.Load()
|
||||||
|
if ffmpreg == nil {
|
||||||
|
return 0, errors.New("wasm not initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call into ffprobe.
|
||||||
|
args.Name = "ffprobe"
|
||||||
|
return wasm.Run(ctx,
|
||||||
|
ffmpreg.run,
|
||||||
|
ffmpreg.mod,
|
||||||
|
args,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,72 +22,27 @@
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
"sync/atomic"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
ffmpeglib "codeberg.org/gruf/go-ffmpreg/embed/ffmpeg"
|
"codeberg.org/gruf/go-ffmpreg/embed"
|
||||||
ffprobelib "codeberg.org/gruf/go-ffmpreg/embed/ffprobe"
|
|
||||||
"codeberg.org/gruf/go-ffmpreg/wasm"
|
"codeberg.org/gruf/go-ffmpreg/wasm"
|
||||||
"github.com/tetratelabs/wazero"
|
"github.com/tetratelabs/wazero"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// ffmpreg is a concurrency-safe pointer
|
||||||
// shared WASM runtime instance.
|
// to our necessary WebAssembly runtime
|
||||||
runtime wazero.Runtime
|
// and compiled ffmpreg module instance.
|
||||||
|
var ffmpreg atomic.Pointer[struct {
|
||||||
|
run wazero.Runtime
|
||||||
|
mod wazero.CompiledModule
|
||||||
|
}]
|
||||||
|
|
||||||
// ffmpeg / ffprobe compiled WASM.
|
// initWASM safely prepares new WebAssembly runtime
|
||||||
ffmpeg wazero.CompiledModule
|
// and compiles ffmpreg module instance, if the global
|
||||||
ffprobe wazero.CompiledModule
|
// pointer has not been already. else, is a no-op.
|
||||||
)
|
func initWASM(ctx context.Context) error {
|
||||||
|
if ffmpreg.Load() != nil {
|
||||||
// compileFfmpeg ensures the ffmpeg WebAssembly has been
|
|
||||||
// pre-compiled into memory. If already compiled is a no-op.
|
|
||||||
func compileFfmpeg(ctx context.Context) error {
|
|
||||||
if ffmpeg != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure runtime already initialized.
|
|
||||||
if err := initRuntime(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compile the ffmpeg WebAssembly module into memory.
|
|
||||||
cmod, err := runtime.CompileModule(ctx, ffmpeglib.B)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set module.
|
|
||||||
ffmpeg = cmod
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// compileFfprobe ensures the ffprobe WebAssembly has been
|
|
||||||
// pre-compiled into memory. If already compiled is a no-op.
|
|
||||||
func compileFfprobe(ctx context.Context) error {
|
|
||||||
if ffprobe != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure runtime already initialized.
|
|
||||||
if err := initRuntime(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compile the ffprobe WebAssembly module into memory.
|
|
||||||
cmod, err := runtime.CompileModule(ctx, ffprobelib.B)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set module.
|
|
||||||
ffprobe = cmod
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// initRuntime initializes the global wazero.Runtime,
|
|
||||||
// if already initialized this function is a no-op.
|
|
||||||
func initRuntime(ctx context.Context) (err error) {
|
|
||||||
if runtime != nil {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +60,59 @@ func initRuntime(ctx context.Context) (err error) {
|
||||||
cfg = cfg.WithCompilationCache(cache)
|
cfg = cfg.WithCompilationCache(cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize new runtime from config.
|
var (
|
||||||
runtime, err = wasm.NewRuntime(ctx, cfg)
|
run wazero.Runtime
|
||||||
|
mod wazero.CompiledModule
|
||||||
|
err error
|
||||||
|
set bool
|
||||||
|
)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err == nil && set {
|
||||||
|
// Drop binary.
|
||||||
|
embed.B = nil
|
||||||
return
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ func (m *Module) indexHandler(c *gin.Context) {
|
||||||
Instance: instance,
|
Instance: instance,
|
||||||
OGMeta: apiutil.OGBase(instance),
|
OGMeta: apiutil.OGBase(instance),
|
||||||
Stylesheets: []string{cssAbout, cssIndex},
|
Stylesheets: []string{cssAbout, cssIndex},
|
||||||
Extra: map[string]any{"showStrap": true},
|
Extra: map[string]any{"showStrap": true, "showLoginButton": true},
|
||||||
}
|
}
|
||||||
|
|
||||||
apiutil.TemplateWebPage(c, page)
|
apiutil.TemplateWebPage(c, page)
|
||||||
|
|
63
internal/web/login.go
Normal file
63
internal/web/login.go
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
// 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 web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
|
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
loginPath = "/login"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *Module) loginGETHandler(c *gin.Context) {
|
||||||
|
instance, errWithCode := m.processor.InstanceGetV1(c.Request.Context())
|
||||||
|
if errWithCode != nil {
|
||||||
|
apiutil.WebErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return instance we already got from the db,
|
||||||
|
// don't try to fetch it again when erroring.
|
||||||
|
instanceGet := func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode) {
|
||||||
|
return instance, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only serve text/html at this endpoint.
|
||||||
|
if _, err := apiutil.NegotiateAccept(c, apiutil.TextHTML); err != nil {
|
||||||
|
apiutil.WebErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), instanceGet)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
page := apiutil.WebPage{
|
||||||
|
Template: "login.tmpl",
|
||||||
|
Instance: instance,
|
||||||
|
OGMeta: apiutil.OGBase(instance),
|
||||||
|
Stylesheets: []string{cssLogin},
|
||||||
|
Extra: map[string]any{
|
||||||
|
"showStrap": false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
apiutil.TemplateWebPage(c, page)
|
||||||
|
}
|
|
@ -61,6 +61,7 @@
|
||||||
cssFA = assetsPathPrefix + "/Fork-Awesome/css/fork-awesome.min.css"
|
cssFA = assetsPathPrefix + "/Fork-Awesome/css/fork-awesome.min.css"
|
||||||
cssAbout = distPathPrefix + "/about.css"
|
cssAbout = distPathPrefix + "/about.css"
|
||||||
cssIndex = distPathPrefix + "/index.css"
|
cssIndex = distPathPrefix + "/index.css"
|
||||||
|
cssLogin = distPathPrefix + "/login.css"
|
||||||
cssStatus = distPathPrefix + "/status.css"
|
cssStatus = distPathPrefix + "/status.css"
|
||||||
cssThread = distPathPrefix + "/thread.css"
|
cssThread = distPathPrefix + "/thread.css"
|
||||||
cssProfile = distPathPrefix + "/profile.css"
|
cssProfile = distPathPrefix + "/profile.css"
|
||||||
|
@ -119,6 +120,7 @@ func (m *Module) Route(r *router.Router, mi ...gin.HandlerFunc) {
|
||||||
r.AttachHandler(http.MethodPost, confirmEmailPath, m.confirmEmailPOSTHandler)
|
r.AttachHandler(http.MethodPost, confirmEmailPath, m.confirmEmailPOSTHandler)
|
||||||
r.AttachHandler(http.MethodGet, robotsPath, m.robotsGETHandler)
|
r.AttachHandler(http.MethodGet, robotsPath, m.robotsGETHandler)
|
||||||
r.AttachHandler(http.MethodGet, aboutPath, m.aboutGETHandler)
|
r.AttachHandler(http.MethodGet, aboutPath, m.aboutGETHandler)
|
||||||
|
r.AttachHandler(http.MethodGet, loginPath, m.loginGETHandler)
|
||||||
r.AttachHandler(http.MethodGet, domainBlockListPath, m.domainBlockListGETHandler)
|
r.AttachHandler(http.MethodGet, domainBlockListPath, m.domainBlockListGETHandler)
|
||||||
r.AttachHandler(http.MethodGet, tagsPath, m.tagGETHandler)
|
r.AttachHandler(http.MethodGet, tagsPath, m.tagGETHandler)
|
||||||
r.AttachHandler(http.MethodGet, signupPath, m.signupGETHandler)
|
r.AttachHandler(http.MethodGet, signupPath, m.signupGETHandler)
|
||||||
|
|
BIN
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/ffmpeg.wasm
generated
vendored
BIN
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/ffmpeg.wasm
generated
vendored
Binary file not shown.
25
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/lib.go
generated
vendored
25
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/lib.go
generated
vendored
|
@ -1,25 +0,0 @@
|
||||||
package ffmpeg
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Check for WASM source file path.
|
|
||||||
path := os.Getenv("FFMPEG_WASM")
|
|
||||||
if path == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Read file into memory.
|
|
||||||
B, err = os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:embed ffmpeg.wasm
|
|
||||||
var B []byte
|
|
BIN
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz
generated
vendored
Normal file
BIN
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/ffprobe.wasm
generated
vendored
BIN
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/ffprobe.wasm
generated
vendored
Binary file not shown.
25
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/lib.go
generated
vendored
25
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/lib.go
generated
vendored
|
@ -1,25 +0,0 @@
|
||||||
package ffprobe
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Check for WASM source file path.
|
|
||||||
path := os.Getenv("FFPROBE_WASM")
|
|
||||||
if path == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Read file into memory.
|
|
||||||
B, err = os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:embed ffprobe.wasm
|
|
||||||
var B []byte
|
|
39
vendor/codeberg.org/gruf/go-ffmpreg/embed/lib.go
generated
vendored
Normal file
39
vendor/codeberg.org/gruf/go-ffmpreg/embed/lib.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package embed
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
_ "embed"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if path := os.Getenv("FFMPREG_WASM"); path != "" {
|
||||||
|
// Read file into memory.
|
||||||
|
B, err = os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap bytes in reader.
|
||||||
|
b := bytes.NewReader(B)
|
||||||
|
|
||||||
|
// Create unzipper from reader.
|
||||||
|
gz, err := gzip.NewReader(b)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract gzipped binary.
|
||||||
|
B, err = io.ReadAll(gz)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:embed ffmpreg.wasm.gz
|
||||||
|
var B []byte
|
7
vendor/codeberg.org/gruf/go-ffmpreg/wasm/run.go
generated
vendored
7
vendor/codeberg.org/gruf/go-ffmpreg/wasm/run.go
generated
vendored
|
@ -14,6 +14,11 @@
|
||||||
// wazero.Runtime on module instantiation.
|
// wazero.Runtime on module instantiation.
|
||||||
type Args struct {
|
type Args struct {
|
||||||
|
|
||||||
|
// Program name, depending on the
|
||||||
|
// module being run this may or may
|
||||||
|
// not be necessary.
|
||||||
|
Name string
|
||||||
|
|
||||||
// Optional further module configuration function.
|
// Optional further module configuration function.
|
||||||
// (e.g. to mount filesystem dir, set env vars, etc).
|
// (e.g. to mount filesystem dir, set env vars, etc).
|
||||||
Config func(wazero.ModuleConfig) wazero.ModuleConfig
|
Config func(wazero.ModuleConfig) wazero.ModuleConfig
|
||||||
|
@ -39,7 +44,7 @@ func Run(
|
||||||
|
|
||||||
// Prefix arguments with module name.
|
// Prefix arguments with module name.
|
||||||
cargs := make([]string, len(args.Args)+1)
|
cargs := make([]string, len(args.Args)+1)
|
||||||
cargs[0] = module.Name()
|
cargs[0] = args.Name
|
||||||
copy(cargs[1:], args.Args)
|
copy(cargs[1:], args.Args)
|
||||||
|
|
||||||
// Prepare new module configuration.
|
// Prepare new module configuration.
|
||||||
|
|
10
vendor/github.com/ncruces/go-sqlite3/config.go
generated
vendored
10
vendor/github.com/ncruces/go-sqlite3/config.go
generated
vendored
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/tetratelabs/wazero/api"
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
@ -70,6 +71,15 @@ func logCallback(ctx context.Context, mod api.Module, _, iCode, zMsg uint32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log writes a message into the error log established by [Conn.ConfigLog].
|
||||||
|
//
|
||||||
|
// https://sqlite.org/c3ref/log.html
|
||||||
|
func (c *Conn) Log(code ExtendedErrorCode, format string, a ...any) {
|
||||||
|
if c.log != nil {
|
||||||
|
c.log(code, fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FileControl allows low-level control of database files.
|
// FileControl allows low-level control of database files.
|
||||||
// Only a subset of opcodes are supported.
|
// Only a subset of opcodes are supported.
|
||||||
//
|
//
|
||||||
|
|
1
vendor/github.com/ncruces/go-sqlite3/context.go
generated
vendored
1
vendor/github.com/ncruces/go-sqlite3/context.go
generated
vendored
|
@ -89,6 +89,7 @@ func (ctx Context) ResultText(value string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResultRawText sets the text result of the function to a []byte.
|
// ResultRawText sets the text result of the function to a []byte.
|
||||||
|
// Returning a nil slice is the same as calling [Context.ResultNull].
|
||||||
//
|
//
|
||||||
// https://sqlite.org/c3ref/result_blob.html
|
// https://sqlite.org/c3ref/result_blob.html
|
||||||
func (ctx Context) ResultRawText(value []byte) {
|
func (ctx Context) ResultRawText(value []byte) {
|
||||||
|
|
10
vendor/github.com/ncruces/go-sqlite3/error.go
generated
vendored
10
vendor/github.com/ncruces/go-sqlite3/error.go
generated
vendored
|
@ -106,6 +106,11 @@ func (e ErrorCode) Temporary() bool {
|
||||||
return e == BUSY
|
return e == BUSY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExtendedCode returns the extended error code for this error.
|
||||||
|
func (e ErrorCode) ExtendedCode() ExtendedErrorCode {
|
||||||
|
return ExtendedErrorCode(e)
|
||||||
|
}
|
||||||
|
|
||||||
// Error implements the error interface.
|
// Error implements the error interface.
|
||||||
func (e ExtendedErrorCode) Error() string {
|
func (e ExtendedErrorCode) Error() string {
|
||||||
return util.ErrorCodeString(uint32(e))
|
return util.ErrorCodeString(uint32(e))
|
||||||
|
@ -136,6 +141,11 @@ func (e ExtendedErrorCode) Timeout() bool {
|
||||||
return e == BUSY_TIMEOUT
|
return e == BUSY_TIMEOUT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Code returns the primary error code for this error.
|
||||||
|
func (e ExtendedErrorCode) Code() ErrorCode {
|
||||||
|
return ErrorCode(e)
|
||||||
|
}
|
||||||
|
|
||||||
func errorCode(err error, def ErrorCode) (msg string, code uint32) {
|
func errorCode(err error, def ErrorCode) (msg string, code uint32) {
|
||||||
switch code := err.(type) {
|
switch code := err.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
|
|
12
vendor/github.com/ncruces/go-sqlite3/internal/util/mmap.go
generated
vendored
12
vendor/github.com/ncruces/go-sqlite3/internal/util/mmap.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
//go:build unix && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_noshm || sqlite3_nosys)
|
//go:build unix && !sqlite3_nosys
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
|
@ -55,10 +55,10 @@ type MappedRegion struct {
|
||||||
used bool
|
used bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func MapRegion(ctx context.Context, mod api.Module, f *os.File, offset int64, size int32, prot int) (*MappedRegion, error) {
|
func MapRegion(ctx context.Context, mod api.Module, f *os.File, offset int64, size int32, readOnly bool) (*MappedRegion, error) {
|
||||||
s := ctx.Value(moduleKey{}).(*moduleState)
|
s := ctx.Value(moduleKey{}).(*moduleState)
|
||||||
r := s.new(ctx, mod, size)
|
r := s.new(ctx, mod, size)
|
||||||
err := r.mmap(f, offset, prot)
|
err := r.mmap(f, offset, readOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,11 @@ func (r *MappedRegion) Unmap() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *MappedRegion) mmap(f *os.File, offset int64, prot int) error {
|
func (r *MappedRegion) mmap(f *os.File, offset int64, readOnly bool) error {
|
||||||
|
prot := unix.PROT_READ
|
||||||
|
if !readOnly {
|
||||||
|
prot |= unix.PROT_WRITE
|
||||||
|
}
|
||||||
_, err := unix.MmapPtr(int(f.Fd()), offset, r.addr, uintptr(r.size),
|
_, err := unix.MmapPtr(int(f.Fd()), offset, r.addr, uintptr(r.size),
|
||||||
prot, unix.MAP_SHARED|unix.MAP_FIXED)
|
prot, unix.MAP_SHARED|unix.MAP_FIXED)
|
||||||
r.used = err == nil
|
r.used = err == nil
|
||||||
|
|
2
vendor/github.com/ncruces/go-sqlite3/internal/util/mmap_other.go
generated
vendored
2
vendor/github.com/ncruces/go-sqlite3/internal/util/mmap_other.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
//go:build !unix || !(386 || arm || amd64 || arm64 || riscv64 || ppc64le) || sqlite3_noshm || sqlite3_nosys
|
//go:build !unix || sqlite3_nosys
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
|
|
53
vendor/github.com/ncruces/go-sqlite3/internal/util/mmap_windows.go
generated
vendored
Normal file
53
vendor/github.com/ncruces/go-sqlite3/internal/util/mmap_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//go:build !sqlite3_nosys
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MappedRegion struct {
|
||||||
|
windows.Handle
|
||||||
|
Data []byte
|
||||||
|
addr uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapRegion(ctx context.Context, mod api.Module, f *os.File, offset int64, size int32) (*MappedRegion, error) {
|
||||||
|
h, err := windows.CreateFileMapping(windows.Handle(f.Fd()), nil, windows.PAGE_READWRITE, 0, 0, nil)
|
||||||
|
if h == 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a, err := windows.MapViewOfFile(h, windows.FILE_MAP_WRITE,
|
||||||
|
uint32(offset>>32), uint32(offset), uintptr(size))
|
||||||
|
if a == 0 {
|
||||||
|
windows.CloseHandle(h)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := &MappedRegion{Handle: h, addr: a}
|
||||||
|
// SliceHeader, although deprecated, avoids a go vet warning.
|
||||||
|
sh := (*reflect.SliceHeader)(unsafe.Pointer(&res.Data))
|
||||||
|
sh.Len = int(size)
|
||||||
|
sh.Cap = int(size)
|
||||||
|
sh.Data = a
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MappedRegion) Unmap() error {
|
||||||
|
if r.Data == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := windows.UnmapViewOfFile(r.addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Data = nil
|
||||||
|
return windows.CloseHandle(r.Handle)
|
||||||
|
}
|
1
vendor/github.com/ncruces/go-sqlite3/stmt.go
generated
vendored
1
vendor/github.com/ncruces/go-sqlite3/stmt.go
generated
vendored
|
@ -255,6 +255,7 @@ func (s *Stmt) BindText(param int, value string) error {
|
||||||
|
|
||||||
// BindRawText binds a []byte to the prepared statement as text.
|
// BindRawText binds a []byte to the prepared statement as text.
|
||||||
// The leftmost SQL parameter has an index of 1.
|
// The leftmost SQL parameter has an index of 1.
|
||||||
|
// Binding a nil slice is the same as calling [Stmt.BindNull].
|
||||||
//
|
//
|
||||||
// https://sqlite.org/c3ref/bind_blob.html
|
// https://sqlite.org/c3ref/bind_blob.html
|
||||||
func (s *Stmt) BindRawText(param int, value []byte) error {
|
func (s *Stmt) BindRawText(param int, value []byte) error {
|
||||||
|
|
36
vendor/github.com/ncruces/go-sqlite3/vfs/README.md
generated
vendored
36
vendor/github.com/ncruces/go-sqlite3/vfs/README.md
generated
vendored
|
@ -15,24 +15,23 @@ The main differences are [file locking](#file-locking) and [WAL mode](#write-ahe
|
||||||
|
|
||||||
POSIX advisory locks, which SQLite uses on Unix, are
|
POSIX advisory locks, which SQLite uses on Unix, are
|
||||||
[broken by design](https://github.com/sqlite/sqlite/blob/b74eb0/src/os_unix.c#L1073-L1161).
|
[broken by design](https://github.com/sqlite/sqlite/blob/b74eb0/src/os_unix.c#L1073-L1161).
|
||||||
|
Instead, on Linux and macOS, this package uses
|
||||||
On Linux and macOS, this package uses
|
|
||||||
[OFD locks](https://www.gnu.org/software/libc/manual/html_node/Open-File-Description-Locks.html)
|
[OFD locks](https://www.gnu.org/software/libc/manual/html_node/Open-File-Description-Locks.html)
|
||||||
to synchronize access to database files.
|
to synchronize access to database files.
|
||||||
OFD locks are fully compatible with POSIX advisory locks.
|
|
||||||
|
|
||||||
This package can also use
|
This package can also use
|
||||||
[BSD locks](https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=2),
|
[BSD locks](https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=2),
|
||||||
albeit with reduced concurrency (`BEGIN IMMEDIATE` behaves like `BEGIN EXCLUSIVE`).
|
albeit with reduced concurrency (`BEGIN IMMEDIATE` behaves like `BEGIN EXCLUSIVE`).
|
||||||
On BSD, macOS, and illumos, BSD locks are fully compatible with POSIX advisory locks;
|
|
||||||
on Linux and z/OS, they are fully functional, but incompatible;
|
|
||||||
elsewhere, they are very likely broken.
|
|
||||||
BSD locks are the default on BSD and illumos,
|
BSD locks are the default on BSD and illumos,
|
||||||
but you can opt into them with the `sqlite3_flock` build tag.
|
but you can opt into them with the `sqlite3_flock` build tag.
|
||||||
|
|
||||||
On Windows, this package uses `LockFileEx` and `UnlockFileEx`,
|
On Windows, this package uses `LockFileEx` and `UnlockFileEx`,
|
||||||
like SQLite.
|
like SQLite.
|
||||||
|
|
||||||
|
You can also opt into a cross-platform locking implementation
|
||||||
|
with the `sqlite3_dotlk` build tag.
|
||||||
|
The only requirement is an atomic `os.Mkdir`.
|
||||||
|
|
||||||
Otherwise, file locking is not supported, and you must use
|
Otherwise, file locking is not supported, and you must use
|
||||||
[`nolock=1`](https://sqlite.org/uri.html#urinolock)
|
[`nolock=1`](https://sqlite.org/uri.html#urinolock)
|
||||||
(or [`immutable=1`](https://sqlite.org/uri.html#uriimmutable))
|
(or [`immutable=1`](https://sqlite.org/uri.html#uriimmutable))
|
||||||
|
@ -46,7 +45,7 @@ to check if your build supports file locking.
|
||||||
|
|
||||||
### Write-Ahead Logging
|
### Write-Ahead Logging
|
||||||
|
|
||||||
On little-endian Unix, this package uses `mmap` to implement
|
On Unix, this package may use `mmap` to implement
|
||||||
[shared-memory for the WAL-index](https://sqlite.org/wal.html#implementation_of_shared_memory_for_the_wal_index),
|
[shared-memory for the WAL-index](https://sqlite.org/wal.html#implementation_of_shared_memory_for_the_wal_index),
|
||||||
like SQLite.
|
like SQLite.
|
||||||
|
|
||||||
|
@ -55,6 +54,11 @@ a WAL database can only be accessed by a single proccess.
|
||||||
Other processes that attempt to access a database locked with BSD locks,
|
Other processes that attempt to access a database locked with BSD locks,
|
||||||
will fail with the [`SQLITE_PROTOCOL`](https://sqlite.org/rescode.html#protocol) error code.
|
will fail with the [`SQLITE_PROTOCOL`](https://sqlite.org/rescode.html#protocol) error code.
|
||||||
|
|
||||||
|
On Windows, this package may use `MapViewOfFile`, like SQLite.
|
||||||
|
|
||||||
|
You can also opt into a cross-platform, in-process, memory sharing implementation
|
||||||
|
with the `sqlite3_dotlk` build tag.
|
||||||
|
|
||||||
Otherwise, [WAL support is limited](https://sqlite.org/wal.html#noshm),
|
Otherwise, [WAL support is limited](https://sqlite.org/wal.html#noshm),
|
||||||
and `EXCLUSIVE` locking mode must be set to create, read, and write WAL databases.
|
and `EXCLUSIVE` locking mode must be set to create, read, and write WAL databases.
|
||||||
To use `EXCLUSIVE` locking mode with the
|
To use `EXCLUSIVE` locking mode with the
|
||||||
|
@ -67,7 +71,7 @@ to check if your build supports shared memory.
|
||||||
|
|
||||||
### Batch-Atomic Write
|
### Batch-Atomic Write
|
||||||
|
|
||||||
On 64-bit Linux, this package supports
|
On Linux, this package may support
|
||||||
[batch-atomic writes](https://sqlite.org/cgi/src/technote/714)
|
[batch-atomic writes](https://sqlite.org/cgi/src/technote/714)
|
||||||
on the F2FS filesystem.
|
on the F2FS filesystem.
|
||||||
|
|
||||||
|
@ -86,27 +90,27 @@ The implementation is compatible with SQLite's
|
||||||
### Build Tags
|
### Build Tags
|
||||||
|
|
||||||
The VFS can be customized with a few build tags:
|
The VFS can be customized with a few build tags:
|
||||||
- `sqlite3_flock` forces the use of BSD locks; it can be used on z/OS to enable locking,
|
- `sqlite3_flock` forces the use of BSD locks.
|
||||||
and elsewhere to test BSD locks.
|
- `sqlite3_dotlk` forces the use of dot-file locks.
|
||||||
- `sqlite3_nosys` prevents importing [`x/sys`](https://pkg.go.dev/golang.org/x/sys);
|
- `sqlite3_nosys` prevents importing [`x/sys`](https://pkg.go.dev/golang.org/x/sys).
|
||||||
disables locking _and_ shared memory on all platforms.
|
|
||||||
- `sqlite3_noshm` disables shared memory on all platforms.
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> The default configuration of this package is compatible with the standard
|
> The default configuration of this package is compatible with the standard
|
||||||
> [Unix and Windows SQLite VFSes](https://sqlite.org/vfs.html#multiple_vfses);
|
> [Unix and Windows SQLite VFSes](https://sqlite.org/vfs.html#multiple_vfses);
|
||||||
> `sqlite3_flock` builds are compatible with the
|
> `sqlite3_flock` builds are compatible with the
|
||||||
> [`unix-flock` VFS](https://sqlite.org/compile.html#enable_locking_style).
|
> [`unix-flock` VFS](https://sqlite.org/compile.html#enable_locking_style);
|
||||||
|
> `sqlite3_dotlk` builds are compatible with the
|
||||||
|
> [`unix-dotfile` VFS](https://sqlite.org/compile.html#enable_locking_style).
|
||||||
> If incompatible file locking is used, accessing databases concurrently with
|
> If incompatible file locking is used, accessing databases concurrently with
|
||||||
> _other_ SQLite libraries will eventually corrupt data.
|
> _other_ SQLite libraries will eventually corrupt data.
|
||||||
|
|
||||||
### Custom VFSes
|
### Custom VFSes
|
||||||
|
|
||||||
- [`github.com/ncruces/go-sqlite3/vfs/adiantum`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/adiantum)
|
|
||||||
wraps a VFS to offer encryption at rest.
|
|
||||||
- [`github.com/ncruces/go-sqlite3/vfs/memdb`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/memdb)
|
- [`github.com/ncruces/go-sqlite3/vfs/memdb`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/memdb)
|
||||||
implements an in-memory VFS.
|
implements an in-memory VFS.
|
||||||
- [`github.com/ncruces/go-sqlite3/vfs/readervfs`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/readervfs)
|
- [`github.com/ncruces/go-sqlite3/vfs/readervfs`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/readervfs)
|
||||||
implements a VFS for immutable databases.
|
implements a VFS for immutable databases.
|
||||||
|
- [`github.com/ncruces/go-sqlite3/vfs/adiantum`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/adiantum)
|
||||||
|
wraps a VFS to offer encryption at rest.
|
||||||
- [`github.com/ncruces/go-sqlite3/vfs/xts`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/xts)
|
- [`github.com/ncruces/go-sqlite3/vfs/xts`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/xts)
|
||||||
wraps a VFS to offer encryption at rest.
|
wraps a VFS to offer encryption at rest.
|
4
vendor/github.com/ncruces/go-sqlite3/vfs/const.go
generated
vendored
4
vendor/github.com/ncruces/go-sqlite3/vfs/const.go
generated
vendored
|
@ -234,4 +234,8 @@ func (e _ErrorCode) Error() string {
|
||||||
_SHM_LOCK _ShmFlag = 2
|
_SHM_LOCK _ShmFlag = 2
|
||||||
_SHM_SHARED _ShmFlag = 4
|
_SHM_SHARED _ShmFlag = 4
|
||||||
_SHM_EXCLUSIVE _ShmFlag = 8
|
_SHM_EXCLUSIVE _ShmFlag = 8
|
||||||
|
|
||||||
|
_SHM_NLOCK = 8
|
||||||
|
_SHM_BASE = 120
|
||||||
|
_SHM_DMS = _SHM_BASE + _SHM_NLOCK
|
||||||
)
|
)
|
||||||
|
|
5
vendor/github.com/ncruces/go-sqlite3/vfs/file.go
generated
vendored
5
vendor/github.com/ncruces/go-sqlite3/vfs/file.go
generated
vendored
|
@ -35,10 +35,10 @@ func testSymlinks(path string) error {
|
||||||
|
|
||||||
func (vfsOS) Delete(path string, syncDir bool) error {
|
func (vfsOS) Delete(path string, syncDir bool) error {
|
||||||
err := os.Remove(path)
|
err := os.Remove(path)
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, fs.ErrNotExist) {
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
return _IOERR_DELETE_NOENT
|
return _IOERR_DELETE_NOENT
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if runtime.GOOS != "windows" && syncDir {
|
if runtime.GOOS != "windows" && syncDir {
|
||||||
|
@ -151,6 +151,7 @@ func (f *vfsFile) Close() error {
|
||||||
if f.shm != nil {
|
if f.shm != nil {
|
||||||
f.shm.Close()
|
f.shm.Close()
|
||||||
}
|
}
|
||||||
|
f.Unlock(LOCK_NONE)
|
||||||
return f.File.Close()
|
return f.File.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,10 +207,10 @@ func (f *vfsFile) HasMoved() (bool, error) {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
pi, err := os.Stat(f.Name())
|
pi, err := os.Stat(f.Name())
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, fs.ErrNotExist) {
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return !os.SameFile(fi, pi), nil
|
return !os.SameFile(fi, pi), nil
|
||||||
|
|
2
vendor/github.com/ncruces/go-sqlite3/vfs/lock.go
generated
vendored
2
vendor/github.com/ncruces/go-sqlite3/vfs/lock.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
//go:build (linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) && !sqlite3_nosys
|
//go:build ((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && !sqlite3_nosys) || sqlite3_flock || sqlite3_dotlk
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
2
vendor/github.com/ncruces/go-sqlite3/vfs/lock_other.go
generated
vendored
2
vendor/github.com/ncruces/go-sqlite3/vfs/lock_other.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
//go:build !(linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) || sqlite3_nosys
|
//go:build !(((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && !sqlite3_nosys) || sqlite3_flock || sqlite3_dotlk)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
22
vendor/github.com/ncruces/go-sqlite3/vfs/memdb/memdb.go
generated
vendored
22
vendor/github.com/ncruces/go-sqlite3/vfs/memdb/memdb.go
generated
vendored
|
@ -78,19 +78,15 @@ type memDB struct {
|
||||||
|
|
||||||
// +checklocks:dataMtx
|
// +checklocks:dataMtx
|
||||||
data []*[sectorSize]byte
|
data []*[sectorSize]byte
|
||||||
|
|
||||||
// +checklocks:dataMtx
|
// +checklocks:dataMtx
|
||||||
size int64
|
size int64
|
||||||
|
|
||||||
// +checklocks:lockMtx
|
|
||||||
shared int32
|
|
||||||
// +checklocks:lockMtx
|
|
||||||
reserved bool
|
|
||||||
// +checklocks:lockMtx
|
|
||||||
pending bool
|
|
||||||
|
|
||||||
// +checklocks:memoryMtx
|
// +checklocks:memoryMtx
|
||||||
refs int
|
refs int32
|
||||||
|
|
||||||
|
shared int32 // +checklocks:lockMtx
|
||||||
|
pending bool // +checklocks:lockMtx
|
||||||
|
reserved bool // +checklocks:lockMtx
|
||||||
|
|
||||||
lockMtx sync.Mutex
|
lockMtx sync.Mutex
|
||||||
dataMtx sync.RWMutex
|
dataMtx sync.RWMutex
|
||||||
|
@ -253,12 +249,12 @@ func (m *memFile) Unlock(lock vfs.LockLevel) error {
|
||||||
m.lockMtx.Lock()
|
m.lockMtx.Lock()
|
||||||
defer m.lockMtx.Unlock()
|
defer m.lockMtx.Unlock()
|
||||||
|
|
||||||
if m.pending && m.lock >= vfs.LOCK_PENDING {
|
if m.lock >= vfs.LOCK_RESERVED {
|
||||||
m.pending = false
|
|
||||||
}
|
|
||||||
if m.reserved && m.lock >= vfs.LOCK_RESERVED {
|
|
||||||
m.reserved = false
|
m.reserved = false
|
||||||
}
|
}
|
||||||
|
if m.lock >= vfs.LOCK_PENDING {
|
||||||
|
m.pending = false
|
||||||
|
}
|
||||||
if lock < vfs.LOCK_SHARED {
|
if lock < vfs.LOCK_SHARED {
|
||||||
m.shared--
|
m.shared--
|
||||||
}
|
}
|
||||||
|
|
2
vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go
generated
vendored
2
vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
//go:build (freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) && !sqlite3_nosys
|
//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && !(sqlite3_dotlk || sqlite3_nosys)) || sqlite3_flock
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
143
vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go
generated
vendored
Normal file
143
vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go
generated
vendored
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
//go:build sqlite3_dotlk
|
||||||
|
|
||||||
|
package vfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// +checklocks:vfsDotLocksMtx
|
||||||
|
vfsDotLocks = map[string]*vfsDotLocker{}
|
||||||
|
vfsDotLocksMtx sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
type vfsDotLocker struct {
|
||||||
|
shared int // +checklocks:vfsDotLocksMtx
|
||||||
|
pending *os.File // +checklocks:vfsDotLocksMtx
|
||||||
|
reserved *os.File // +checklocks:vfsDotLocksMtx
|
||||||
|
}
|
||||||
|
|
||||||
|
func osGetSharedLock(file *os.File) _ErrorCode {
|
||||||
|
vfsDotLocksMtx.Lock()
|
||||||
|
defer vfsDotLocksMtx.Unlock()
|
||||||
|
|
||||||
|
name := file.Name()
|
||||||
|
locker := vfsDotLocks[name]
|
||||||
|
if locker == nil {
|
||||||
|
err := os.Mkdir(name+".lock", 0777)
|
||||||
|
if errors.Is(err, fs.ErrExist) {
|
||||||
|
return _BUSY // Another process has the lock.
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return _IOERR_LOCK
|
||||||
|
}
|
||||||
|
locker = &vfsDotLocker{}
|
||||||
|
vfsDotLocks[name] = locker
|
||||||
|
}
|
||||||
|
|
||||||
|
if locker.pending != nil {
|
||||||
|
return _BUSY
|
||||||
|
}
|
||||||
|
locker.shared++
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func osGetReservedLock(file *os.File) _ErrorCode {
|
||||||
|
vfsDotLocksMtx.Lock()
|
||||||
|
defer vfsDotLocksMtx.Unlock()
|
||||||
|
|
||||||
|
name := file.Name()
|
||||||
|
locker := vfsDotLocks[name]
|
||||||
|
if locker == nil {
|
||||||
|
return _IOERR_LOCK
|
||||||
|
}
|
||||||
|
|
||||||
|
if locker.reserved != nil && locker.reserved != file {
|
||||||
|
return _BUSY
|
||||||
|
}
|
||||||
|
locker.reserved = file
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func osGetExclusiveLock(file *os.File, _ *LockLevel) _ErrorCode {
|
||||||
|
vfsDotLocksMtx.Lock()
|
||||||
|
defer vfsDotLocksMtx.Unlock()
|
||||||
|
|
||||||
|
name := file.Name()
|
||||||
|
locker := vfsDotLocks[name]
|
||||||
|
if locker == nil {
|
||||||
|
return _IOERR_LOCK
|
||||||
|
}
|
||||||
|
|
||||||
|
if locker.pending != nil && locker.pending != file {
|
||||||
|
return _BUSY
|
||||||
|
}
|
||||||
|
locker.pending = file
|
||||||
|
if locker.shared > 1 {
|
||||||
|
return _BUSY
|
||||||
|
}
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func osDowngradeLock(file *os.File, _ LockLevel) _ErrorCode {
|
||||||
|
vfsDotLocksMtx.Lock()
|
||||||
|
defer vfsDotLocksMtx.Unlock()
|
||||||
|
|
||||||
|
name := file.Name()
|
||||||
|
locker := vfsDotLocks[name]
|
||||||
|
if locker == nil {
|
||||||
|
return _IOERR_UNLOCK
|
||||||
|
}
|
||||||
|
|
||||||
|
if locker.reserved == file {
|
||||||
|
locker.reserved = nil
|
||||||
|
}
|
||||||
|
if locker.pending == file {
|
||||||
|
locker.pending = nil
|
||||||
|
}
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func osReleaseLock(file *os.File, state LockLevel) _ErrorCode {
|
||||||
|
vfsDotLocksMtx.Lock()
|
||||||
|
defer vfsDotLocksMtx.Unlock()
|
||||||
|
|
||||||
|
name := file.Name()
|
||||||
|
locker := vfsDotLocks[name]
|
||||||
|
if locker == nil {
|
||||||
|
return _IOERR_UNLOCK
|
||||||
|
}
|
||||||
|
|
||||||
|
if locker.shared == 1 {
|
||||||
|
err := os.Remove(name + ".lock")
|
||||||
|
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return _IOERR_UNLOCK
|
||||||
|
}
|
||||||
|
delete(vfsDotLocks, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if locker.reserved == file {
|
||||||
|
locker.reserved = nil
|
||||||
|
}
|
||||||
|
if locker.pending == file {
|
||||||
|
locker.pending = nil
|
||||||
|
}
|
||||||
|
locker.shared--
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func osCheckReservedLock(file *os.File) (bool, _ErrorCode) {
|
||||||
|
vfsDotLocksMtx.Lock()
|
||||||
|
defer vfsDotLocksMtx.Unlock()
|
||||||
|
|
||||||
|
name := file.Name()
|
||||||
|
locker := vfsDotLocks[name]
|
||||||
|
if locker == nil {
|
||||||
|
return false, _OK
|
||||||
|
}
|
||||||
|
return locker.reserved != nil, _OK
|
||||||
|
}
|
2
vendor/github.com/ncruces/go-sqlite3/vfs/os_ofd.go
generated
vendored
2
vendor/github.com/ncruces/go-sqlite3/vfs/os_ofd.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
//go:build (linux || darwin) && !(sqlite3_flock || sqlite3_nosys)
|
//go:build (linux || darwin) && !(sqlite3_flock || sqlite3_dotlk || sqlite3_nosys)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
2
vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go
generated
vendored
2
vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
//go:build !sqlite3_nosys
|
//go:build !(sqlite3_dotlk || sqlite3_nosys)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
190
vendor/github.com/ncruces/go-sqlite3/vfs/shm.go
generated
vendored
190
vendor/github.com/ncruces/go-sqlite3/vfs/shm.go
generated
vendored
|
@ -1,20 +1,7 @@
|
||||||
//go:build (darwin || linux) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_flock || sqlite3_noshm || sqlite3_nosys)
|
//go:build ((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_nosys) || sqlite3_flock || sqlite3_dotlk
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/tetratelabs/wazero/api"
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
"github.com/ncruces/go-sqlite3/internal/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SupportsSharedMemory is false on platforms that do not support shared memory.
|
// SupportsSharedMemory is false on platforms that do not support shared memory.
|
||||||
// To use [WAL without shared-memory], you need to set [EXCLUSIVE locking mode].
|
// To use [WAL without shared-memory], you need to set [EXCLUSIVE locking mode].
|
||||||
//
|
//
|
||||||
|
@ -22,12 +9,6 @@
|
||||||
// [EXCLUSIVE locking mode]: https://sqlite.org/pragma.html#pragma_locking_mode
|
// [EXCLUSIVE locking mode]: https://sqlite.org/pragma.html#pragma_locking_mode
|
||||||
const SupportsSharedMemory = true
|
const SupportsSharedMemory = true
|
||||||
|
|
||||||
const (
|
|
||||||
_SHM_NLOCK = 8
|
|
||||||
_SHM_BASE = 120
|
|
||||||
_SHM_DMS = _SHM_BASE + _SHM_NLOCK
|
|
||||||
)
|
|
||||||
|
|
||||||
func (f *vfsFile) SharedMemory() SharedMemory { return f.shm }
|
func (f *vfsFile) SharedMemory() SharedMemory { return f.shm }
|
||||||
|
|
||||||
// NewSharedMemory returns a shared-memory WAL-index
|
// NewSharedMemory returns a shared-memory WAL-index
|
||||||
|
@ -41,172 +22,5 @@ func NewSharedMemory(path string, flags OpenFlag) SharedMemory {
|
||||||
if flags&OPEN_MAIN_DB == 0 || flags&(OPEN_DELETEONCLOSE|OPEN_MEMORY) != 0 {
|
if flags&OPEN_MAIN_DB == 0 || flags&(OPEN_DELETEONCLOSE|OPEN_MEMORY) != 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &vfsShm{
|
return &vfsShm{path: path}
|
||||||
path: path,
|
|
||||||
readOnly: flags&OPEN_READONLY != 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ blockingSharedMemory = &vfsShm{}
|
|
||||||
|
|
||||||
type vfsShm struct {
|
|
||||||
*os.File
|
|
||||||
path string
|
|
||||||
regions []*util.MappedRegion
|
|
||||||
readOnly bool
|
|
||||||
blocking bool
|
|
||||||
sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *vfsShm) shmOpen() _ErrorCode {
|
|
||||||
if s.File == nil {
|
|
||||||
var flag int
|
|
||||||
if s.readOnly {
|
|
||||||
flag = unix.O_RDONLY
|
|
||||||
} else {
|
|
||||||
flag = unix.O_RDWR
|
|
||||||
}
|
|
||||||
f, err := os.OpenFile(s.path,
|
|
||||||
flag|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
|
|
||||||
if err != nil {
|
|
||||||
return _CANTOPEN
|
|
||||||
}
|
|
||||||
s.File = f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dead man's switch.
|
|
||||||
if lock, rc := osTestLock(s.File, _SHM_DMS, 1); rc != _OK {
|
|
||||||
return _IOERR_LOCK
|
|
||||||
} else if lock == unix.F_WRLCK {
|
|
||||||
return _BUSY
|
|
||||||
} else if lock == unix.F_UNLCK {
|
|
||||||
if s.readOnly {
|
|
||||||
return _READONLY_CANTINIT
|
|
||||||
}
|
|
||||||
// Do not use a blocking lock here.
|
|
||||||
// If the lock cannot be obtained immediately,
|
|
||||||
// it means some other connection is truncating the file.
|
|
||||||
// And after it has done so, it will not release its lock,
|
|
||||||
// but only downgrade it to a shared lock.
|
|
||||||
// So no point in blocking here.
|
|
||||||
// The call below to obtain the shared DMS lock may use a blocking lock.
|
|
||||||
if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc != _OK {
|
|
||||||
return rc
|
|
||||||
}
|
|
||||||
if err := s.Truncate(0); err != nil {
|
|
||||||
return _IOERR_SHMOPEN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if rc := osReadLock(s.File, _SHM_DMS, 1, time.Millisecond); rc != _OK {
|
|
||||||
return rc
|
|
||||||
}
|
|
||||||
return _OK
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) {
|
|
||||||
// Ensure size is a multiple of the OS page size.
|
|
||||||
if int(size)&(unix.Getpagesize()-1) != 0 {
|
|
||||||
return 0, _IOERR_SHMMAP
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc := s.shmOpen(); rc != _OK {
|
|
||||||
return 0, rc
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if file is big enough.
|
|
||||||
o, err := s.Seek(0, io.SeekEnd)
|
|
||||||
if err != nil {
|
|
||||||
return 0, _IOERR_SHMSIZE
|
|
||||||
}
|
|
||||||
if n := (int64(id) + 1) * int64(size); n > o {
|
|
||||||
if !extend {
|
|
||||||
return 0, _OK
|
|
||||||
}
|
|
||||||
err := osAllocate(s.File, n)
|
|
||||||
if err != nil {
|
|
||||||
return 0, _IOERR_SHMSIZE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var prot int
|
|
||||||
if s.readOnly {
|
|
||||||
prot = unix.PROT_READ
|
|
||||||
} else {
|
|
||||||
prot = unix.PROT_READ | unix.PROT_WRITE
|
|
||||||
}
|
|
||||||
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, prot)
|
|
||||||
if err != nil {
|
|
||||||
return 0, _IOERR_SHMMAP
|
|
||||||
}
|
|
||||||
s.regions = append(s.regions, r)
|
|
||||||
if s.readOnly {
|
|
||||||
return r.Ptr, _READONLY
|
|
||||||
}
|
|
||||||
return r.Ptr, _OK
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
|
||||||
// Argument check.
|
|
||||||
if n <= 0 || offset < 0 || offset+n > _SHM_NLOCK {
|
|
||||||
panic(util.AssertErr())
|
|
||||||
}
|
|
||||||
switch flags {
|
|
||||||
case
|
|
||||||
_SHM_LOCK | _SHM_SHARED,
|
|
||||||
_SHM_LOCK | _SHM_EXCLUSIVE,
|
|
||||||
_SHM_UNLOCK | _SHM_SHARED,
|
|
||||||
_SHM_UNLOCK | _SHM_EXCLUSIVE:
|
|
||||||
//
|
|
||||||
default:
|
|
||||||
panic(util.AssertErr())
|
|
||||||
}
|
|
||||||
if n != 1 && flags&_SHM_EXCLUSIVE == 0 {
|
|
||||||
panic(util.AssertErr())
|
|
||||||
}
|
|
||||||
|
|
||||||
var timeout time.Duration
|
|
||||||
if s.blocking {
|
|
||||||
timeout = time.Millisecond
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case flags&_SHM_UNLOCK != 0:
|
|
||||||
return osUnlock(s.File, _SHM_BASE+int64(offset), int64(n))
|
|
||||||
case flags&_SHM_SHARED != 0:
|
|
||||||
return osReadLock(s.File, _SHM_BASE+int64(offset), int64(n), timeout)
|
|
||||||
case flags&_SHM_EXCLUSIVE != 0:
|
|
||||||
return osWriteLock(s.File, _SHM_BASE+int64(offset), int64(n), timeout)
|
|
||||||
default:
|
|
||||||
panic(util.AssertErr())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *vfsShm) shmUnmap(delete bool) {
|
|
||||||
if s.File == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmap regions.
|
|
||||||
for _, r := range s.regions {
|
|
||||||
r.Unmap()
|
|
||||||
}
|
|
||||||
clear(s.regions)
|
|
||||||
s.regions = s.regions[:0]
|
|
||||||
|
|
||||||
// Close the file.
|
|
||||||
if delete {
|
|
||||||
os.Remove(s.path)
|
|
||||||
}
|
|
||||||
s.Close()
|
|
||||||
s.File = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *vfsShm) shmBarrier() {
|
|
||||||
s.Lock()
|
|
||||||
//lint:ignore SA2001 memory barrier.
|
|
||||||
s.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *vfsShm) shmEnableBlocking(block bool) {
|
|
||||||
s.blocking = block
|
|
||||||
}
|
}
|
||||||
|
|
81
vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go
generated
vendored
81
vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
//go:build (freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_noshm || sqlite3_nosys)
|
//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_dotlk || sqlite3_nosys)) || sqlite3_flock
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
@ -14,44 +14,14 @@
|
||||||
"github.com/ncruces/go-sqlite3/internal/util"
|
"github.com/ncruces/go-sqlite3/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SupportsSharedMemory is false on platforms that do not support shared memory.
|
|
||||||
// To use [WAL without shared-memory], you need to set [EXCLUSIVE locking mode].
|
|
||||||
//
|
|
||||||
// [WAL without shared-memory]: https://sqlite.org/wal.html#noshm
|
|
||||||
// [EXCLUSIVE locking mode]: https://sqlite.org/pragma.html#pragma_locking_mode
|
|
||||||
const SupportsSharedMemory = true
|
|
||||||
|
|
||||||
const _SHM_NLOCK = 8
|
|
||||||
|
|
||||||
func (f *vfsFile) SharedMemory() SharedMemory { return f.shm }
|
|
||||||
|
|
||||||
// NewSharedMemory returns a shared-memory WAL-index
|
|
||||||
// backed by a file with the given path.
|
|
||||||
// It will return nil if shared-memory is not supported,
|
|
||||||
// or not appropriate for the given flags.
|
|
||||||
// Only [OPEN_MAIN_DB] databases may need a WAL-index.
|
|
||||||
// You must ensure all concurrent accesses to a database
|
|
||||||
// use shared-memory instances created with the same path.
|
|
||||||
func NewSharedMemory(path string, flags OpenFlag) SharedMemory {
|
|
||||||
if flags&OPEN_MAIN_DB == 0 || flags&(OPEN_DELETEONCLOSE|OPEN_MEMORY) != 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &vfsShm{
|
|
||||||
path: path,
|
|
||||||
readOnly: flags&OPEN_READONLY != 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type vfsShmFile struct {
|
type vfsShmFile struct {
|
||||||
*os.File
|
*os.File
|
||||||
info os.FileInfo
|
info os.FileInfo
|
||||||
|
|
||||||
// +checklocks:vfsShmFilesMtx
|
refs int // +checklocks:vfsShmFilesMtx
|
||||||
refs int
|
|
||||||
|
|
||||||
// +checklocks:lockMtx
|
lock [_SHM_NLOCK]int16 // +checklocks:Mutex
|
||||||
lock [_SHM_NLOCK]int16
|
sync.Mutex
|
||||||
lockMtx sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -65,7 +35,6 @@ type vfsShm struct {
|
||||||
path string
|
path string
|
||||||
lock [_SHM_NLOCK]bool
|
lock [_SHM_NLOCK]bool
|
||||||
regions []*util.MappedRegion
|
regions []*util.MappedRegion
|
||||||
readOnly bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) Close() error {
|
func (s *vfsShm) Close() error {
|
||||||
|
@ -80,7 +49,7 @@ func (s *vfsShm) Close() error {
|
||||||
s.shmLock(0, _SHM_NLOCK, _SHM_UNLOCK)
|
s.shmLock(0, _SHM_NLOCK, _SHM_UNLOCK)
|
||||||
|
|
||||||
// Decrease reference count.
|
// Decrease reference count.
|
||||||
if s.vfsShmFile.refs > 1 {
|
if s.vfsShmFile.refs > 0 {
|
||||||
s.vfsShmFile.refs--
|
s.vfsShmFile.refs--
|
||||||
s.vfsShmFile = nil
|
s.vfsShmFile = nil
|
||||||
return nil
|
return nil
|
||||||
|
@ -97,7 +66,7 @@ func (s *vfsShm) Close() error {
|
||||||
panic(util.AssertErr())
|
panic(util.AssertErr())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmOpen() (rc _ErrorCode) {
|
func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
if s.vfsShmFile != nil {
|
if s.vfsShmFile != nil {
|
||||||
return _OK
|
return _OK
|
||||||
}
|
}
|
||||||
|
@ -128,34 +97,29 @@ func (s *vfsShm) shmOpen() (rc _ErrorCode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock and truncate the file, if not readonly.
|
// Lock and truncate the file.
|
||||||
// The lock is only released by closing the file.
|
// The lock is only released by closing the file.
|
||||||
if s.readOnly {
|
|
||||||
rc = _READONLY_CANTINIT
|
|
||||||
} else {
|
|
||||||
if rc := osLock(f, unix.LOCK_EX|unix.LOCK_NB, _IOERR_LOCK); rc != _OK {
|
if rc := osLock(f, unix.LOCK_EX|unix.LOCK_NB, _IOERR_LOCK); rc != _OK {
|
||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
if err := f.Truncate(0); err != nil {
|
if err := f.Truncate(0); err != nil {
|
||||||
return _IOERR_SHMOPEN
|
return _IOERR_SHMOPEN
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Add the new shared file.
|
// Add the new shared file.
|
||||||
s.vfsShmFile = &vfsShmFile{
|
s.vfsShmFile = &vfsShmFile{
|
||||||
File: f,
|
File: f,
|
||||||
info: fi,
|
info: fi,
|
||||||
refs: 1,
|
|
||||||
}
|
}
|
||||||
f = nil // Don't close the file.
|
f = nil // Don't close the file.
|
||||||
for i, g := range vfsShmFiles {
|
for i, g := range vfsShmFiles {
|
||||||
if g == nil {
|
if g == nil {
|
||||||
vfsShmFiles[i] = s.vfsShmFile
|
vfsShmFiles[i] = s.vfsShmFile
|
||||||
return rc
|
return _OK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vfsShmFiles = append(vfsShmFiles, s.vfsShmFile)
|
vfsShmFiles = append(vfsShmFiles, s.vfsShmFile)
|
||||||
return rc
|
return _OK
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) {
|
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) {
|
||||||
|
@ -177,32 +141,22 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
|
||||||
if !extend {
|
if !extend {
|
||||||
return 0, _OK
|
return 0, _OK
|
||||||
}
|
}
|
||||||
err := osAllocate(s.File, n)
|
if osAllocate(s.File, n) != nil {
|
||||||
if err != nil {
|
|
||||||
return 0, _IOERR_SHMSIZE
|
return 0, _IOERR_SHMSIZE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var prot int
|
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, false)
|
||||||
if s.readOnly {
|
|
||||||
prot = unix.PROT_READ
|
|
||||||
} else {
|
|
||||||
prot = unix.PROT_READ | unix.PROT_WRITE
|
|
||||||
}
|
|
||||||
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, prot)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, _IOERR_SHMMAP
|
return 0, _IOERR_SHMMAP
|
||||||
}
|
}
|
||||||
s.regions = append(s.regions, r)
|
s.regions = append(s.regions, r)
|
||||||
if s.readOnly {
|
|
||||||
return r.Ptr, _READONLY
|
|
||||||
}
|
|
||||||
return r.Ptr, _OK
|
return r.Ptr, _OK
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
||||||
s.lockMtx.Lock()
|
s.Lock()
|
||||||
defer s.lockMtx.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case flags&_SHM_UNLOCK != 0:
|
case flags&_SHM_UNLOCK != 0:
|
||||||
|
@ -224,7 +178,7 @@ func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
||||||
if s.lock[i] {
|
if s.lock[i] {
|
||||||
panic(util.AssertErr())
|
panic(util.AssertErr())
|
||||||
}
|
}
|
||||||
if s.vfsShmFile.lock[i] < 0 {
|
if s.vfsShmFile.lock[i]+1 <= 0 {
|
||||||
return _BUSY
|
return _BUSY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,8 +215,7 @@ func (s *vfsShm) shmUnmap(delete bool) {
|
||||||
for _, r := range s.regions {
|
for _, r := range s.regions {
|
||||||
r.Unmap()
|
r.Unmap()
|
||||||
}
|
}
|
||||||
clear(s.regions)
|
s.regions = nil
|
||||||
s.regions = s.regions[:0]
|
|
||||||
|
|
||||||
// Close the file.
|
// Close the file.
|
||||||
if delete {
|
if delete {
|
||||||
|
@ -272,7 +225,7 @@ func (s *vfsShm) shmUnmap(delete bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmBarrier() {
|
func (s *vfsShm) shmBarrier() {
|
||||||
s.lockMtx.Lock()
|
s.Lock()
|
||||||
//lint:ignore SA2001 memory barrier.
|
//lint:ignore SA2001 memory barrier.
|
||||||
s.lockMtx.Unlock()
|
s.Unlock()
|
||||||
}
|
}
|
||||||
|
|
84
vendor/github.com/ncruces/go-sqlite3/vfs/shm_copy.go
generated
vendored
Normal file
84
vendor/github.com/ncruces/go-sqlite3/vfs/shm_copy.go
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
//go:build (windows && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_nosys) || sqlite3_dotlk
|
||||||
|
|
||||||
|
package vfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/ncruces/go-sqlite3/internal/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_WALINDEX_HDR_SIZE = 136
|
||||||
|
_WALINDEX_PGSZ = 32768
|
||||||
|
)
|
||||||
|
|
||||||
|
// This looks like a safe way of keeping the WAL-index in sync.
|
||||||
|
//
|
||||||
|
// The WAL-index file starts with a header,
|
||||||
|
// and the index doesn't meaningfully change if the header doesn't change.
|
||||||
|
//
|
||||||
|
// The header starts with two 48 byte, checksummed, copies of the same information,
|
||||||
|
// which are accessed independently between memory barriers.
|
||||||
|
// The checkpoint information that follows uses 4 byte aligned words.
|
||||||
|
//
|
||||||
|
// Finally, we have the WAL-index hash tables,
|
||||||
|
// which are only modified holding the exclusive WAL_WRITE_LOCK.
|
||||||
|
//
|
||||||
|
// Since all the data is either redundant+checksummed,
|
||||||
|
// 4 byte aligned, or modified under an exclusive lock,
|
||||||
|
// the copies below should correctly keep copies in sync.
|
||||||
|
//
|
||||||
|
// https://sqlite.org/walformat.html#the_wal_index_file_format
|
||||||
|
|
||||||
|
func (s *vfsShm) shmAcquire() {
|
||||||
|
if len(s.ptrs) == 0 || shmUnmodified(s.shadow[0][:], s.shared[0][:]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Copies modified words from shared to private memory.
|
||||||
|
for id, p := range s.ptrs {
|
||||||
|
shared := shmPage(s.shared[id][:])
|
||||||
|
shadow := shmPage(s.shadow[id][:])
|
||||||
|
privat := shmPage(util.View(s.mod, p, _WALINDEX_PGSZ))
|
||||||
|
for i, shared := range shared {
|
||||||
|
if shadow[i] != shared {
|
||||||
|
shadow[i] = shared
|
||||||
|
privat[i] = shared
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmRelease() {
|
||||||
|
if len(s.ptrs) == 0 || shmUnmodified(s.shadow[0][:], util.View(s.mod, s.ptrs[0], _WALINDEX_HDR_SIZE)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Copies modified words from private to shared memory.
|
||||||
|
for id, p := range s.ptrs {
|
||||||
|
shared := shmPage(s.shared[id][:])
|
||||||
|
shadow := shmPage(s.shadow[id][:])
|
||||||
|
privat := shmPage(util.View(s.mod, p, _WALINDEX_PGSZ))
|
||||||
|
for i, privat := range privat {
|
||||||
|
if shadow[i] != privat {
|
||||||
|
shadow[i] = privat
|
||||||
|
shared[i] = privat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmBarrier() {
|
||||||
|
s.Lock()
|
||||||
|
s.shmAcquire()
|
||||||
|
s.shmRelease()
|
||||||
|
s.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func shmPage(s []byte) *[_WALINDEX_PGSZ / 4]uint32 {
|
||||||
|
p := (*uint32)(unsafe.Pointer(unsafe.SliceData(s)))
|
||||||
|
return (*[_WALINDEX_PGSZ / 4]uint32)(unsafe.Slice(p, _WALINDEX_PGSZ/4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func shmUnmodified(v1, v2 []byte) bool {
|
||||||
|
return *(*[_WALINDEX_HDR_SIZE]byte)(v1[:]) == *(*[_WALINDEX_HDR_SIZE]byte)(v2[:])
|
||||||
|
}
|
224
vendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go
generated
vendored
Normal file
224
vendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go
generated
vendored
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
//go:build sqlite3_dotlk
|
||||||
|
|
||||||
|
package vfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ncruces/go-sqlite3/internal/util"
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type vfsShmBuffer struct {
|
||||||
|
shared [][_WALINDEX_PGSZ]byte
|
||||||
|
refs int // +checklocks:vfsShmBuffersMtx
|
||||||
|
|
||||||
|
lock [_SHM_NLOCK]int16 // +checklocks:Mutex
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// +checklocks:vfsShmBuffersMtx
|
||||||
|
vfsShmBuffers = map[string]*vfsShmBuffer{}
|
||||||
|
vfsShmBuffersMtx sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
type vfsShm struct {
|
||||||
|
*vfsShmBuffer
|
||||||
|
mod api.Module
|
||||||
|
alloc api.Function
|
||||||
|
free api.Function
|
||||||
|
path string
|
||||||
|
shadow [][_WALINDEX_PGSZ]byte
|
||||||
|
ptrs []uint32
|
||||||
|
stack [1]uint64
|
||||||
|
lock [_SHM_NLOCK]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) Close() error {
|
||||||
|
if s.vfsShmBuffer == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
vfsShmBuffersMtx.Lock()
|
||||||
|
defer vfsShmBuffersMtx.Unlock()
|
||||||
|
|
||||||
|
// Unlock everything.
|
||||||
|
s.shmLock(0, _SHM_NLOCK, _SHM_UNLOCK)
|
||||||
|
|
||||||
|
// Decrease reference count.
|
||||||
|
if s.vfsShmBuffer.refs > 0 {
|
||||||
|
s.vfsShmBuffer.refs--
|
||||||
|
s.vfsShmBuffer = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := os.Remove(s.path)
|
||||||
|
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return _IOERR_UNLOCK
|
||||||
|
}
|
||||||
|
delete(vfsShmBuffers, s.path)
|
||||||
|
s.vfsShmBuffer = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
|
if s.vfsShmBuffer != nil {
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
vfsShmBuffersMtx.Lock()
|
||||||
|
defer vfsShmBuffersMtx.Unlock()
|
||||||
|
|
||||||
|
// Find a shared buffer, increase the reference count.
|
||||||
|
if g, ok := vfsShmBuffers[s.path]; ok {
|
||||||
|
s.vfsShmBuffer = g
|
||||||
|
g.refs++
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a directory on disk to ensure only this process
|
||||||
|
// uses this path to register a shared memory.
|
||||||
|
err := os.Mkdir(s.path, 0777)
|
||||||
|
if errors.Is(err, fs.ErrExist) {
|
||||||
|
return _BUSY
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return _IOERR_LOCK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the new shared buffer.
|
||||||
|
s.vfsShmBuffer = &vfsShmBuffer{}
|
||||||
|
vfsShmBuffers[s.path] = s.vfsShmBuffer
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) {
|
||||||
|
if size != _WALINDEX_PGSZ {
|
||||||
|
return 0, _IOERR_SHMMAP
|
||||||
|
}
|
||||||
|
if s.mod == nil {
|
||||||
|
s.mod = mod
|
||||||
|
s.free = mod.ExportedFunction("sqlite3_free")
|
||||||
|
s.alloc = mod.ExportedFunction("sqlite3_malloc64")
|
||||||
|
}
|
||||||
|
if rc := s.shmOpen(); rc != _OK {
|
||||||
|
return 0, rc
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
defer s.shmAcquire()
|
||||||
|
|
||||||
|
// Extend shared memory.
|
||||||
|
if int(id) >= len(s.shared) {
|
||||||
|
if !extend {
|
||||||
|
return 0, _OK
|
||||||
|
}
|
||||||
|
s.shared = append(s.shared, make([][_WALINDEX_PGSZ]byte, int(id)-len(s.shared)+1)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate shadow memory.
|
||||||
|
if int(id) >= len(s.shadow) {
|
||||||
|
s.shadow = append(s.shadow, make([][_WALINDEX_PGSZ]byte, int(id)-len(s.shadow)+1)...)
|
||||||
|
s.shadow[0][4] = 1 // force invalidation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate local memory.
|
||||||
|
for int(id) >= len(s.ptrs) {
|
||||||
|
s.stack[0] = uint64(size)
|
||||||
|
if err := s.alloc.CallWithStack(ctx, s.stack[:]); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if s.stack[0] == 0 {
|
||||||
|
panic(util.OOMErr)
|
||||||
|
}
|
||||||
|
clear(util.View(s.mod, uint32(s.stack[0]), _WALINDEX_PGSZ))
|
||||||
|
s.ptrs = append(s.ptrs, uint32(s.stack[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.ptrs[id], _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case flags&_SHM_LOCK != 0:
|
||||||
|
defer s.shmAcquire()
|
||||||
|
case flags&_SHM_EXCLUSIVE != 0:
|
||||||
|
s.shmRelease()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case flags&_SHM_UNLOCK != 0:
|
||||||
|
for i := offset; i < offset+n; i++ {
|
||||||
|
if s.lock[i] {
|
||||||
|
if s.vfsShmBuffer.lock[i] == 0 {
|
||||||
|
panic(util.AssertErr())
|
||||||
|
}
|
||||||
|
if s.vfsShmBuffer.lock[i] <= 0 {
|
||||||
|
s.vfsShmBuffer.lock[i] = 0
|
||||||
|
} else {
|
||||||
|
s.vfsShmBuffer.lock[i]--
|
||||||
|
}
|
||||||
|
s.lock[i] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case flags&_SHM_SHARED != 0:
|
||||||
|
for i := offset; i < offset+n; i++ {
|
||||||
|
if s.lock[i] {
|
||||||
|
panic(util.AssertErr())
|
||||||
|
}
|
||||||
|
if s.vfsShmBuffer.lock[i]+1 <= 0 {
|
||||||
|
return _BUSY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := offset; i < offset+n; i++ {
|
||||||
|
s.vfsShmBuffer.lock[i]++
|
||||||
|
s.lock[i] = true
|
||||||
|
}
|
||||||
|
case flags&_SHM_EXCLUSIVE != 0:
|
||||||
|
for i := offset; i < offset+n; i++ {
|
||||||
|
if s.lock[i] {
|
||||||
|
panic(util.AssertErr())
|
||||||
|
}
|
||||||
|
if s.vfsShmBuffer.lock[i] != 0 {
|
||||||
|
return _BUSY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := offset; i < offset+n; i++ {
|
||||||
|
s.vfsShmBuffer.lock[i] = -1
|
||||||
|
s.lock[i] = true
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic(util.AssertErr())
|
||||||
|
}
|
||||||
|
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmUnmap(delete bool) {
|
||||||
|
if s.vfsShmBuffer == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
s.Lock()
|
||||||
|
s.shmRelease()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
for _, p := range s.ptrs {
|
||||||
|
s.stack[0] = uint64(p)
|
||||||
|
if err := s.free.CallWithStack(context.Background(), s.stack[:]); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.ptrs = nil
|
||||||
|
s.shadow = nil
|
||||||
|
}
|
168
vendor/github.com/ncruces/go-sqlite3/vfs/shm_ofd.go
generated
vendored
Normal file
168
vendor/github.com/ncruces/go-sqlite3/vfs/shm_ofd.go
generated
vendored
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
//go:build (linux || darwin) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_flock || sqlite3_dotlk || sqlite3_nosys)
|
||||||
|
|
||||||
|
package vfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
"github.com/ncruces/go-sqlite3/internal/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type vfsShm struct {
|
||||||
|
*os.File
|
||||||
|
path string
|
||||||
|
regions []*util.MappedRegion
|
||||||
|
readOnly bool
|
||||||
|
blocking bool
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ blockingSharedMemory = &vfsShm{}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
|
if s.File == nil {
|
||||||
|
f, err := os.OpenFile(s.path,
|
||||||
|
unix.O_RDWR|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
|
||||||
|
if err != nil {
|
||||||
|
f, err = os.OpenFile(s.path,
|
||||||
|
unix.O_RDONLY|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
|
||||||
|
s.readOnly = true
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return _CANTOPEN
|
||||||
|
}
|
||||||
|
s.File = f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dead man's switch.
|
||||||
|
if lock, rc := osTestLock(s.File, _SHM_DMS, 1); rc != _OK {
|
||||||
|
return _IOERR_LOCK
|
||||||
|
} else if lock == unix.F_WRLCK {
|
||||||
|
return _BUSY
|
||||||
|
} else if lock == unix.F_UNLCK {
|
||||||
|
if s.readOnly {
|
||||||
|
return _READONLY_CANTINIT
|
||||||
|
}
|
||||||
|
// Do not use a blocking lock here.
|
||||||
|
// If the lock cannot be obtained immediately,
|
||||||
|
// it means some other connection is truncating the file.
|
||||||
|
// And after it has done so, it will not release its lock,
|
||||||
|
// but only downgrade it to a shared lock.
|
||||||
|
// So no point in blocking here.
|
||||||
|
// The call below to obtain the shared DMS lock may use a blocking lock.
|
||||||
|
if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc != _OK {
|
||||||
|
return rc
|
||||||
|
}
|
||||||
|
if err := s.Truncate(0); err != nil {
|
||||||
|
return _IOERR_SHMOPEN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return osReadLock(s.File, _SHM_DMS, 1, time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) {
|
||||||
|
// Ensure size is a multiple of the OS page size.
|
||||||
|
if int(size)&(unix.Getpagesize()-1) != 0 {
|
||||||
|
return 0, _IOERR_SHMMAP
|
||||||
|
}
|
||||||
|
|
||||||
|
if rc := s.shmOpen(); rc != _OK {
|
||||||
|
return 0, rc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file is big enough.
|
||||||
|
o, err := s.Seek(0, io.SeekEnd)
|
||||||
|
if err != nil {
|
||||||
|
return 0, _IOERR_SHMSIZE
|
||||||
|
}
|
||||||
|
if n := (int64(id) + 1) * int64(size); n > o {
|
||||||
|
if !extend {
|
||||||
|
return 0, _OK
|
||||||
|
}
|
||||||
|
if s.readOnly || osAllocate(s.File, n) != nil {
|
||||||
|
return 0, _IOERR_SHMSIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, s.readOnly)
|
||||||
|
if err != nil {
|
||||||
|
return 0, _IOERR_SHMMAP
|
||||||
|
}
|
||||||
|
s.regions = append(s.regions, r)
|
||||||
|
if s.readOnly {
|
||||||
|
return r.Ptr, _READONLY
|
||||||
|
}
|
||||||
|
return r.Ptr, _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
||||||
|
// Argument check.
|
||||||
|
if n <= 0 || offset < 0 || offset+n > _SHM_NLOCK {
|
||||||
|
panic(util.AssertErr())
|
||||||
|
}
|
||||||
|
switch flags {
|
||||||
|
case
|
||||||
|
_SHM_LOCK | _SHM_SHARED,
|
||||||
|
_SHM_LOCK | _SHM_EXCLUSIVE,
|
||||||
|
_SHM_UNLOCK | _SHM_SHARED,
|
||||||
|
_SHM_UNLOCK | _SHM_EXCLUSIVE:
|
||||||
|
//
|
||||||
|
default:
|
||||||
|
panic(util.AssertErr())
|
||||||
|
}
|
||||||
|
if n != 1 && flags&_SHM_EXCLUSIVE == 0 {
|
||||||
|
panic(util.AssertErr())
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeout time.Duration
|
||||||
|
if s.blocking {
|
||||||
|
timeout = time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case flags&_SHM_UNLOCK != 0:
|
||||||
|
return osUnlock(s.File, _SHM_BASE+int64(offset), int64(n))
|
||||||
|
case flags&_SHM_SHARED != 0:
|
||||||
|
return osReadLock(s.File, _SHM_BASE+int64(offset), int64(n), timeout)
|
||||||
|
case flags&_SHM_EXCLUSIVE != 0:
|
||||||
|
return osWriteLock(s.File, _SHM_BASE+int64(offset), int64(n), timeout)
|
||||||
|
default:
|
||||||
|
panic(util.AssertErr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmUnmap(delete bool) {
|
||||||
|
if s.File == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmap regions.
|
||||||
|
for _, r := range s.regions {
|
||||||
|
r.Unmap()
|
||||||
|
}
|
||||||
|
s.regions = nil
|
||||||
|
|
||||||
|
// Close the file.
|
||||||
|
if delete {
|
||||||
|
os.Remove(s.path)
|
||||||
|
}
|
||||||
|
s.Close()
|
||||||
|
s.File = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmBarrier() {
|
||||||
|
s.Lock()
|
||||||
|
//lint:ignore SA2001 memory barrier.
|
||||||
|
s.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmEnableBlocking(block bool) {
|
||||||
|
s.blocking = block
|
||||||
|
}
|
2
vendor/github.com/ncruces/go-sqlite3/vfs/shm_other.go
generated
vendored
2
vendor/github.com/ncruces/go-sqlite3/vfs/shm_other.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
//go:build !(darwin || linux || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) || !(386 || arm || amd64 || arm64 || riscv64 || ppc64le) || sqlite3_noshm || sqlite3_nosys
|
//go:build !(((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_nosys) || sqlite3_flock || sqlite3_dotlk)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
182
vendor/github.com/ncruces/go-sqlite3/vfs/shm_windows.go
generated
vendored
Normal file
182
vendor/github.com/ncruces/go-sqlite3/vfs/shm_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
//go:build (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_dotlk || sqlite3_nosys)
|
||||||
|
|
||||||
|
package vfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
|
||||||
|
"github.com/ncruces/go-sqlite3/internal/util"
|
||||||
|
"github.com/ncruces/go-sqlite3/util/osutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type vfsShm struct {
|
||||||
|
*os.File
|
||||||
|
mod api.Module
|
||||||
|
alloc api.Function
|
||||||
|
free api.Function
|
||||||
|
path string
|
||||||
|
regions []*util.MappedRegion
|
||||||
|
shared [][]byte
|
||||||
|
shadow [][_WALINDEX_PGSZ]byte
|
||||||
|
ptrs []uint32
|
||||||
|
stack [1]uint64
|
||||||
|
blocking bool
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ blockingSharedMemory = &vfsShm{}
|
||||||
|
|
||||||
|
func (s *vfsShm) Close() error {
|
||||||
|
// Unmap regions.
|
||||||
|
for _, r := range s.regions {
|
||||||
|
r.Unmap()
|
||||||
|
}
|
||||||
|
s.regions = nil
|
||||||
|
|
||||||
|
// Close the file.
|
||||||
|
return s.File.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
|
if s.File == nil {
|
||||||
|
f, err := osutil.OpenFile(s.path, os.O_RDWR|os.O_CREATE, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return _CANTOPEN
|
||||||
|
}
|
||||||
|
s.File = f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dead man's switch.
|
||||||
|
if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc == _OK {
|
||||||
|
err := s.Truncate(0)
|
||||||
|
osUnlock(s.File, _SHM_DMS, 1)
|
||||||
|
if err != nil {
|
||||||
|
return _IOERR_SHMOPEN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return osReadLock(s.File, _SHM_DMS, 1, time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) {
|
||||||
|
// Ensure size is a multiple of the OS page size.
|
||||||
|
if size != _WALINDEX_PGSZ || (windows.Getpagesize()-1)&_WALINDEX_PGSZ != 0 {
|
||||||
|
return 0, _IOERR_SHMMAP
|
||||||
|
}
|
||||||
|
if s.mod == nil {
|
||||||
|
s.mod = mod
|
||||||
|
s.free = mod.ExportedFunction("sqlite3_free")
|
||||||
|
s.alloc = mod.ExportedFunction("sqlite3_malloc64")
|
||||||
|
}
|
||||||
|
if rc := s.shmOpen(); rc != _OK {
|
||||||
|
return 0, rc
|
||||||
|
}
|
||||||
|
|
||||||
|
defer s.shmAcquire()
|
||||||
|
|
||||||
|
// Check if file is big enough.
|
||||||
|
o, err := s.Seek(0, io.SeekEnd)
|
||||||
|
if err != nil {
|
||||||
|
return 0, _IOERR_SHMSIZE
|
||||||
|
}
|
||||||
|
if n := (int64(id) + 1) * int64(size); n > o {
|
||||||
|
if !extend {
|
||||||
|
return 0, _OK
|
||||||
|
}
|
||||||
|
if osAllocate(s.File, n) != nil {
|
||||||
|
return 0, _IOERR_SHMSIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maps regions into memory.
|
||||||
|
for int(id) >= len(s.shared) {
|
||||||
|
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size)
|
||||||
|
if err != nil {
|
||||||
|
return 0, _IOERR_SHMMAP
|
||||||
|
}
|
||||||
|
s.regions = append(s.regions, r)
|
||||||
|
s.shared = append(s.shared, r.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate shadow memory.
|
||||||
|
if int(id) >= len(s.shadow) {
|
||||||
|
s.shadow = append(s.shadow, make([][_WALINDEX_PGSZ]byte, int(id)-len(s.shadow)+1)...)
|
||||||
|
s.shadow[0][4] = 1 // force invalidation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate local memory.
|
||||||
|
for int(id) >= len(s.ptrs) {
|
||||||
|
s.stack[0] = uint64(size)
|
||||||
|
if err := s.alloc.CallWithStack(ctx, s.stack[:]); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if s.stack[0] == 0 {
|
||||||
|
panic(util.OOMErr)
|
||||||
|
}
|
||||||
|
clear(util.View(s.mod, uint32(s.stack[0]), _WALINDEX_PGSZ))
|
||||||
|
s.ptrs = append(s.ptrs, uint32(s.stack[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.ptrs[id], _OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
||||||
|
switch {
|
||||||
|
case flags&_SHM_LOCK != 0:
|
||||||
|
defer s.shmAcquire()
|
||||||
|
case flags&_SHM_EXCLUSIVE != 0:
|
||||||
|
s.shmRelease()
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeout time.Duration
|
||||||
|
if s.blocking {
|
||||||
|
timeout = time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case flags&_SHM_UNLOCK != 0:
|
||||||
|
return osUnlock(s.File, _SHM_BASE+uint32(offset), uint32(n))
|
||||||
|
case flags&_SHM_SHARED != 0:
|
||||||
|
return osReadLock(s.File, _SHM_BASE+uint32(offset), uint32(n), timeout)
|
||||||
|
case flags&_SHM_EXCLUSIVE != 0:
|
||||||
|
return osWriteLock(s.File, _SHM_BASE+uint32(offset), uint32(n), timeout)
|
||||||
|
default:
|
||||||
|
panic(util.AssertErr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmUnmap(delete bool) {
|
||||||
|
if s.File == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.shmRelease()
|
||||||
|
|
||||||
|
// Free local memory.
|
||||||
|
for _, p := range s.ptrs {
|
||||||
|
s.stack[0] = uint64(p)
|
||||||
|
if err := s.free.CallWithStack(context.Background(), s.stack[:]); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.ptrs = nil
|
||||||
|
s.shadow = nil
|
||||||
|
s.shared = nil
|
||||||
|
|
||||||
|
// Close the file.
|
||||||
|
s.Close()
|
||||||
|
s.File = nil
|
||||||
|
if delete {
|
||||||
|
os.Remove(s.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmEnableBlocking(block bool) {
|
||||||
|
s.blocking = block
|
||||||
|
}
|
7
vendor/modules.txt
vendored
7
vendor/modules.txt
vendored
|
@ -24,10 +24,9 @@ codeberg.org/gruf/go-fastcopy
|
||||||
# codeberg.org/gruf/go-fastpath/v2 v2.0.0
|
# codeberg.org/gruf/go-fastpath/v2 v2.0.0
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
codeberg.org/gruf/go-fastpath/v2
|
codeberg.org/gruf/go-fastpath/v2
|
||||||
# codeberg.org/gruf/go-ffmpreg v0.4.2
|
# codeberg.org/gruf/go-ffmpreg v0.6.0
|
||||||
## explicit; go 1.22.0
|
## explicit; go 1.22.0
|
||||||
codeberg.org/gruf/go-ffmpreg/embed/ffmpeg
|
codeberg.org/gruf/go-ffmpreg/embed
|
||||||
codeberg.org/gruf/go-ffmpreg/embed/ffprobe
|
|
||||||
codeberg.org/gruf/go-ffmpreg/wasm
|
codeberg.org/gruf/go-ffmpreg/wasm
|
||||||
# codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
|
# codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
|
@ -515,7 +514,7 @@ github.com/modern-go/reflect2
|
||||||
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
||||||
## explicit
|
## explicit
|
||||||
github.com/munnerz/goautoneg
|
github.com/munnerz/goautoneg
|
||||||
# github.com/ncruces/go-sqlite3 v0.20.0
|
# github.com/ncruces/go-sqlite3 v0.20.2
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
github.com/ncruces/go-sqlite3
|
github.com/ncruces/go-sqlite3
|
||||||
github.com/ncruces/go-sqlite3/driver
|
github.com/ncruces/go-sqlite3/driver
|
||||||
|
|
119
web/source/css/login.css
Normal file
119
web/source/css/login.css
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.about-section.settings {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
padding-top: 1rem !important;
|
||||||
|
padding-bottom: 1rem !important;
|
||||||
|
|
||||||
|
p.settings-text {
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-button {
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reuse about styling, but rework it
|
||||||
|
to separate sections a bit more.
|
||||||
|
*/
|
||||||
|
.about {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2rem;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
background: initial;
|
||||||
|
box-shadow: initial;
|
||||||
|
border: initial;
|
||||||
|
border-radius: initial;
|
||||||
|
|
||||||
|
.about-section {
|
||||||
|
padding: 2rem;
|
||||||
|
background: $bg-accent;
|
||||||
|
box-shadow: $boxshadow;
|
||||||
|
border: $boxshadow-border;
|
||||||
|
border-radius: $br;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.apps {
|
||||||
|
align-self: start;
|
||||||
|
|
||||||
|
.applist {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-gap: 0.5rem;
|
||||||
|
align-content: start;
|
||||||
|
|
||||||
|
.applist-entry {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 25% 1fr;
|
||||||
|
grid-template-areas: "logo text";
|
||||||
|
gap: 1.5rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
|
||||||
|
.applist-logo {
|
||||||
|
grid-area: logo;
|
||||||
|
align-self: center;
|
||||||
|
justify-self: center;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.applist-logo.redraw {
|
||||||
|
fill: $fg;
|
||||||
|
stroke: $fg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.applist-text {
|
||||||
|
grid-area: text;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.apps .applist {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -116,3 +116,9 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login {
|
||||||
|
position: absolute;
|
||||||
|
top: 2vh;
|
||||||
|
right: 2vh;
|
||||||
|
}
|
||||||
|
|
28
web/template/login.tmpl
Normal file
28
web/template/login.tmpl
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{{- /*
|
||||||
|
// 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/>.
|
||||||
|
*/ -}}
|
||||||
|
|
||||||
|
<main class="about">
|
||||||
|
<section role="region" class="about-section settings">
|
||||||
|
<p class="settings-text">
|
||||||
|
Looking to configure your profile and other settings?
|
||||||
|
</p>
|
||||||
|
<a href="/settings" class="settings-button button with-icon">Settings</a>
|
||||||
|
</section>
|
||||||
|
{{- include "index_apps.tmpl" . | indent 1 }}
|
||||||
|
</main>
|
22
web/template/login_button.tmpl
Normal file
22
web/template/login_button.tmpl
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{{- /*
|
||||||
|
// 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/>.
|
||||||
|
*/ -}}
|
||||||
|
|
||||||
|
{{- if .showLoginButton }}
|
||||||
|
<div class="login"><a href="/login" class="button with-icon">Log in</a></div>
|
||||||
|
{{- end }}
|
|
@ -71,7 +71,9 @@ image/webp
|
||||||
{{- end }}
|
{{- end }}
|
||||||
<title>{{- template "instanceTitle" . -}}</title>
|
<title>{{- template "instanceTitle" . -}}</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="page">
|
<body>
|
||||||
|
{{- include "login_button.tmpl" . | indent 3 }}
|
||||||
|
<div class="page">
|
||||||
<header class="page-header">
|
<header class="page-header">
|
||||||
{{- include "page_header.tmpl" . | indent 3 }}
|
{{- include "page_header.tmpl" . | indent 3 }}
|
||||||
</header>
|
</header>
|
||||||
|
@ -81,5 +83,6 @@ image/webp
|
||||||
<footer class="page-footer">
|
<footer class="page-footer">
|
||||||
{{- include "page_footer.tmpl" . | indent 3 }}
|
{{- include "page_footer.tmpl" . | indent 3 }}
|
||||||
</footer>
|
</footer>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in a new issue