mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
checkpoint
This commit is contained in:
parent
9e7e7af04a
commit
2317ce87f3
3
db/db.go
3
db/db.go
@ -7,3 +7,6 @@ import "embed"
|
|||||||
|
|
||||||
//go:embed migrations-blockstore/*.sql
|
//go:embed migrations-blockstore/*.sql
|
||||||
var BlockstoreMigrationFS embed.FS
|
var BlockstoreMigrationFS embed.FS
|
||||||
|
|
||||||
|
//go:embed migrations-wstore/*.sql
|
||||||
|
var WStoreMigrationFS embed.FS
|
||||||
|
@ -15,6 +15,5 @@ CREATE TABLE db_tab (
|
|||||||
|
|
||||||
CREATE TABLE db_block (
|
CREATE TABLE db_block (
|
||||||
blockid varchar(36) PRIMARY KEY,
|
blockid varchar(36) PRIMARY KEY,
|
||||||
tabid varchar(36) NOT NULL, -- the tab this block belongs to
|
|
||||||
data json NOT NULL
|
data json NOT NULL
|
||||||
);
|
);
|
||||||
|
6
main.go
6
main.go
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/wavetermdev/thenextwave/pkg/service/blockservice"
|
"github.com/wavetermdev/thenextwave/pkg/service/blockservice"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/service/fileservice"
|
"github.com/wavetermdev/thenextwave/pkg/service/fileservice"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v3/pkg/application"
|
"github.com/wailsapp/wails/v3/pkg/application"
|
||||||
"github.com/wailsapp/wails/v3/pkg/events"
|
"github.com/wailsapp/wails/v3/pkg/events"
|
||||||
@ -104,6 +105,11 @@ func main() {
|
|||||||
log.Printf("error initializing blockstore: %v\n", err)
|
log.Printf("error initializing blockstore: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
err = wstore.InitWStore()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error initializing wstore: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
app := application.New(application.Options{
|
app := application.New(application.Options{
|
||||||
Name: "NextWave",
|
Name: "NextWave",
|
||||||
|
@ -4,8 +4,10 @@
|
|||||||
package blockservice
|
package blockservice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/blockcontroller"
|
"github.com/wavetermdev/thenextwave/pkg/blockcontroller"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
||||||
@ -41,7 +43,12 @@ func (bs *BlockService) CloseBlock(blockId string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BlockService) GetBlockData(blockId string) (map[string]any, error) {
|
func (bs *BlockService) GetBlockData(blockId string) (map[string]any, error) {
|
||||||
blockData := wstore.BlockMap.Get(blockId)
|
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
|
defer cancelFn()
|
||||||
|
blockData, err := wstore.BlockGet(ctx, blockId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting block data: %w", err)
|
||||||
|
}
|
||||||
if blockData == nil {
|
if blockData == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
package wstore
|
package wstore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ type Client struct {
|
|||||||
type Workspace struct {
|
type Workspace struct {
|
||||||
Lock *sync.Mutex `json:"-"`
|
Lock *sync.Mutex `json:"-"`
|
||||||
WorkspaceId string `json:"workspaceid"`
|
WorkspaceId string `json:"workspaceid"`
|
||||||
|
Name string `json:"name"`
|
||||||
TabIds []string `json:"tabids"`
|
TabIds []string `json:"tabids"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,3 +120,33 @@ func CreateWorkspace() (*Workspace, error) {
|
|||||||
}
|
}
|
||||||
return ws, nil
|
return ws, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EnsureWorkspace(ctx context.Context) error {
|
||||||
|
wsCount, err := WorkspaceCount(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error getting workspace count: %w", err)
|
||||||
|
}
|
||||||
|
if wsCount > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ws := &Workspace{
|
||||||
|
Lock: &sync.Mutex{},
|
||||||
|
WorkspaceId: uuid.New().String(),
|
||||||
|
Name: "default",
|
||||||
|
}
|
||||||
|
err = WorkspaceInsert(ctx, ws)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error inserting workspace: %w", err)
|
||||||
|
}
|
||||||
|
tab := &Tab{
|
||||||
|
Lock: &sync.Mutex{},
|
||||||
|
TabId: uuid.New().String(),
|
||||||
|
Name: "Tab 1",
|
||||||
|
BlockIds: []string{},
|
||||||
|
}
|
||||||
|
err = TabInsert(ctx, tab, ws.WorkspaceId)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error inserting tab: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
97
pkg/wstore/wstore_dbops.go
Normal file
97
pkg/wstore/wstore_dbops.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package wstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WorkspaceCount(ctx context.Context) (int, error) {
|
||||||
|
return WithTxRtn(ctx, func(tx *TxWrap) (int, error) {
|
||||||
|
query := "SELECT count(*) FROM workspace"
|
||||||
|
return tx.GetInt(query), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WorkspaceInsert(ctx context.Context, ws *Workspace) error {
|
||||||
|
if ws.WorkspaceId == "" {
|
||||||
|
ws.WorkspaceId = uuid.New().String()
|
||||||
|
}
|
||||||
|
return WithTx(ctx, func(tx *TxWrap) error {
|
||||||
|
query := "INSERT INTO workspace (workspaceid, data) VALUES (?, ?)"
|
||||||
|
tx.Exec(query, ws.WorkspaceId, TxJson(tx, ws))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WorkspaceGet(ctx context.Context, workspaceId string) (*Workspace, error) {
|
||||||
|
return WithTxRtn(ctx, func(tx *TxWrap) (*Workspace, error) {
|
||||||
|
query := "SELECT data FROM workspace WHERE workspaceid = ?"
|
||||||
|
jsonData := tx.GetString(query, workspaceId)
|
||||||
|
return TxReadJson[Workspace](tx, jsonData), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WorkspaceUpdate(ctx context.Context, ws *Workspace) error {
|
||||||
|
return WithTx(ctx, func(tx *TxWrap) error {
|
||||||
|
query := "UPDATE workspace SET data = ? WHERE workspaceid = ?"
|
||||||
|
tx.Exec(query, TxJson(tx, ws), ws.WorkspaceId)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func addTabToWorkspace(ctx context.Context, workspaceId string, tabId string) error {
|
||||||
|
return WithTx(ctx, func(tx *TxWrap) error {
|
||||||
|
ws, err := WorkspaceGet(tx.Context(), workspaceId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ws == nil {
|
||||||
|
return fmt.Errorf("workspace not found: %s", workspaceId)
|
||||||
|
}
|
||||||
|
ws.TabIds = append(ws.TabIds, tabId)
|
||||||
|
return WorkspaceUpdate(tx.Context(), ws)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TabInsert(ctx context.Context, tab *Tab, workspaceId string) error {
|
||||||
|
if tab.TabId == "" {
|
||||||
|
tab.TabId = uuid.New().String()
|
||||||
|
}
|
||||||
|
return WithTx(ctx, func(tx *TxWrap) error {
|
||||||
|
query := "INSERT INTO tab (tabid, data) VALUES (?, ?)"
|
||||||
|
tx.Exec(query, tab.TabId, TxJson(tx, tab))
|
||||||
|
return addTabToWorkspace(tx.Context(), workspaceId, tab.TabId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BlockGet(ctx context.Context, blockId string) (*Block, error) {
|
||||||
|
return WithTxRtn(ctx, func(tx *TxWrap) (*Block, error) {
|
||||||
|
query := "SELECT data FROM block WHERE blockid = ?"
|
||||||
|
jsonData := tx.GetString(query, blockId)
|
||||||
|
return TxReadJson[Block](tx, jsonData), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BlockDelete(ctx context.Context, blockId string) error {
|
||||||
|
return WithTx(ctx, func(tx *TxWrap) error {
|
||||||
|
query := "DELETE FROM block WHERE blockid = ?"
|
||||||
|
tx.Exec(query, blockId)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BlockInsert(ctx context.Context, block *Block) error {
|
||||||
|
if block.BlockId == "" {
|
||||||
|
block.BlockId = uuid.New().String()
|
||||||
|
}
|
||||||
|
return WithTx(ctx, func(tx *TxWrap) error {
|
||||||
|
query := "INSERT INTO block (blockid, data) VALUES (?, ?)"
|
||||||
|
tx.Exec(query, block.BlockId, TxJson(tx, block))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
@ -5,14 +5,20 @@ package wstore
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang-migrate/migrate/v4"
|
||||||
|
"github.com/golang-migrate/migrate/v4/source/iofs"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/sawka/txwrap"
|
"github.com/sawka/txwrap"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
||||||
|
|
||||||
|
sqlite3migrate "github.com/golang-migrate/migrate/v4/database/sqlite3"
|
||||||
|
dbfs "github.com/wavetermdev/thenextwave/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
const WStoreDBName = "waveterm.db"
|
const WStoreDBName = "waveterm.db"
|
||||||
@ -55,3 +61,63 @@ func MakeDB(ctx context.Context) (*sqlx.DB, error) {
|
|||||||
func MigrateWStore() error {
|
func MigrateWStore() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MakeWStoreMigrate() (*migrate.Migrate, error) {
|
||||||
|
fsVar, err := iofs.New(dbfs.WStoreMigrationFS, "migrations-wstore")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("opening iofs: %w", err)
|
||||||
|
}
|
||||||
|
mdriver, err := sqlite3migrate.WithInstance(globalDB.DB, &sqlite3migrate.Config{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("making blockstore migration driver: %w", err)
|
||||||
|
}
|
||||||
|
m, err := migrate.NewWithInstance("iofs", fsVar, "sqlite3", mdriver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("making blockstore migration db[%s]: %w", GetDBName(), err)
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMigrateVersion(m *migrate.Migrate) (uint, bool, error) {
|
||||||
|
if m == nil {
|
||||||
|
var err error
|
||||||
|
m, err = MakeWStoreMigrate()
|
||||||
|
if err != nil {
|
||||||
|
return 0, false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curVersion, dirty, err := m.Version()
|
||||||
|
if err == migrate.ErrNilVersion {
|
||||||
|
return 0, false, nil
|
||||||
|
}
|
||||||
|
return curVersion, dirty, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithTx(ctx context.Context, fn func(tx *TxWrap) error) error {
|
||||||
|
return txwrap.WithTx(ctx, globalDB, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithTxRtn[RT any](ctx context.Context, fn func(tx *TxWrap) (RT, error)) (RT, error) {
|
||||||
|
return txwrap.WithTxRtn(ctx, globalDB, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TxJson(tx *TxWrap, v any) string {
|
||||||
|
barr, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
tx.SetErr(fmt.Errorf("json marshal (%T): %w", v, err))
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(barr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TxReadJson[T any](tx *TxWrap, jsonData string) *T {
|
||||||
|
if jsonData == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var v T
|
||||||
|
err := json.Unmarshal([]byte(jsonData), &v)
|
||||||
|
if err != nil {
|
||||||
|
tx.SetErr(fmt.Errorf("json unmarshal (%T): %w", v, err))
|
||||||
|
}
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user