Skip to content

Commit

Permalink
Go: Add sqlite support (#83).
Browse files Browse the repository at this point in the history
Add sqlite support for long-season storage interface.
  • Loading branch information
thinkofher authored Nov 12, 2021
2 parents b437f4f + cb3a8f9 commit 8547afd
Show file tree
Hide file tree
Showing 19 changed files with 3,082 additions and 181 deletions.
17 changes: 6 additions & 11 deletions cmd/long-season/long-season.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/cristalhq/jwt/v3"
"github.com/go-chi/cors"
bolt "go.etcd.io/bbolt"

"github.com/hakierspejs/long-season/pkg/services/config"
"github.com/hakierspejs/long-season/pkg/services/handlers"
Expand All @@ -19,32 +18,28 @@ import (
"github.com/hakierspejs/long-season/pkg/services/session"
"github.com/hakierspejs/long-season/pkg/services/status"
"github.com/hakierspejs/long-season/pkg/storage"
"github.com/hakierspejs/long-season/pkg/storage/memory"
"github.com/hakierspejs/long-season/pkg/storage/abstract"
"github.com/hakierspejs/long-season/pkg/storage/temp"
"github.com/hakierspejs/long-season/web"
)

func main() {
config := config.Env()

boltDB, err := bolt.Open(config.DatabasePath, 0666, nil)
if err != nil {
log.Fatal(err.Error())
}
defer boltDB.Close()

factoryStorage, err := memory.New(boltDB)
factoryStorage, closer, err := abstract.Factory(config.DatabasePath, config.DatabaseType)
if err != nil {
log.Fatal(err.Error())
}
defer closer()

onlineUsersStorage := temp.NewOnlineUsers()
statusTx := temp.NewStatusTx()

ctx := context.Background()
macChannel, macDeamon := status.NewDaemon(ctx, status.DaemonArgs{
OnlineUsers: onlineUsersStorage,
Devices: factoryStorage.Devices(),
Counters: factoryStorage.StatusTx(),
Counters: statusTx,
RefreshTime: config.RefreshTime,
SingleAddrTTL: config.SingleAddrTTL,
})
Expand Down Expand Up @@ -88,7 +83,7 @@ func main() {
Opener: opener,
Users: factoryStorage.Users(),
Devices: factoryStorage.Devices(),
StatusTx: factoryStorage.StatusTx(),
StatusTx: statusTx,
TwoFactor: factoryStorage.TwoFactor(),
OnlineUsers: onlineUsersStorage,
UserAdapter: userAdapter,
Expand Down
191 changes: 29 additions & 162 deletions cmd/short-season/short-season.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,83 +3,29 @@ package main
import (
"bufio"
"bytes"
"context"
"encoding/gob"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strconv"

"github.com/urfave/cli/v2"
bolt "go.etcd.io/bbolt"
"golang.org/x/crypto/bcrypt"

"github.com/hakierspejs/long-season/pkg/models"
"github.com/hakierspejs/long-season/pkg/services/exim"
"github.com/hakierspejs/long-season/pkg/services/users"
"github.com/hakierspejs/long-season/pkg/storage"
"github.com/hakierspejs/long-season/pkg/storage/abstract"
"github.com/hakierspejs/long-season/pkg/storage/memory"
"golang.org/x/crypto/bcrypt"

"github.com/urfave/cli/v2"
bolt "go.etcd.io/bbolt"
)

const (
usersBucket = "ls::users"
devicesBucket = "ls::devices"
)

func readOldUsers(db *bolt.DB) ([]models.User, error) {
result := []models.User{}

if err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(usersBucket))

return b.ForEach(func(k, v []byte) error {
user := new(models.User)
buff := bytes.NewBuffer(v)
// Check if given key is an integer.
if _, err := strconv.Atoi(string(k)); err == nil {
err := gob.NewDecoder(buff).Decode(user)
if err != nil {
return fmt.Errorf("decoding user from gob failed: %w", err)
}
}
result = append(result, *user)
return nil
})
}); err != nil {
return result, err
}

return result, nil
}

func readOldDevices(db *bolt.DB) ([]models.Device, error) {
result := []models.Device{}

if err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(devicesBucket))

return b.ForEach(func(k, v []byte) error {
device := new(models.Device)
buff := bytes.NewBuffer(v)
// Check if given key is an integer.
if _, err := strconv.Atoi(string(k)); err == nil {
err := gob.NewDecoder(buff).Decode(device)
if err != nil {
return fmt.Errorf("decoding user from gob failed: %w", err)
}
}
result = append(result, *device)
return nil
})
}); err != nil {
return result, err
}

return result, nil
}

func putRequest(url string, headers map[string]string, data io.Reader) (*http.Response, error) {
client := &http.Client{}
req, err := http.NewRequest(http.MethodPut, url, data)
Expand All @@ -102,7 +48,7 @@ type body struct {
Addresses []string `json:"addresses"`
}

func usersStorage(ctx *cli.Context) (*memory.UsersStorage, func(), error) {
func usersStorage(ctx *cli.Context) (storage.Users, func(), error) {
if ctx.String("database") == "" {
return nil, nil, fmt.Errorf("database flag is not set. see admin command.")
}
Expand Down Expand Up @@ -179,89 +125,22 @@ func app() *cli.App {
return nil
},
},
{
Name: "migrate",
Usage: "migrate old bolt database to new long-season version",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "old-database",
Aliases: []string{"o", "od", "odb"},
Usage: "path to old bolt database",
Value: "long-season.db",
},
&cli.StringFlag{
Name: "new-database",
Aliases: []string{"n", "nd", "ndb"},
Usage: "name of new database that will be created",
Value: "new-long-season.db",
},
},
Action: func(ctx *cli.Context) error {
old := ctx.String("old-database")

oldDB, err := bolt.Open(old, 0666, nil)
if err != nil {
return err
}
defer oldDB.Close()

users, err := readOldUsers(oldDB)
if err != nil {
return err
}

devices, err := readOldDevices(oldDB)
if err != nil {
return err
}

newDBFilename := ctx.String("new-database")
newDB, err := bolt.Open(newDBFilename, 0666, nil)
if err != nil {
return err
}

factory, err := memory.New(newDB)
if err != nil {
return err
}

usersStorage := factory.Users()
devicesStorage := factory.Devices()

localCtx := context.Background()
for _, user := range users {
_, err = usersStorage.New(localCtx, storage.UserEntry{
ID: user.ID,
Nickname: user.Nickname,
HashedPassword: user.Password,
Private: user.Private,
})
if err != nil {
return err
}
}

for _, device := range devices {
_, err = devicesStorage.NewByOwner(localCtx, device.Owner, device)
if err != nil {
return err
}
}

return nil
},
},
{
Name: "admin",
Usage: "set of administration tools for managing content of long-season database",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "database",
Aliases: []string{"d", "db"},
Usage: "path to bolt database",
Usage: "path to database",
Value: "long-season.db",
},
&cli.StringFlag{
Name: "database-type",
Aliases: []string{"dt", "dbt"},
Usage: "type of database",
Value: "bolt",
},
},
Action: func(ctx *cli.Context) error {
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
Expand All @@ -271,25 +150,19 @@ func app() *cli.App {
Name: "export",
Usage: "export all data from database as single json object to stdout",
Action: func(ctx *cli.Context) error {
if ctx.String("database") == "" {
return fmt.Errorf("database flag is not set. see admin command.")
}

boltDB, err := bolt.Open(ctx.String("database"), 0666, nil)
if err != nil {
return fmt.Errorf("bolt.Open: %w", err)
}
defer boltDB.Close()
dbPath := ctx.String("database")
dbType := ctx.String("database-type")

factoryStorage, err := memory.New(boltDB)
factory, closer, err := abstract.Factory(dbPath, dbType)
if err != nil {
return fmt.Errorf("memory.New: %w", err)
return fmt.Errorf("abstract.Factory: %w", err)
}
defer closer()

dump, err := exim.Export(ctx.Context, exim.ExportRequest{
UsersStorage: factoryStorage.Users(),
DevicesStorage: factoryStorage.Devices(),
TwoFactorStorage: factoryStorage.TwoFactor(),
UsersStorage: factory.Users(),
DevicesStorage: factory.Devices(),
TwoFactorStorage: factory.TwoFactor(),
})
if err != nil {
return fmt.Errorf("exim.Export: %w", err)
Expand All @@ -306,20 +179,14 @@ func app() *cli.App {
Name: "import",
Usage: "import data as json object from stdin into database",
Action: func(ctx *cli.Context) error {
if ctx.String("database") == "" {
return fmt.Errorf("database flag is not set. see admin command.")
}
dbPath := ctx.String("database")
dbType := ctx.String("database-type")

boltDB, err := bolt.Open(ctx.String("database"), 0666, nil)
factory, closer, err := abstract.Factory(dbPath, dbType)
if err != nil {
return fmt.Errorf("bolt.Open: %w", err)
}
defer boltDB.Close()

factoryStorage, err := memory.New(boltDB)
if err != nil {
return fmt.Errorf("memory.New: %w", err)
return fmt.Errorf("abstract.Factory: %w", err)
}
defer closer()

dump := exim.Data{}

Expand All @@ -329,9 +196,9 @@ func app() *cli.App {

err = exim.Import(ctx.Context, exim.ImportRequest{
Dump: dump,
UsersStorage: factoryStorage.Users(),
DevicesStorage: factoryStorage.Devices(),
TwoFactorStorage: factoryStorage.TwoFactor(),
UsersStorage: factory.Users(),
DevicesStorage: factory.Devices(),
TwoFactorStorage: factory.TwoFactor(),
})
if err != nil {
return fmt.Errorf("exim.Import: %w", err)
Expand Down
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ require (
github.com/cristalhq/jwt/v3 v3.0.4
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/cors v1.1.1
github.com/google/uuid v1.1.2
github.com/golang-migrate/migrate/v4 v4.15.1
github.com/google/uuid v1.3.0
github.com/matryer/is v1.4.0
github.com/pquerna/otp v1.3.0
github.com/thinkofher/horror v0.1.2
github.com/urfave/cli/v2 v2.3.0
go.etcd.io/bbolt v1.3.5
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
modernc.org/sqlite v1.13.3 // indirect
)
Loading

0 comments on commit 8547afd

Please sign in to comment.