From 73f59eaf091463190816e3aeec79262f3df7807a Mon Sep 17 00:00:00 2001
From: guopeng <alex.guoba@gmail.com>
Date: Mon, 16 Oct 2023 21:07:21 +0800
Subject: [PATCH] fix: storage setting changed don't take effect (#2385)

* fix: Storage setting changed don't take effect

* fix: Storage setting changed don't take effect

* fix: Storage setting changed don't take effect
---
 api/v2/system_service.go                      |  7 ++--
 store/db/mysql/mysql.go                       | 42 ++++++++++++++++++-
 store/db/sqlite/sqlite.go                     | 12 ++++++
 store/driver.go                               |  3 ++
 store/store.go                                |  4 ++
 .../components/Settings/StorageSection.tsx    |  6 ++-
 6 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/api/v2/system_service.go b/api/v2/system_service.go
index 6bfe4c29..9c187b1c 100644
--- a/api/v2/system_service.go
+++ b/api/v2/system_service.go
@@ -2,7 +2,6 @@ package v2
 
 import (
 	"context"
-	"os"
 	"strconv"
 
 	"google.golang.org/grpc/codes"
@@ -37,11 +36,11 @@ func (s *SystemService) GetSystemInfo(ctx context.Context, _ *apiv2pb.GetSystemI
 		return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
 	}
 	if currentUser != nil && currentUser.Role == store.RoleHost {
-		fi, err := os.Stat(s.Profile.DSN)
+		size, err := s.Store.GetCurrentDBSize(ctx)
 		if err != nil {
-			return nil, status.Errorf(codes.Internal, "failed to get file info: %v", err)
+			return nil, status.Errorf(codes.Internal, "failed to get db size: %v", err)
 		}
-		defaultSystemInfo.DbSize = fi.Size()
+		defaultSystemInfo.DbSize = size
 	}
 
 	response := &apiv2pb.GetSystemInfoResponse{
diff --git a/store/db/mysql/mysql.go b/store/db/mysql/mysql.go
index f4d015ad..31545d95 100644
--- a/store/db/mysql/mysql.go
+++ b/store/db/mysql/mysql.go
@@ -5,8 +5,10 @@ import (
 	"database/sql"
 	"fmt"
 
+	"github.com/go-sql-driver/mysql"
 	"github.com/pkg/errors"
 
+	"github.com/usememos/memos/common/log"
 	"github.com/usememos/memos/server/profile"
 	"github.com/usememos/memos/store"
 )
@@ -14,18 +16,28 @@ import (
 type DB struct {
 	db      *sql.DB
 	profile *profile.Profile
+	config  *mysql.Config
 }
 
 func NewDB(profile *profile.Profile) (store.Driver, error) {
 	// Open MySQL connection with parameter.
 	// multiStatements=true is required for migration.
 	// See more in: https://github.com/go-sql-driver/mysql#multistatements
-	db, err := sql.Open("mysql", fmt.Sprintf("%s?multiStatements=true", profile.DSN))
+	dsn := fmt.Sprintf("%s?multiStatements=true", profile.DSN)
+
+	var err error
+	driver := DB{profile: profile}
+	driver.config, err = mysql.ParseDSN(dsn)
+	if err != nil {
+		log.Error(fmt.Sprintf("DSN parse error: %s", dsn))
+		return nil, errors.New("Parse DSN eroor")
+	}
+
+	driver.db, err = sql.Open("mysql", dsn)
 	if err != nil {
 		return nil, errors.Wrapf(err, "failed to open db: %s", profile.DSN)
 	}
 
-	driver := DB{db: db, profile: profile}
 	return &driver, nil
 }
 
@@ -67,6 +79,32 @@ func (*DB) BackupTo(context.Context, string) error {
 	return errors.New("Please use mysqldump to backup")
 }
 
+func (d *DB) GetCurrentDBSize(ctx context.Context) (int64, error) {
+	query := "SELECT SUM(`data_length` + `index_length`) AS `size` " +
+		" FROM information_schema.TABLES" +
+		" WHERE `table_schema` = ?" +
+		" GROUP BY `table_schema`"
+	rows, err := d.db.QueryContext(ctx, query, d.config.DBName)
+	if err != nil {
+		log.Error("Query db size error, make sure you have enough privilege")
+		return 0, err
+	}
+	defer rows.Close()
+
+	var size int64
+	for rows.Next() {
+		if err := rows.Scan(&size); err != nil {
+			return 0, err
+		}
+	}
+
+	if rows.Err() != nil {
+		return 0, rows.Err()
+	}
+
+	return size, nil
+}
+
 func (d *DB) Close() error {
 	return d.db.Close()
 }
diff --git a/store/db/sqlite/sqlite.go b/store/db/sqlite/sqlite.go
index 182cfc1b..e766343e 100644
--- a/store/db/sqlite/sqlite.go
+++ b/store/db/sqlite/sqlite.go
@@ -3,8 +3,11 @@ package sqlite
 import (
 	"context"
 	"database/sql"
+	"os"
 
 	"github.com/pkg/errors"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
 	"modernc.org/sqlite"
 
 	"github.com/usememos/memos/server/profile"
@@ -137,6 +140,15 @@ func (d *DB) BackupTo(ctx context.Context, filename string) error {
 	return nil
 }
 
+func (d *DB) GetCurrentDBSize(context.Context) (int64, error) {
+	fi, err := os.Stat(d.profile.DSN)
+	if err != nil {
+		return 0, status.Errorf(codes.Internal, "failed to get file info: %v", err)
+	}
+
+	return fi.Size(), nil
+}
+
 func (d *DB) Close() error {
 	return d.db.Close()
 }
diff --git a/store/driver.go b/store/driver.go
index 7fe852fc..2425feba 100644
--- a/store/driver.go
+++ b/store/driver.go
@@ -17,6 +17,9 @@ type Driver interface {
 	Vacuum(ctx context.Context) error
 	BackupTo(ctx context.Context, filename string) error
 
+	// current file is driver
+	GetCurrentDBSize(ctx context.Context) (int64, error)
+
 	// Activity model related methods.
 	CreateActivity(ctx context.Context, create *Activity) (*Activity, error)
 	ListActivity(ctx context.Context, find *FindActivity) ([]*Activity, error)
diff --git a/store/store.go b/store/store.go
index 91ef6175..a2c8e068 100644
--- a/store/store.go
+++ b/store/store.go
@@ -36,3 +36,7 @@ func (s *Store) Vacuum(ctx context.Context) error {
 func (s *Store) Close() error {
 	return s.driver.Close()
 }
+
+func (s *Store) GetCurrentDBSize(ctx context.Context) (int64, error) {
+	return s.driver.GetCurrentDBSize(ctx)
+}
diff --git a/web/src/components/Settings/StorageSection.tsx b/web/src/components/Settings/StorageSection.tsx
index cd91090f..f773d3f3 100644
--- a/web/src/components/Settings/StorageSection.tsx
+++ b/web/src/components/Settings/StorageSection.tsx
@@ -32,7 +32,11 @@ const StorageSection = () => {
       name: "storage-service-id",
       value: JSON.stringify(storageId),
     });
-    await globalStore.fetchSystemStatus();
+    try {
+      await globalStore.fetchSystemStatus();
+    } catch (error: any) {
+      console.error(error);
+    }
     setStorageServiceId(storageId);
   };