diff --git a/go.mod b/go.mod
index 73b284743..a6a030eb6 100644
--- a/go.mod
+++ b/go.mod
@@ -31,7 +31,7 @@ require (
codeberg.org/gruf/go-debug v1.3.0
codeberg.org/gruf/go-errors/v2 v2.3.2
codeberg.org/gruf/go-fastcopy v1.1.3
- codeberg.org/gruf/go-ffmpreg v0.6.2
+ codeberg.org/gruf/go-ffmpreg v0.6.4
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
codeberg.org/gruf/go-kv v1.6.5
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
@@ -62,7 +62,7 @@ require (
github.com/miekg/dns v1.1.62
github.com/minio/minio-go/v7 v7.0.81
github.com/mitchellh/mapstructure v1.5.0
- github.com/ncruces/go-sqlite3 v0.21.0
+ github.com/ncruces/go-sqlite3 v0.21.2
github.com/oklog/ulid v1.3.1
github.com/prometheus/client_golang v1.20.5
github.com/spf13/cobra v1.8.1
diff --git a/go.sum b/go.sum
index 48e210837..09c4f9565 100644
--- a/go.sum
+++ b/go.sum
@@ -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-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-ffmpreg v0.6.2 h1:VNYfV7bQgAcY9/xk5mBNk9IBethJhHS0guUoptmgnPQ=
-codeberg.org/gruf/go-ffmpreg v0.6.2/go.mod h1:HQmEaBF83rHOt2Jo1yJv9D0JApoSLFtVR9Uzu7aVglk=
+codeberg.org/gruf/go-ffmpreg v0.6.4 h1:TaTx3SW1+PhJXgr1LUZF+/LHWg/8Oe8cDLJyMOsIPb8=
+codeberg.org/gruf/go-ffmpreg v0.6.4/go.mod h1:HQmEaBF83rHOt2Jo1yJv9D0JApoSLFtVR9Uzu7aVglk=
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-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0=
@@ -434,8 +434,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/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/ncruces/go-sqlite3 v0.21.0 h1:EwKFoy1hHEopN4sFZarmi+McXdbCcbTuLixhEayXVbQ=
-github.com/ncruces/go-sqlite3 v0.21.0/go.mod h1:zxMOaSG5kFYVFK4xQa0pdwIszqxqJ0W0BxBgwdrNjuA=
+github.com/ncruces/go-sqlite3 v0.21.2 h1:X7Ao4BwtS9h308lFtZA/stkvrzEHvAdp8g4Gko7Ehjs=
+github.com/ncruces/go-sqlite3 v0.21.2/go.mod h1:zxMOaSG5kFYVFK4xQa0pdwIszqxqJ0W0BxBgwdrNjuA=
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/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
diff --git a/internal/web/about.go b/internal/web/about.go
index 843dda652..2bc558962 100644
--- a/internal/web/about.go
+++ b/internal/web/about.go
@@ -54,7 +54,7 @@ func (m *Module) aboutGETHandler(c *gin.Context) {
Template: "about.tmpl",
Instance: instance,
OGMeta: apiutil.OGBase(instance),
- Stylesheets: []string{cssAbout, instanceCustomCSSPath},
+ Stylesheets: []string{cssAbout},
Extra: map[string]any{
"showStrap": true,
"blocklistExposed": config.GetInstanceExposeSuspendedWeb(),
diff --git a/internal/web/confirmemail.go b/internal/web/confirmemail.go
index 21028c6c4..e512761f4 100644
--- a/internal/web/confirmemail.go
+++ b/internal/web/confirmemail.go
@@ -127,9 +127,8 @@ func (m *Module) confirmEmailPOSTHandler(c *gin.Context) {
// Serve page informing user that their
// email address is now confirmed.
page := apiutil.WebPage{
- Template: "confirmed_email.tmpl",
- Instance: instance,
- Stylesheets: []string{instanceCustomCSSPath},
+ Template: "confirmed_email.tmpl",
+ Instance: instance,
Extra: map[string]any{
"email": user.Email,
"username": user.Account.Username,
diff --git a/internal/web/domain-blocklist.go b/internal/web/domain-blocklist.go
index 7b6710049..5d631e0f7 100644
--- a/internal/web/domain-blocklist.go
+++ b/internal/web/domain-blocklist.go
@@ -67,7 +67,7 @@ func (m *Module) domainBlockListGETHandler(c *gin.Context) {
Template: "domain-blocklist.tmpl",
Instance: instance,
OGMeta: apiutil.OGBase(instance),
- Stylesheets: []string{cssFA, instanceCustomCSSPath},
+ Stylesheets: []string{cssFA},
Javascript: []string{jsFrontend},
Extra: map[string]any{"blocklist": domainBlocks},
}
diff --git a/internal/web/index.go b/internal/web/index.go
index dd9d80561..25960cf7f 100644
--- a/internal/web/index.go
+++ b/internal/web/index.go
@@ -59,7 +59,7 @@ func (m *Module) indexHandler(c *gin.Context) {
Template: "index.tmpl",
Instance: instance,
OGMeta: apiutil.OGBase(instance),
- Stylesheets: []string{cssAbout, cssIndex, instanceCustomCSSPath},
+ Stylesheets: []string{cssAbout, cssIndex},
Extra: map[string]any{"showStrap": true},
}
diff --git a/internal/web/profile.go b/internal/web/profile.go
index 741dc2a83..a6d96a9ea 100644
--- a/internal/web/profile.go
+++ b/internal/web/profile.go
@@ -142,7 +142,6 @@ func (m *Module) profileGETHandler(c *gin.Context) {
cssStatus,
cssThread,
cssProfile,
- instanceCustomCSSPath,
}...,
)
diff --git a/internal/web/settings-panel.go b/internal/web/settings-panel.go
index 41cd8666e..ec8166e95 100644
--- a/internal/web/settings-panel.go
+++ b/internal/web/settings-panel.go
@@ -53,7 +53,6 @@ func (m *Module) SettingsPanelHandler(c *gin.Context) {
cssProfile, // Used for rendering stub/fake profiles.
cssStatus, // Used for rendering stub/fake statuses.
cssSettings,
- instanceCustomCSSPath,
},
Javascript: []string{jsSettings},
}
diff --git a/internal/web/signup.go b/internal/web/signup.go
index 64b9f4e2d..a943f3680 100644
--- a/internal/web/signup.go
+++ b/internal/web/signup.go
@@ -126,10 +126,9 @@ func (m *Module) signupPOSTHandler(c *gin.Context) {
// Serve a page informing the
// user that they've signed up.
page := apiutil.WebPage{
- Template: "signed-up.tmpl",
- Instance: instance,
- Stylesheets: []string{instanceCustomCSSPath},
- OGMeta: apiutil.OGBase(instance),
+ Template: "signed-up.tmpl",
+ Instance: instance,
+ OGMeta: apiutil.OGBase(instance),
Extra: map[string]any{
"email": user.UnconfirmedEmail,
"username": user.Account.Username,
diff --git a/internal/web/tag.go b/internal/web/tag.go
index 423000f99..5c3cd31a6 100644
--- a/internal/web/tag.go
+++ b/internal/web/tag.go
@@ -59,7 +59,7 @@ func (m *Module) tagGETHandler(c *gin.Context) {
Template: "tag.tmpl",
Instance: instance,
OGMeta: apiutil.OGBase(instance),
- Stylesheets: []string{cssFA, cssThread, cssTag, instanceCustomCSSPath},
+ Stylesheets: []string{cssFA, cssThread, cssTag},
Extra: map[string]any{"tagName": tagName},
}
diff --git a/internal/web/thread.go b/internal/web/thread.go
index 557e00381..60f7ac4d2 100644
--- a/internal/web/thread.go
+++ b/internal/web/thread.go
@@ -124,7 +124,6 @@ func (m *Module) threadGETHandler(c *gin.Context) {
cssFA,
cssStatus,
cssThread,
- instanceCustomCSSPath,
}...,
)
diff --git a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz b/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz
index e4e8963d2..116fcf802 100644
Binary files a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz and b/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz differ
diff --git a/vendor/github.com/ncruces/go-sqlite3/README.md b/vendor/github.com/ncruces/go-sqlite3/README.md
index d3d5e518f..b370e9638 100644
--- a/vendor/github.com/ncruces/go-sqlite3/README.md
+++ b/vendor/github.com/ncruces/go-sqlite3/README.md
@@ -74,7 +74,7 @@ This project aims for [high test coverage](https://github.com/ncruces/go-sqlite3
It also benefits greatly from [SQLite's](https://sqlite.org/testing.html) and
[wazero's](https://tetrate.io/blog/introducing-wazero-from-tetrate/#:~:text=Rock%2Dsolid%20test%20approach) thorough testing.
-Every commit is [tested](https://github.com/ncruces/go-sqlite3/wiki/Test-matrix) on
+Every commit is [tested](https://github.com/ncruces/go-sqlite3/wiki/Support-matrix) on
Linux (amd64/arm64/386/riscv64/ppc64le/s390x), macOS (amd64/arm64),
Windows (amd64), FreeBSD (amd64), OpenBSD (amd64), NetBSD (amd64),
DragonFly BSD (amd64), illumos (amd64), and Solaris (amd64).
diff --git a/vendor/github.com/ncruces/go-sqlite3/conn.go b/vendor/github.com/ncruces/go-sqlite3/conn.go
index 5ae0eef7c..d1ce30556 100644
--- a/vendor/github.com/ncruces/go-sqlite3/conn.go
+++ b/vendor/github.com/ncruces/go-sqlite3/conn.go
@@ -4,6 +4,7 @@
"context"
"fmt"
"math"
+ "math/rand"
"net/url"
"strings"
"time"
@@ -24,7 +25,6 @@ type Conn struct {
interrupt context.Context
pending *Stmt
stmts []*Stmt
- timer *time.Timer
busy func(context.Context, int) bool
log func(xErrorCode, string)
collation func(*Conn, string)
@@ -36,7 +36,9 @@ type Conn struct {
rollback func()
arena arena
- handle uint32
+ busy1st time.Time
+ busylst time.Time
+ handle uint32
}
// Open calls [OpenFlags] with [OPEN_READWRITE], [OPEN_CREATE] and [OPEN_URI].
@@ -389,38 +391,20 @@ func (c *Conn) BusyTimeout(timeout time.Duration) error {
}
func timeoutCallback(ctx context.Context, mod api.Module, count, tmout int32) (retry uint32) {
+ // https://fractaledmind.github.io/2024/04/15/sqlite-on-rails-the-how-and-why-of-optimal-performance/
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.interrupt.Err() == nil {
- const delays = "\x01\x02\x05\x0a\x0f\x14\x19\x19\x19\x32\x32\x64"
- const totals = "\x00\x01\x03\x08\x12\x21\x35\x4e\x67\x80\xb2\xe4"
- const ndelay = int32(len(delays) - 1)
-
- var delay, prior int32
- if count <= ndelay {
- delay = int32(delays[count])
- prior = int32(totals[count])
- } else {
- delay = int32(delays[ndelay])
- prior = int32(totals[ndelay]) + delay*(count-ndelay)
+ switch {
+ case count == 0:
+ c.busy1st = time.Now()
+ case time.Since(c.busy1st) >= time.Duration(tmout)*time.Millisecond:
+ return 0
}
-
- if delay = min(delay, tmout-prior); delay > 0 {
- delay := time.Duration(delay) * time.Millisecond
- if c.interrupt.Done() == nil {
- time.Sleep(delay)
- return 1
- }
- if c.timer == nil {
- c.timer = time.NewTimer(delay)
- } else {
- c.timer.Reset(delay)
- }
- select {
- case <-c.interrupt.Done():
- c.timer.Stop()
- case <-c.timer.C:
- return 1
- }
+ if time.Since(c.busylst) < time.Millisecond {
+ const sleepIncrement = 2*1024*1024 - 1 // power of two, ~2ms
+ time.Sleep(time.Duration(rand.Int63() & sleepIncrement))
}
+ c.busylst = time.Now()
+ return 1
}
return 0
}
diff --git a/vendor/github.com/ncruces/go-sqlite3/driver/driver.go b/vendor/github.com/ncruces/go-sqlite3/driver/driver.go
index 477e9a940..b9bb03bb7 100644
--- a/vendor/github.com/ncruces/go-sqlite3/driver/driver.go
+++ b/vendor/github.com/ncruces/go-sqlite3/driver/driver.go
@@ -379,7 +379,7 @@ func (c *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, e
if err != nil {
return nil, err
}
- if tail != "" {
+ if notWhitespace(tail) {
s.Close()
return nil, util.TailErr
}
diff --git a/vendor/github.com/ncruces/go-sqlite3/driver/whitespace.go b/vendor/github.com/ncruces/go-sqlite3/driver/whitespace.go
new file mode 100644
index 000000000..8f45706f5
--- /dev/null
+++ b/vendor/github.com/ncruces/go-sqlite3/driver/whitespace.go
@@ -0,0 +1,61 @@
+package driver
+
+func notWhitespace(sql string) bool {
+ const (
+ code = iota
+ slash
+ minus
+ ccomment
+ sqlcomment
+ endcomment
+ )
+
+ state := code
+ for _, b := range ([]byte)(sql) {
+ if b == 0 {
+ break
+ }
+
+ switch state {
+ case code:
+ switch b {
+ case '/':
+ state = slash
+ case '-':
+ state = minus
+ case ' ', ';', '\t', '\n', '\v', '\f', '\r':
+ continue
+ default:
+ return true
+ }
+ case slash:
+ if b != '*' {
+ return true
+ }
+ state = ccomment
+ case minus:
+ if b != '-' {
+ return true
+ }
+ state = sqlcomment
+ case ccomment:
+ if b == '*' {
+ state = endcomment
+ }
+ case sqlcomment:
+ if b == '\n' {
+ state = code
+ }
+ case endcomment:
+ switch b {
+ case '/':
+ state = code
+ case '*':
+ state = endcomment
+ default:
+ state = ccomment
+ }
+ }
+ }
+ return state == slash || state == minus
+}
diff --git a/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm b/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm
index bf119d41d..c312aa62a 100644
Binary files a/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm and b/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm differ
diff --git a/vendor/github.com/ncruces/go-sqlite3/go.work.sum b/vendor/github.com/ncruces/go-sqlite3/go.work.sum
index f41ac5535..ded9bda72 100644
--- a/vendor/github.com/ncruces/go-sqlite3/go.work.sum
+++ b/vendor/github.com/ncruces/go-sqlite3/go.work.sum
@@ -1,3 +1,4 @@
+github.com/ncruces/go-sqlite3 v0.21.0/go.mod h1:zxMOaSG5kFYVFK4xQa0pdwIszqxqJ0W0BxBgwdrNjuA=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
diff --git a/vendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk.go b/vendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk.go
new file mode 100644
index 000000000..3c8d782d7
--- /dev/null
+++ b/vendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk.go
@@ -0,0 +1,29 @@
+package dotlk
+
+import (
+ "errors"
+ "io/fs"
+ "os"
+)
+
+// LockShm creates a directory on disk to prevent SQLite
+// from using this path for a shared memory file.
+func LockShm(name string) error {
+ err := os.Mkdir(name, 0777)
+ if errors.Is(err, fs.ErrExist) {
+ s, err := os.Lstat(name)
+ if err == nil && s.IsDir() {
+ return nil
+ }
+ }
+ return err
+}
+
+// Unlock removes the lock or shared memory file.
+func Unlock(name string) error {
+ err := os.Remove(name)
+ if errors.Is(err, fs.ErrNotExist) {
+ return nil
+ }
+ return err
+}
diff --git a/vendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk_other.go b/vendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk_other.go
new file mode 100644
index 000000000..5399a5f8a
--- /dev/null
+++ b/vendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk_other.go
@@ -0,0 +1,13 @@
+//go:build !unix
+
+package dotlk
+
+import "os"
+
+// TryLock returns nil if it acquired the lock,
+// fs.ErrExist if another process has the lock.
+func TryLock(name string) error {
+ f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
+ f.Close()
+ return err
+}
diff --git a/vendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk_unix.go b/vendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk_unix.go
new file mode 100644
index 000000000..177ab30bb
--- /dev/null
+++ b/vendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk_unix.go
@@ -0,0 +1,50 @@
+//go:build unix
+
+package dotlk
+
+import (
+ "errors"
+ "io/fs"
+ "os"
+ "strconv"
+
+ "golang.org/x/sys/unix"
+)
+
+// TryLock returns nil if it acquired the lock,
+// fs.ErrExist if another process has the lock.
+func TryLock(name string) error {
+ for retry := true; retry; retry = false {
+ f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
+ if err == nil {
+ f.WriteString(strconv.Itoa(os.Getpid()))
+ f.Close()
+ return nil
+ }
+ if !errors.Is(err, fs.ErrExist) {
+ return err
+ }
+ if !removeStale(name) {
+ break
+ }
+ }
+ return fs.ErrExist
+}
+
+func removeStale(name string) bool {
+ buf, err := os.ReadFile(name)
+ if err != nil {
+ return errors.Is(err, fs.ErrNotExist)
+ }
+
+ pid, err := strconv.Atoi(string(buf))
+ if err != nil {
+ return false
+ }
+ if unix.Kill(pid, 0) == nil {
+ return false
+ }
+
+ err = os.Remove(name)
+ return err == nil || errors.Is(err, fs.ErrNotExist)
+}
diff --git a/vendor/github.com/ncruces/go-sqlite3/util/sql3util/parse/sql3parse_table.wasm b/vendor/github.com/ncruces/go-sqlite3/util/sql3util/parse/sql3parse_table.wasm
index f0b3819c8..4d3357ea1 100644
Binary files a/vendor/github.com/ncruces/go-sqlite3/util/sql3util/parse/sql3parse_table.wasm and b/vendor/github.com/ncruces/go-sqlite3/util/sql3util/parse/sql3parse_table.wasm differ
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/README.md b/vendor/github.com/ncruces/go-sqlite3/vfs/README.md
index 354f8bf33..4e987ce3f 100644
--- a/vendor/github.com/ncruces/go-sqlite3/vfs/README.md
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/README.md
@@ -48,11 +48,6 @@ 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),
like SQLite.
-With [BSD locks](https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=2)
-a WAL database can only be accessed by a single proccess.
-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.
-
On Windows, this package may use `MapViewOfFile`, like SQLite.
You can also opt into a cross-platform, in-process, memory sharing implementation
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go
index fa13ef3ae..4f6fadef4 100644
--- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go
@@ -9,11 +9,11 @@
)
func osGetSharedLock(file *os.File) _ErrorCode {
- return osLock(file, unix.LOCK_SH|unix.LOCK_NB, _IOERR_RDLOCK)
+ return osFlock(file, unix.LOCK_SH|unix.LOCK_NB, _IOERR_RDLOCK)
}
func osGetReservedLock(file *os.File) _ErrorCode {
- rc := osLock(file, unix.LOCK_EX|unix.LOCK_NB, _IOERR_LOCK)
+ rc := osFlock(file, unix.LOCK_EX|unix.LOCK_NB, _IOERR_LOCK)
if rc == _BUSY {
// The documentation states that a lock is upgraded by
// releasing the previous lock, then acquiring the new lock.
@@ -37,7 +37,7 @@ func osGetExclusiveLock(file *os.File, state *LockLevel) _ErrorCode {
}
func osDowngradeLock(file *os.File, _ LockLevel) _ErrorCode {
- rc := osLock(file, unix.LOCK_SH|unix.LOCK_NB, _IOERR_RDLOCK)
+ rc := osFlock(file, unix.LOCK_SH|unix.LOCK_NB, _IOERR_RDLOCK)
if rc == _BUSY {
// The documentation states that a lock is downgraded by
// releasing the previous lock then acquiring the new lock.
@@ -66,7 +66,36 @@ func osCheckReservedLock(file *os.File) (bool, _ErrorCode) {
return lock == unix.F_WRLCK, rc
}
-func osLock(file *os.File, how int, def _ErrorCode) _ErrorCode {
+func osFlock(file *os.File, how int, def _ErrorCode) _ErrorCode {
err := unix.Flock(int(file.Fd()), how)
return osLockErrorCode(err, def)
}
+
+func osReadLock(file *os.File, start, len int64) _ErrorCode {
+ return osLock(file, unix.F_RDLCK, start, len, _IOERR_RDLOCK)
+}
+
+func osWriteLock(file *os.File, start, len int64) _ErrorCode {
+ return osLock(file, unix.F_WRLCK, start, len, _IOERR_LOCK)
+}
+
+func osLock(file *os.File, typ int16, start, len int64, def _ErrorCode) _ErrorCode {
+ err := unix.FcntlFlock(file.Fd(), unix.F_SETLK, &unix.Flock_t{
+ Type: typ,
+ Start: start,
+ Len: len,
+ })
+ return osLockErrorCode(err, def)
+}
+
+func osUnlock(file *os.File, start, len int64) _ErrorCode {
+ err := unix.FcntlFlock(file.Fd(), unix.F_SETLK, &unix.Flock_t{
+ Type: unix.F_UNLCK,
+ Start: start,
+ Len: len,
+ })
+ if err != nil {
+ return _IOERR_UNLOCK
+ }
+ return _OK
+}
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go
index 7d809b223..07de7c3d8 100644
--- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go
@@ -56,16 +56,12 @@ func osAllocate(file *os.File, size int64) error {
return file.Truncate(size)
}
-func osUnlock(file *os.File, start, len int64) _ErrorCode {
- err := unix.FcntlFlock(file.Fd(), _F_OFD_SETLK, &unix.Flock_t{
- Type: unix.F_UNLCK,
- Start: start,
- Len: len,
- })
- if err != nil {
- return _IOERR_UNLOCK
- }
- return _OK
+func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
+ return osLock(file, unix.F_RDLCK, start, len, timeout, _IOERR_RDLOCK)
+}
+
+func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
+ return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK)
}
func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, def _ErrorCode) _ErrorCode {
@@ -88,10 +84,14 @@ func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, d
return osLockErrorCode(err, def)
}
-func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
- return osLock(file, unix.F_RDLCK, start, len, timeout, _IOERR_RDLOCK)
-}
-
-func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
- return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK)
+func osUnlock(file *os.File, start, len int64) _ErrorCode {
+ err := unix.FcntlFlock(file.Fd(), _F_OFD_SETLK, &unix.Flock_t{
+ Type: unix.F_UNLCK,
+ Start: start,
+ Len: len,
+ })
+ if err != nil {
+ return _IOERR_UNLOCK
+ }
+ return _OK
}
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go
index b00a1865b..7a9c38897 100644
--- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go
@@ -7,6 +7,8 @@
"io/fs"
"os"
"sync"
+
+ "github.com/ncruces/go-sqlite3/internal/dotlk"
)
var (
@@ -28,12 +30,10 @@ func osGetSharedLock(file *os.File) _ErrorCode {
name := file.Name()
locker := vfsDotLocks[name]
if locker == nil {
- f, err := os.OpenFile(name+".lock", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
- f.Close()
- if errors.Is(err, fs.ErrExist) {
- return _BUSY // Another process has the lock.
- }
- if err != nil {
+ if err := dotlk.TryLock(name + ".lock"); err != nil {
+ if errors.Is(err, fs.ErrExist) {
+ return _BUSY // Another process has the lock.
+ }
return _IOERR_LOCK
}
locker = &vfsDotLocker{}
@@ -114,8 +114,7 @@ func osReleaseLock(file *os.File, state LockLevel) _ErrorCode {
}
if locker.shared == 1 {
- err := os.Remove(name + ".lock")
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
+ if err := dotlk.Unlock(name + ".lock"); err != nil {
return _IOERR_UNLOCK
}
delete(vfsDotLocks, name)
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go
index f5841fc20..6199c7b00 100644
--- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go
@@ -3,7 +3,6 @@
package vfs
import (
- "math/rand"
"os"
"time"
@@ -22,6 +21,30 @@ func osAllocate(file *os.File, size int64) error {
return unix.Fallocate(int(file.Fd()), 0, 0, size)
}
+func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
+ return osLock(file, unix.F_RDLCK, start, len, timeout, _IOERR_RDLOCK)
+}
+
+func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
+ return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK)
+}
+
+func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, def _ErrorCode) _ErrorCode {
+ lock := unix.Flock_t{
+ Type: typ,
+ Start: start,
+ Len: len,
+ }
+ var err error
+ switch {
+ case timeout < 0:
+ err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLKW, &lock)
+ default:
+ err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock)
+ }
+ return osLockErrorCode(err, def)
+}
+
func osUnlock(file *os.File, start, len int64) _ErrorCode {
err := unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &unix.Flock_t{
Type: unix.F_UNLCK,
@@ -33,40 +56,3 @@ func osUnlock(file *os.File, start, len int64) _ErrorCode {
}
return _OK
}
-
-func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, def _ErrorCode) _ErrorCode {
- lock := unix.Flock_t{
- Type: typ,
- Start: start,
- Len: len,
- }
- var err error
- switch {
- case timeout == 0:
- err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock)
- case timeout < 0:
- err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLKW, &lock)
- default:
- before := time.Now()
- for {
- err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock)
- if errno, _ := err.(unix.Errno); errno != unix.EAGAIN {
- break
- }
- if time.Since(before) > timeout {
- break
- }
- const sleepIncrement = 1024*1024 - 1 // power of two, ~1ms
- time.Sleep(time.Duration(rand.Int63() & sleepIncrement))
- }
- }
- return osLockErrorCode(err, def)
-}
-
-func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
- return osLock(file, unix.F_RDLCK, start, len, timeout, _IOERR_RDLOCK)
-}
-
-func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
- return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK)
-}
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go
index 2872201b0..0398f4760 100644
--- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go
@@ -45,6 +45,7 @@ func osGetExclusiveLock(file *os.File, state *LockLevel) _ErrorCode {
osUnlock(file, _SHARED_FIRST, _SHARED_SIZE)
// Acquire the EXCLUSIVE lock.
+ // Can't wait here, because the file is not OVERLAPPED.
rc := osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, 0)
if rc != _OK {
@@ -106,6 +107,27 @@ func osCheckReservedLock(file *os.File) (bool, _ErrorCode) {
return false, rc
}
+func osReadLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode {
+ return osLock(file, 0, start, len, timeout, _IOERR_RDLOCK)
+}
+
+func osWriteLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode {
+ return osLock(file, windows.LOCKFILE_EXCLUSIVE_LOCK, start, len, timeout, _IOERR_LOCK)
+}
+
+func osLock(file *os.File, flags, start, len uint32, timeout time.Duration, def _ErrorCode) _ErrorCode {
+ var err error
+ switch {
+ case timeout == 0:
+ err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len)
+ case timeout < 0:
+ err = osLockEx(file, flags, start, len)
+ default:
+ err = osLockExTimeout(file, flags, start, len, timeout)
+ }
+ return osLockErrorCode(err, def)
+}
+
func osUnlock(file *os.File, start, len uint32) _ErrorCode {
err := windows.UnlockFileEx(windows.Handle(file.Fd()),
0, len, 0, &windows.Overlapped{Offset: start})
@@ -118,52 +140,40 @@ func osUnlock(file *os.File, start, len uint32) _ErrorCode {
return _OK
}
-func osLock(file *os.File, flags, start, len uint32, timeout time.Duration, def _ErrorCode) _ErrorCode {
- var err error
- switch {
- case timeout == 0:
- err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len, 0)
- case timeout < 0:
- err = osLockEx(file, flags, start, len, 0)
- default:
- var event windows.Handle
- event, err = windows.CreateEvent(nil, 1, 0, nil)
- if err != nil {
- break
- }
- defer windows.CloseHandle(event)
-
- err = osLockEx(file, flags, start, len, event)
- if err == windows.ERROR_IO_PENDING {
- rc, serr := windows.WaitForSingleObject(event, uint32(timeout/time.Millisecond))
- if rc == windows.WAIT_OBJECT_0 {
- return _OK
- }
- if serr != nil {
- err = serr
- } else {
- err = windows.Errno(rc)
- }
- windows.CancelIo(windows.Handle(file.Fd()))
- }
- }
- return osLockErrorCode(err, def)
-}
-
-func osLockEx(file *os.File, flags, start, len uint32, event windows.Handle) error {
+func osLockEx(file *os.File, flags, start, len uint32) error {
return windows.LockFileEx(windows.Handle(file.Fd()), flags,
- 0, len, 0, &windows.Overlapped{
- Offset: start,
- HEvent: event,
- })
+ 0, len, 0, &windows.Overlapped{Offset: start})
}
-func osReadLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode {
- return osLock(file, 0, start, len, timeout, _IOERR_RDLOCK)
-}
+func osLockExTimeout(file *os.File, flags, start, len uint32, timeout time.Duration) error {
+ event, err := windows.CreateEvent(nil, 1, 0, nil)
+ if err != nil {
+ return err
+ }
+ defer windows.CloseHandle(event)
-func osWriteLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode {
- return osLock(file, windows.LOCKFILE_EXCLUSIVE_LOCK, start, len, timeout, _IOERR_LOCK)
+ fd := windows.Handle(file.Fd())
+ overlapped := &windows.Overlapped{
+ Offset: start,
+ HEvent: event,
+ }
+
+ err = windows.LockFileEx(fd, flags, 0, len, 0, overlapped)
+ if err != windows.ERROR_IO_PENDING {
+ return err
+ }
+
+ ms := (timeout + time.Millisecond - 1) / time.Millisecond
+ rc, err := windows.WaitForSingleObject(event, uint32(ms))
+ if rc == windows.WAIT_OBJECT_0 {
+ return nil
+ }
+ defer windows.CancelIoEx(fd, overlapped)
+
+ if err != nil {
+ return err
+ }
+ return windows.Errno(rc)
}
func osLockErrorCode(err error, def _ErrorCode) _ErrorCode {
@@ -175,8 +185,8 @@ func osLockErrorCode(err error, def _ErrorCode) _ErrorCode {
switch errno {
case
windows.ERROR_LOCK_VIOLATION,
- windows.ERROR_IO_PENDING,
windows.ERROR_OPERATION_ABORTED,
+ windows.ERROR_IO_PENDING,
windows.WAIT_TIMEOUT:
return _BUSY
}
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go
index 8e7f27084..10d6dbf61 100644
--- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go
@@ -4,7 +4,9 @@
import (
"context"
+ "errors"
"io"
+ "io/fs"
"os"
"sync"
@@ -71,23 +73,21 @@ func (s *vfsShm) shmOpen() _ErrorCode {
return _OK
}
- // Always open file read-write, as it will be shared.
- f, err := os.OpenFile(s.path,
- os.O_RDWR|os.O_CREATE|_O_NOFOLLOW, 0666)
- if err != nil {
- return _CANTOPEN
- }
- // Closes file if it's not nil.
+ var f *os.File
+ // Close file on error.
+ // Keep this here to avoid confusing checklocks.
defer func() { f.Close() }()
- fi, err := f.Stat()
- if err != nil {
- return _IOERR_FSTAT
- }
-
vfsShmListMtx.Lock()
defer vfsShmListMtx.Unlock()
+ // Stat file without opening it.
+ // Closing it would release all POSIX locks on it.
+ fi, err := os.Stat(s.path)
+ if err != nil && !errors.Is(err, fs.ErrNotExist) {
+ return _IOERR_FSTAT
+ }
+
// Find a shared file, increase the reference count.
for _, g := range vfsShmList {
if g != nil && os.SameFile(fi, g.info) {
@@ -97,13 +97,33 @@ func (s *vfsShm) shmOpen() _ErrorCode {
}
}
- // Lock and truncate the file.
- // The lock is only released by closing the file.
- if rc := osLock(f, unix.LOCK_EX|unix.LOCK_NB, _IOERR_LOCK); rc != _OK {
+ // Always open file read-write, as it will be shared.
+ f, err = os.OpenFile(s.path,
+ os.O_RDWR|os.O_CREATE|_O_NOFOLLOW, 0666)
+ if err != nil {
+ return _CANTOPEN
+ }
+
+ // Dead man's switch.
+ if lock, rc := osTestLock(f, _SHM_DMS, 1); rc != _OK {
+ return _IOERR_LOCK
+ } else if lock == unix.F_WRLCK {
+ return _BUSY
+ } else if lock == unix.F_UNLCK {
+ if rc := osWriteLock(f, _SHM_DMS, 1); rc != _OK {
+ return rc
+ }
+ if err := f.Truncate(0); err != nil {
+ return _IOERR_SHMOPEN
+ }
+ }
+ if rc := osReadLock(f, _SHM_DMS, 1); rc != _OK {
return rc
}
- if err := f.Truncate(0); err != nil {
- return _IOERR_SHMOPEN
+
+ fi, err = f.Stat()
+ if err != nil {
+ return _IOERR_FSTAT
}
// Add the new shared file.
@@ -157,7 +177,30 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
s.Lock()
defer s.Unlock()
- return s.shmMemLock(offset, n, flags)
+
+ // Check if we could obtain/release the lock locally.
+ rc := s.shmMemLock(offset, n, flags)
+ if rc != _OK {
+ return rc
+ }
+
+ // Obtain/release the appropriate file lock.
+ switch {
+ case flags&_SHM_UNLOCK != 0:
+ return osUnlock(s.File, _SHM_BASE+int64(offset), int64(n))
+ case flags&_SHM_SHARED != 0:
+ rc = osReadLock(s.File, _SHM_BASE+int64(offset), int64(n))
+ case flags&_SHM_EXCLUSIVE != 0:
+ rc = osWriteLock(s.File, _SHM_BASE+int64(offset), int64(n))
+ default:
+ panic(util.AssertErr())
+ }
+
+ // Release the local lock.
+ if rc != _OK {
+ s.shmMemLock(offset, n, flags^(_SHM_UNLOCK|_SHM_LOCK))
+ }
+ return rc
}
func (s *vfsShm) shmUnmap(delete bool) {
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go
index e302db7e6..17fefe562 100644
--- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go
@@ -6,11 +6,11 @@
"context"
"errors"
"io/fs"
- "os"
"sync"
"github.com/tetratelabs/wazero/api"
+ "github.com/ncruces/go-sqlite3/internal/dotlk"
"github.com/ncruces/go-sqlite3/internal/util"
)
@@ -58,8 +58,7 @@ func (s *vfsShm) Close() error {
return nil
}
- err := os.Remove(s.path)
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
+ if err := dotlk.Unlock(s.path); err != nil {
return _IOERR_UNLOCK
}
delete(vfsShmList, s.path)
@@ -82,9 +81,8 @@ func (s *vfsShm) shmOpen() _ErrorCode {
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)
+ // Dead man's switch.
+ err := dotlk.LockShm(s.path)
if errors.Is(err, fs.ErrExist) {
return _BUSY
}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 661c05943..e0aef8e18 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -24,7 +24,7 @@ codeberg.org/gruf/go-fastcopy
# codeberg.org/gruf/go-fastpath/v2 v2.0.0
## explicit; go 1.14
codeberg.org/gruf/go-fastpath/v2
-# codeberg.org/gruf/go-ffmpreg v0.6.2
+# codeberg.org/gruf/go-ffmpreg v0.6.4
## explicit; go 1.22.0
codeberg.org/gruf/go-ffmpreg/embed
codeberg.org/gruf/go-ffmpreg/wasm
@@ -520,12 +520,13 @@ github.com/modern-go/reflect2
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
## explicit
github.com/munnerz/goautoneg
-# github.com/ncruces/go-sqlite3 v0.21.0
+# github.com/ncruces/go-sqlite3 v0.21.2
## explicit; go 1.21
github.com/ncruces/go-sqlite3
github.com/ncruces/go-sqlite3/driver
github.com/ncruces/go-sqlite3/embed
github.com/ncruces/go-sqlite3/internal/alloc
+github.com/ncruces/go-sqlite3/internal/dotlk
github.com/ncruces/go-sqlite3/internal/util
github.com/ncruces/go-sqlite3/util/osutil
github.com/ncruces/go-sqlite3/util/sql3util
diff --git a/web/template/page_stylesheets.tmpl b/web/template/page_stylesheets.tmpl
index 9234607f8..9ccc65c13 100644
--- a/web/template/page_stylesheets.tmpl
+++ b/web/template/page_stylesheets.tmpl
@@ -32,10 +32,16 @@
{{- range .stylesheets }}
{{- end }}
+{{- if .instance.CustomCSS }}
+
+{{- end }}
{{- range .stylesheets }}
{{- end }}
+{{- if .instance.CustomCSS }}
+
+{{- end }}
{{- end }}
\ No newline at end of file