Files
Pikachu Renandpikachuren f2dcf4a86b
Beta Release builds / Beta Release Changelog (push) Failing after 55s
Beta Release builds / Beta Release (, , md5, !(*musl*|*windows-arm64*|*windows7-*|*android*|*freebsd*)) (push) Skipped
Beta Release builds / Beta Release (, , md5-android, false, android-*) (push) Skipped
Beta Release builds / Beta Release (, , md5-freebsd, false, freebsd-*) (push) Skipped
Beta Release builds / Beta Release (, , md5-windows-arm64, false, windows-arm64) (push) Skipped
Beta Release builds / Beta Release (, -tags=sqlite_cgo_compat, md5-windows7, false, windows7-*) (push) Skipped
Beta Release builds / Beta Release (-ldflags=-linkmode external -extldflags '-static -fpic', , md5-linux-musl, true, linux-!(arm*|mips|mips64|mipsle|mips64le|loong64)-musl*) (push) Skipped
Beta Release builds / Beta Release (-ldflags=-linkmode external -extldflags '-static -fpic', , md5-linux-musl-arm, true, linux-arm*-musl*) (push) Skipped
Beta Release builds / Beta Release (-ldflags=-linkmode external -extldflags '-static -fpic', , md5-linux-musl-mips, true, linux-(mips|mips64|mipsle|mips64le|loong64)-musl*) (push) Skipped
Sync to Gitee / Sync GitHub to Gitee (push) Failing after 57s
Beta Release (Docker) / Build Binaries for Docker Release (Beta) (push) Failing after 13m2s
Beta Release (Docker) / Release Docker image (Beta) (aio, INSTALL_FFMPEG=true INSTALL_ARIA2=true , aio, suffix=-aio,onlatest=true) (push) Skipped
Beta Release (Docker) / Release Docker image (Beta) (aria2, INSTALL_ARIA2=true, aria2, suffix=-aria2,onlatest=true) (push) Skipped
Beta Release (Docker) / Release Docker image (Beta) (base, , latest, ) (push) Skipped
Beta Release (Docker) / Release Docker image (Beta) (ffmpeg, INSTALL_FFMPEG=true, ffmpeg, suffix=-ffmpeg,onlatest=true) (push) Skipped
fix(storage): persist rotated tokens reliably and enable sqlite WAL (#3344)
* fix(storage): persist rotated tokens reliably and enable sqlite WAL

sqlite: build the DSN per driver. The default pure-Go build (glebarez/go-sqlite) only understands '_pragma=' parameters, so the mattn style '_journal=WAL&_vacuum=incremental' was silently ignored and the database kept running in rollback-journal mode with the driver default 5000ms busy timeout. Verified: journal_mode=delete,busy_timeout=5000 before, journal_mode=wal,busy_timeout=10000 after.

op: retry storage saves on transient SQLITE_BUSY. Drivers persist rotating credentials through MustSaveDriverStorage (115 Open, PikPak, OneDrive...); the previous token is invalidated by the server as soon as a new one is issued, so a single failed write left the storage with a dead token after a restart.

115_open: never overwrite the refresh token with an empty value and refresh up front when only a refresh token is configured, so the SDK cannot send a refresh request without the parameter (which 115 reports as '40100000 参数错误' or '40140114 refresh_token 格式错误').

* fix(115_open): restore sdk client state on token refresh

The SDK assigns the refresh response to its own fields before invoking onRefreshToken, so a response without refresh_token also cleared the value used by the next refresh request. Guarding only d.Addition was not enough: the running client kept sending an empty parameter.

Write the resolved pair back to the client, and add regression tests covering both the missing-field and the normal rotation cases.

---------

Co-authored-by: pikachuren <pikachuren@example.com>
2026-11-13 11:52:16 +08:00

105 lines
3.0 KiB
Go

package bootstrap
import (
"fmt"
stdlog "log"
"strings"
"time"
"github.com/OpenListTeam/OpenList/v4/cmd/flags"
"github.com/OpenListTeam/OpenList/v4/internal/conf"
"github.com/OpenListTeam/OpenList/v4/internal/db"
log "github.com/sirupsen/logrus"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
func InitDB() {
logLevel := logger.Silent
if flags.Debug || flags.Dev {
logLevel = logger.Info
}
newLogger := logger.New(
stdlog.New(log.StandardLogger().Out, "\r\n", stdlog.LstdFlags),
logger.Config{
SlowThreshold: time.Second,
LogLevel: logLevel,
IgnoreRecordNotFoundError: true,
Colorful: true,
},
)
gormConfig := &gorm.Config{
NamingStrategy: schema.NamingStrategy{
TablePrefix: conf.Conf.Database.TablePrefix,
},
Logger: newLogger,
}
var dB *gorm.DB
var err error
if flags.Dev {
dB, err = gorm.Open(openSQLite("file::memory:?cache=shared"), gormConfig)
conf.Conf.Database.Type = "sqlite3"
} else {
database := conf.Conf.Database
switch database.Type {
case "sqlite3":
{
if !(strings.HasSuffix(database.DBFile, ".db") && len(database.DBFile) > 3) {
log.Fatalf("db name error.")
}
dB, err = gorm.Open(openSQLite(database.DBFile), gormConfig)
}
case "mysql":
{
dsn := database.DSN
if dsn == "" {
//[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]
dsn = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&tls=%s",
database.User, database.Password, database.Host, database.Port, database.Name, database.SSLMode)
}
dB, err = gorm.Open(mysql.Open(dsn), gormConfig)
}
case "postgres":
{
dsn := database.DSN
if dsn == "" {
if database.Password != "" {
dsn = fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=%s TimeZone=Asia/Shanghai",
database.Host, database.User, database.Password, database.Name, database.Port, database.SSLMode)
} else {
dsn = fmt.Sprintf("host=%s user=%s dbname=%s port=%d sslmode=%s TimeZone=Asia/Shanghai",
database.Host, database.User, database.Name, database.Port, database.SSLMode)
}
}
dB, err = gorm.Open(postgres.Open(dsn), gormConfig)
}
default:
log.Fatalf("not supported database type: %s", database.Type)
}
}
if err != nil {
log.Fatalf("failed to connect database:%s", err.Error())
}
db.Init(dB)
}
// appendDSNParams appends SQLite DSN query parameters while keeping the ones
// already present. The accepted pragma syntax differs between the pure-Go and
// the cgo builds, so each build supplies its own parameter list.
func appendDSNParams(dsn, params string) string {
if params == "" {
return dsn
}
switch {
case strings.HasSuffix(dsn, "?"), strings.HasSuffix(dsn, "&"):
return dsn + params
case strings.Contains(dsn, "?"):
return dsn + "&" + params
default:
return dsn + "?" + params
}
}