feat: support mysql/postgres/sqlite3

This commit is contained in:
face.wsl 2022-11-21 19:25:48 +08:00
parent 8c8be1cdf2
commit 53265fd64b
10 changed files with 159 additions and 140 deletions

View File

@ -17,7 +17,7 @@ import (
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/storage"
"github.com/filebrowser/filebrowser/v2/storage/bolt"
"github.com/filebrowser/filebrowser/v2/storage/psql"
"github.com/filebrowser/filebrowser/v2/storage/sql"
)
func checkErr(err error) {
@ -107,49 +107,22 @@ func openBoltDB(path string, cfg pythonConfig) (pythonData, Closeable) {
return data, db
}
func isPsqlDB(path string) bool {
return strings.HasPrefix(path, "postgres:")
}
func openPsqlDB(path string, cfg pythonConfig) (pythonData, Closeable) {
data := pythonData{hadDB: true}
db, err := psql.ConnectDB(path)
if err != nil {
data.store, err = psql.NewStorage(db)
} else {
log.Fatal("Fail to open psql database " + path)
}
return data, db
}
func openDB(path string, cfg pythonConfig) (pythonData, Closeable) {
if isPsqlDB(path) {
return openPsqlDB(path, cfg)
if sql.IsDBPath(path) {
data := pythonData{hadDB: true}
db, err := sql.OpenDB(path)
if err != nil {
data.store, err = sql.NewStorage(db)
} else {
log.Fatal("Fail to open database " + path)
}
return data, db
}
return openBoltDB(path, cfg)
}
func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
return func(cmd *cobra.Command, args []string) {
// data := pythonData{hadDB: true}
// path := getParam(cmd.Flags(), "database")
// exists, err := dbExists(path)
// if err != nil {
// panic(err)
// } else if exists && cfg.noDB {
// log.Fatal(path + " already exists")
// } else if !exists && !cfg.noDB && !cfg.allowNoDB {
// log.Fatal(path + " does not exist. Please run 'filebrowser config init' first.")
// }
// data.hadDB = exists
// db, err := storm.Open(path)
// checkErr(err)
// defer db.Close()
// data.store, err = bolt.NewStorage(db)
// checkErr(err)
data, db := openDB(getParam(cmd.Flags(), "database"), cfg)
defer db.Close()
fn(cmd, args, data)

2
go.mod
View File

@ -41,6 +41,7 @@ require (
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-errors/errors v1.1.1 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect
github.com/golang/snappy v0.0.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
@ -54,6 +55,7 @@ require (
github.com/lib/pq v1.10.7 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-runewidth v0.0.4 // indirect
github.com/mattn/go-sqlite3 v1.14.16 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.2 // indirect

4
go.sum
View File

@ -97,6 +97,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ=
github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
@ -210,6 +212,8 @@ github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tp
github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=

View File

@ -1,44 +0,0 @@
package psql
import (
"database/sql"
"github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/share"
"github.com/filebrowser/filebrowser/v2/storage"
"github.com/filebrowser/filebrowser/v2/users"
)
func ConnectDB(path string) (*sql.DB, error) {
db, err := sql.Open("postgres", path)
if err == nil {
return db, nil
}
return nil, err
}
// NewStorage creates a storage.Storage based on Bolt DB.
func NewStorage(db *sql.DB) (*storage.Storage, error) {
userStore := users.NewStorage(usersBackend{db: db})
shareStore := share.NewStorage(shareBackend{db: db})
settingsStore := settings.NewStorage(settingsBackend{db: db})
authStore := auth.NewStorage(authBackend{db: db}, userStore)
err := save(db, "version", 2) //nolint:gomnd
if err != nil {
return nil, err
}
return &storage.Storage{
Auth: authStore,
Users: userStore,
Share: shareStore,
Settings: settingsStore,
}, nil
}
func save(db *sql.DB, name string, from interface{}) error {
// return db.Set("config", name, from)
return nil
}

View File

@ -1,53 +0,0 @@
package psql
import (
"database/sql"
"log"
_ "github.com/lib/pq"
)
const (
// DB_DSN is a
DB_DSN = "postgres://postgres:12345678@127.0.0.1:5432/postgres?sslmode=disable"
)
func loadUsers() {
db, err := sql.Open("postgres", DB_DSN)
if err != nil {
log.Fatal("Fail to open a DB connection")
}
rows, err := db.Query("select id, name from users")
if err == nil {
log.Fatal("Fail to query db")
}
defer db.Close()
for rows.Next() {
id := ""
name := ""
err := rows.Scan(&id, &name)
if err != nil {
log.Fatal("Fail to scan db row")
}
}
}
func getConfig(db *sql.DB, key string, to interface{}) error {
var value string = ""
err := db.QueryRow("select value from config where name='" + key + "'").Scan(&value)
if err == nil {
return err
}
to = value
return nil
}
func setConfig(db *sql.DB, key string, to interface{}) error {
var value string = to.(string)
_, err := db.Exec("insert into config (name, value) values('" + key + "','" + value + "')")
if err == nil {
return nil
}
return err
}

View File

@ -1,7 +1,8 @@
package psql
package sql
import (
"database/sql"
"encoding/json"
"github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/errors"
@ -12,6 +13,12 @@ type authBackend struct {
db *sql.DB
}
func InitAuthTable(db *sql.DB) error {
sql := "create table if not exists appliction(key string primary key, value string)"
_, err := db.Exec(sql)
return err
}
func (s authBackend) Get(t settings.AuthMethod) (auth.Auther, error) {
var auther auth.Auther
@ -28,9 +35,17 @@ func (s authBackend) Get(t settings.AuthMethod) (auth.Auther, error) {
return nil, errors.ErrInvalidAuthMethod
}
return auther, getConfig(s.db, "auther", auther)
val := GetSetting(s.db, "auther")
if val == "" {
return auther, nil
}
return auther, json.Unmarshal([]byte(val), auther)
}
func (s authBackend) Save(a auth.Auther) error {
return setConfig(s.db, "author", a)
val, err := json.Marshal(a)
if err != nil {
return err
}
return SetSetting(s.db, "auther", string(val))
}

View File

@ -1,4 +1,4 @@
package psql
package sql
import (
"database/sql"
@ -13,6 +13,12 @@ type settingsBackend struct {
db *sql.DB
}
func InitSettingsTable(db *sql.DB) error {
sql := "create table if not exists settings(key string primary key, value string)"
_, err := db.Exec(sql)
return err
}
func userDefaultsFromString(s string) settings.UserDefaults {
if s == "" {
return settings.UserDefaults{}
@ -252,3 +258,39 @@ func (s settingsBackend) SaveServer(ss *settings.Server) error {
}
return nil
}
func SetSetting(db *sql.DB, key string, value string) error {
sql := "select count(key) from settings"
count := 0
err := db.QueryRow(sql).Scan(&count)
if err != nil {
return err
}
if count == 0 {
return addSetting(db, key, value)
}
return updateSetting(db, key, value)
}
func GetSetting(db *sql.DB, key string) string {
sql := "select value from settings where key = '" + key + "';"
value := ""
err := db.QueryRow(sql).Scan(&value)
if err != nil {
fmt.Printf("ERROR: " + err.Error())
return value
}
return value
}
func addSetting(db *sql.DB, key string, value string) error {
sql := "insert into settings(key, value) values('" + key + "', '" + value + "')"
_, err := db.Exec(sql)
return err
}
func updateSetting(db *sql.DB, key string, value string) error {
sql := "update settings set value = '" + value + "' where key = '" + key + "'"
_, err := db.Exec(sql)
return err
}

View File

@ -1,4 +1,4 @@
package psql
package sql
import (
"database/sql"
@ -16,6 +16,12 @@ type linkRecord interface {
Scan(dest ...interface{}) error
}
func InitShareTable(db *sql.DB) error {
sql := "create table if not exists share_links (path string, userid integer, expire integer, passwordhash string, token string)"
_, err := db.Exec(sql)
return err
}
func parseLink(row linkRecord) (*share.Link, error) {
path := ""
hash := ""

68
storage/sql/sql.go Normal file
View File

@ -0,0 +1,68 @@
package sql
import (
"database/sql"
"errors"
"strings"
"github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/share"
"github.com/filebrowser/filebrowser/v2/storage"
"github.com/filebrowser/filebrowser/v2/users"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
)
func IsDBPath(path string) bool {
prefixes := []string{"sqlite3", "postgres", "mysql"}
for _, prefix := range prefixes {
if strings.HasPrefix(path, prefix+"://") {
return true
}
}
return false
}
func OpenDB(path string) (*sql.DB, error) {
prefixes := []string{"sqlite3", "postgres", "mysql"}
for _, prefix := range prefixes {
if strings.HasPrefix(path, prefix) {
return connectDB(prefix, strings.TrimPrefix(path, prefix+"://"))
}
}
return nil, errors.New("Unsupported db scheme")
}
func connectDB(dbType string, path string) (*sql.DB, error) {
db, err := sql.Open(dbType, path)
if err == nil {
return db, nil
}
return nil, err
}
func NewStorage(db *sql.DB) (*storage.Storage, error) {
InitUserTable(db)
InitShareTable(db)
InitSettingsTable(db)
userStore := users.NewStorage(usersBackend{db: db})
shareStore := share.NewStorage(shareBackend{db: db})
settingsStore := settings.NewStorage(settingsBackend{db: db})
authStore := auth.NewStorage(authBackend{db: db}, userStore)
err := SetSetting(db, "version", "2")
if err != nil {
return nil, err
}
return &storage.Storage{
Auth: authStore,
Users: userStore,
Share: shareStore,
Settings: settingsStore,
}, nil
}

View File

@ -1,4 +1,4 @@
package psql
package sql
import (
"database/sql"
@ -88,6 +88,12 @@ func RulesToString(rules []rules.Rule) string {
return string(data)
}
func InitUserTable(db *sql.DB) error {
sql := "create table if not exists users (id integer primary key, username string, password string, scope string, lockpassword bool, viewmode string, perm string, commands string, sorting string, rules string);"
_, err := db.Exec(sql)
return err
}
func (s usersBackend) Get(id interface{}) (*users.User, error) {
userId := id.(uint)
username := ""