From d51591d8f7601ba5eb6fe85c16c5fca5a29cfd7d Mon Sep 17 00:00:00 2001 From: feiniks <36756310+feiniks@users.noreply.github.com> Date: Wed, 10 Jul 2024 16:34:33 +0800 Subject: [PATCH] get nickname from seahub database (#663) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add parse seahub database config * Get nickname from seahub database * Go get nickname from seahub database * Save output of script to memory and fix some errors * Add exec permission and free child_output --------- Co-authored-by: 杨赫然 --- Makefile.am | 4 +- common/merge-new.c | 46 ++++++++++++- common/merge-new.h | 2 + common/seaf-utils.c | 126 ++++++++++++++++++++++++++++++++++++ common/seaf-utils.h | 3 + configure.ac | 1 + fileserver/fileserver.go | 70 +++++++++++++++++++- fileserver/merge.go | 38 +++++++++-- fileserver/merge_test.go | 31 +++++---- fuse/seafile-session.h | 1 + scripts/Makefile.am | 3 + scripts/parse_seahub_db.py | 6 ++ server/gc/seafile-session.h | 1 + server/seafile-session.c | 2 + server/seafile-session.h | 1 + 15 files changed, 311 insertions(+), 24 deletions(-) create mode 100644 scripts/Makefile.am create mode 100755 scripts/parse_seahub_db.py diff --git a/Makefile.am b/Makefile.am index 16d03aa3..ae142d7b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,9 +14,9 @@ endif MAKE_SERVER = server tools $(MAKE_CONTROLLER) $(MAKE_FUSE) -SUBDIRS = include lib common python $(MAKE_SERVER) doc +SUBDIRS = include lib common python $(MAKE_SERVER) doc scripts -DIST_SUBDIRS = include lib common python server tools controller fuse doc +DIST_SUBDIRS = include lib common python server tools controller fuse doc scripts INTLTOOL = \ intltool-extract.in \ diff --git a/common/merge-new.c b/common/merge-new.c index 3d5a2e88..35a0bd8c 100644 --- a/common/merge-new.c +++ b/common/merge-new.c @@ -13,6 +13,31 @@ merge_trees_recursive (const char *store_id, int version, const char *basedir, MergeOptions *opt); +static const char * +get_nickname_by_modifier (GHashTable *email_to_nickname, const char *modifier) +{ + const char *nickname = NULL; + + if (!modifier) { + return NULL; + } + + nickname = g_hash_table_lookup (email_to_nickname, modifier); + if (nickname) { + return nickname; + } + + char *sql = "SELECT nickname from profile_profile WHERE user = ?"; + nickname = seaf_db_statement_get_string(seaf->seahub_db, sql, 1, "string", modifier); + + if (!nickname) { + nickname = modifier; + } + g_hash_table_insert (email_to_nickname, g_strdup(modifier), g_strdup(nickname)); + + return nickname; +} + static char * merge_conflict_filename (const char *store_id, int version, MergeOptions *opt, @@ -20,6 +45,7 @@ merge_conflict_filename (const char *store_id, int version, const char *filename) { char *path = NULL, *modifier = NULL, *conflict_name = NULL; + const char *nickname = NULL; gint64 mtime; SeafCommit *commit; @@ -46,7 +72,11 @@ merge_conflict_filename (const char *store_id, int version, seaf_commit_unref (commit); } - conflict_name = gen_conflict_path (filename, modifier, mtime); + nickname = modifier; + if (seaf->seahub_db) + nickname = get_nickname_by_modifier (opt->email_to_nickname, modifier); + + conflict_name = gen_conflict_path (filename, nickname, mtime); out: g_free (path); @@ -61,6 +91,7 @@ merge_conflict_dirname (const char *store_id, int version, const char *dirname) { char *modifier = NULL, *conflict_name = NULL; + const char *nickname = NULL; SeafCommit *commit; commit = seaf_commit_manager_get_commit (seaf->commit_mgr, @@ -74,7 +105,11 @@ merge_conflict_dirname (const char *store_id, int version, modifier = g_strdup(commit->creator_name); seaf_commit_unref (commit); - conflict_name = gen_conflict_path (dirname, modifier, (gint64)time(NULL)); + nickname = modifier; + if (seaf->seahub_db) + nickname = get_nickname_by_modifier (opt->email_to_nickname, modifier); + + conflict_name = gen_conflict_path (dirname, nickname, (gint64)time(NULL)); out: g_free (modifier); @@ -687,6 +722,11 @@ seaf_merge_trees (const char *store_id, int version, g_return_val_if_fail (n == 2 || n == 3, -1); + opt->email_to_nickname = g_hash_table_new_full(g_str_hash, + g_str_equal, + g_free, + g_free); + trees = g_new0 (SeafDir *, n); for (i = 0; i < n; ++i) { root = seaf_fs_manager_get_seafdir (seaf->fs_mgr, store_id, version, roots[i]); @@ -704,5 +744,7 @@ seaf_merge_trees (const char *store_id, int version, seaf_dir_free (trees[i]); g_free (trees); + g_hash_table_destroy (opt->email_to_nickname); + return ret; } diff --git a/common/merge-new.h b/common/merge-new.h index 0c8d1d49..3e5cfe6f 100644 --- a/common/merge-new.h +++ b/common/merge-new.h @@ -25,6 +25,8 @@ typedef struct MergeOptions { char merged_tree_root[41]; /* merge result */ int visit_dirs; gboolean conflict; + + GHashTable *email_to_nickname; } MergeOptions; int diff --git a/common/seaf-utils.c b/common/seaf-utils.c index f007a963..fd2f9814 100644 --- a/common/seaf-utils.c +++ b/common/seaf-utils.c @@ -379,3 +379,129 @@ load_ccnet_database_config (SeafileSession *session) g_free (engine); return ret; } + +static char * +parse_seahub_db_config () +{ + char buf[1024]; + GError *error = NULL; + int retcode = 0; + char *child_stdout = NULL; + char *child_stderr = NULL; + + char *binary_path = g_find_program_in_path ("parse_seahub_db.py"); + + snprintf (buf, + sizeof(buf), + "python3 %s", + binary_path); + g_spawn_command_line_sync (buf, + &child_stdout, + &child_stderr, + &retcode, + &error); + + if (error != NULL) { + seaf_warning ("Failed to run python parse_seahub_db.py: %s\n", error->message); + g_free (binary_path); + g_free (child_stdout); + g_free (child_stderr); + g_clear_error (&error); + return NULL; + } + g_spawn_check_exit_status (retcode, &error); + if (error != NULL) { + seaf_warning ("Failed to run python parse_seahub_db.py: %s\n", error->message); + g_free (binary_path); + g_free (child_stdout); + g_free (child_stderr); + g_clear_error (&error); + return NULL; + } + + g_free (binary_path); + g_free (child_stderr); + return child_stdout; +} + +int +load_seahub_database_config (SeafileSession *session) +{ + int ret = 0; + json_t *object = NULL; + json_error_t err; + const char *engine = NULL, *name = NULL, *user = NULL, *password = NULL, *host = NULL, *charset = NULL; + int port; + char *json_str = NULL; + + json_str = parse_seahub_db_config (); + if (!json_str){ + seaf_warning ("Failed to parse seahub database config.\n"); + ret = -1; + goto out; + } + + object = json_loadb (json_str, strlen(json_str), 0, &err); + if (!object) { + seaf_warning ("Failed to load seahub db json: %s: %s\n", json_str, err.text); + ret = -1; + goto out; + } + + engine = json_object_get_string_member (object, "ENGINE"); + name = json_object_get_string_member (object, "NAME"); + user = json_object_get_string_member (object, "USER"); + password = json_object_get_string_member (object, "PASSWORD"); + host = json_object_get_string_member (object, "HOST"); + charset = json_object_get_string_member (object, "CHARSET"); + port = json_object_get_int_member (object, "PORT"); + if (port <= 0) { + port = MYSQL_DEFAULT_PORT; + } + + if (!engine || strstr (engine, "sqlite") != NULL) { + goto out; + } +#ifdef HAVE_MYSQL + else if (strstr (engine, "mysql") != NULL) { + seaf_message("Use database Mysql\n"); + if (!host) { + seaf_warning ("Seahub DB host not set in config.\n"); + ret = -1; + goto out; + } + if (!user) { + seaf_warning ("Seahub DB user not set in config.\n"); + ret = -1; + goto out; + } + if (!password) { + seaf_warning ("Seahub DB password not set in config.\n"); + ret = -1; + goto out; + } + if (!name) { + seaf_warning ("Seahub DB name not set in config.\n"); + ret = -1; + goto out; + } + + session->seahub_db = seaf_db_new_mysql (host, port, user, password, name, NULL, FALSE, FALSE, NULL, charset, DEFAULT_MAX_CONNECTIONS); + if (!session->seahub_db) { + seaf_warning ("Failed to open seahub database.\n"); + ret = -1; + goto out; + } + } +#endif + else { + seaf_warning ("Unknown database type: %s.\n", engine); + ret = -1; + } + +out: + if (object) + json_decref (object); + g_free (json_str); + return ret; +} diff --git a/common/seaf-utils.h b/common/seaf-utils.h index 2113c441..e5d30e15 100644 --- a/common/seaf-utils.h +++ b/common/seaf-utils.h @@ -16,4 +16,7 @@ load_database_config (struct _SeafileSession *session); int load_ccnet_database_config (struct _SeafileSession *session); +int +load_seahub_database_config (SeafileSession *session); + #endif diff --git a/configure.ac b/configure.ac index d7acd854..23d4de8b 100644 --- a/configure.ac +++ b/configure.ac @@ -317,6 +317,7 @@ AC_CONFIG_FILES( controller/Makefile tools/Makefile doc/Makefile + scripts/Makefile ) AC_OUTPUT diff --git a/fileserver/fileserver.go b/fileserver/fileserver.go index 63d8ba8b..fa4c169f 100644 --- a/fileserver/fileserver.go +++ b/fileserver/fileserver.go @@ -5,15 +5,18 @@ import ( "crypto/tls" "crypto/x509" "database/sql" + "encoding/json" "flag" "fmt" "io" "io/ioutil" "net/http" "os" + "os/exec" "os/signal" "path/filepath" "runtime/debug" + "strconv" "strings" "syscall" @@ -41,7 +44,7 @@ var pidFilePath string var logFp *os.File var dbType string -var seafileDB, ccnetDB *sql.DB +var seafileDB, ccnetDB, seahubDB *sql.DB // when SQLite is used, user and group db are separated. var userDB, groupDB *sql.DB @@ -269,6 +272,69 @@ func loadSeafileDB() { dbType = dbEngine } +func loadSeahubDB() { + scriptPath, err := exec.LookPath("parse_seahub_db.py") + if err != nil { + log.Warnf("Failed to find script of parse_seahub_db.py: %v", err) + return + } + cmd := exec.Command("python3", scriptPath) + dbData, err := cmd.CombinedOutput() + if err != nil { + log.Warnf("Failed to run python parse_seahub_db.py: %v", err) + return + } + + dbConfig := make(map[string]string) + + err = json.Unmarshal(dbData, &dbConfig) + if err != nil { + log.Warnf("Failed to decode seahub database json file: %v", err) + return + } + + dbEngine := dbConfig["ENGINE"] + dbName := dbConfig["NAME"] + user := dbConfig["USER"] + password := dbConfig["PASSWORD"] + host := dbConfig["HOST"] + portStr := dbConfig["PORT"] + + if strings.Index(dbEngine, "mysql") >= 0 { + port, err := strconv.ParseInt(portStr, 10, 64) + if err != nil || port <= 0 { + port = 3306 + } + if dbName == "" { + log.Warnf("Seahub DB name not set in config") + return + } + if user == "" { + log.Warnf("Seahub DB user not set in config") + return + } + if password == "" { + log.Warnf("Seahub DB password not set in config") + return + } + if host == "" { + log.Warnf("Seahub DB host not set in config") + return + } + + dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?tls=%t", user, password, host, port, dbName, false) + + seahubDB, err = sql.Open("mysql", dsn) + if err != nil { + log.Warnf("Failed to open database: %v", err) + } + } else if strings.Index(dbEngine, "sqlite") >= 0 { + return + } else { + log.Warnf("Unsupported database %s.", dbEngine) + } +} + func writePidFile(pid_file_path string) error { file, err := os.OpenFile(pid_file_path, os.O_CREATE|os.O_WRONLY, 0664) if err != nil { @@ -367,6 +433,8 @@ func main() { fp.Close() } + loadSeahubDB() + repomgr.Init(seafileDB) fsmgr.Init(centralDir, dataDir, option.FsCacheLimit) diff --git a/fileserver/merge.go b/fileserver/merge.go index f3c7bd6f..1444eed8 100644 --- a/fileserver/merge.go +++ b/fileserver/merge.go @@ -12,10 +12,11 @@ import ( ) type mergeOptions struct { - remoteRepoID string - remoteHead string - mergedRoot string - conflict bool + remoteRepoID string + remoteHead string + mergedRoot string + conflict bool + emailToNickname map[string]string } func mergeTrees(storeID string, roots []string, opt *mergeOptions) error { @@ -24,6 +25,8 @@ func mergeTrees(storeID string, roots []string, opt *mergeOptions) error { return err } + opt.emailToNickname = make(map[string]string) + var trees []*fsmgr.SeafDir for i := 0; i < 3; i++ { dir, err := fsmgr.GetSeafdir(storeID, roots[i]) @@ -335,7 +338,9 @@ func mergeConflictFileName(storeID string, opt *mergeOptions, baseDir, fileName mtime = time.Now().Unix() } - conflictName := genConflictPath(fileName, modifier, mtime) + nickname := getNickNameByModifier(opt.emailToNickname, modifier) + + conflictName := genConflictPath(fileName, nickname, mtime) return conflictName, nil } @@ -366,6 +371,29 @@ func genConflictPath(originPath, modifier string, mtime int64) string { return conflictPath } +func getNickNameByModifier(emailToNickname map[string]string, modifier string) string { + if modifier == "" { + return "" + } + nickname, ok := emailToNickname[modifier] + if ok { + return nickname + } + if seahubDB != nil { + sqlStr := "SELECT nickname from profile_profile WHERE user = ?" + row := seahubDB.QueryRow(sqlStr, modifier) + row.Scan(&nickname) + } + + if nickname == "" { + nickname = modifier + } + + emailToNickname[modifier] = nickname + + return nickname +} + func getFileModifierMtime(repoID, storeID, head, filePath string) (string, int64, error) { commit, err := commitmgr.Load(repoID, head) if err != nil { diff --git a/fileserver/merge_test.go b/fileserver/merge_test.go index e34c46bc..07a24bf2 100644 --- a/fileserver/merge_test.go +++ b/fileserver/merge_test.go @@ -30,24 +30,27 @@ var mergeTestTree4CommitID string var mergeTestTree5CommitID string /* - test directory structure: - tree1 - |--bbb - |-- testfile(size:1) +test directory structure: +tree1 +|--bbb - tree2 - |--bbb - |-- testfile(size:10) + |-- testfile(size:1) - tree3 - |--bbb +tree2 +|--bbb - tree4 - |--bbb - |-- testfile(size:100) + |-- testfile(size:10) - tree5 - |-- +tree3 +|--bbb + +tree4 +|--bbb + + |-- testfile(size:100) + +tree5 +|-- */ func mergeTestCreateTestDir() error { modeDir := uint32(syscall.S_IFDIR | 0644) diff --git a/fuse/seafile-session.h b/fuse/seafile-session.h index 922e598a..f535f91d 100644 --- a/fuse/seafile-session.h +++ b/fuse/seafile-session.h @@ -26,6 +26,7 @@ struct _SeafileSession { GKeyFile *ccnet_config; SeafDB *db; SeafDB *ccnet_db; + SeafDB *seahub_db; SeafBlockManager *block_mgr; SeafFSManager *fs_mgr; diff --git a/scripts/Makefile.am b/scripts/Makefile.am new file mode 100644 index 00000000..63235534 --- /dev/null +++ b/scripts/Makefile.am @@ -0,0 +1,3 @@ +bin_SCRIPTS = parse_seahub_db.py + +EXTRA_DIST = parse_seahub_db.py diff --git a/scripts/parse_seahub_db.py b/scripts/parse_seahub_db.py new file mode 100755 index 00000000..b20d9648 --- /dev/null +++ b/scripts/parse_seahub_db.py @@ -0,0 +1,6 @@ +import json +import seahub_settings + +db_infos = seahub_settings.DATABASES['default'] + +print(json.dumps(db_infos)) diff --git a/server/gc/seafile-session.h b/server/gc/seafile-session.h index 641dc36a..b05f68f2 100644 --- a/server/gc/seafile-session.h +++ b/server/gc/seafile-session.h @@ -24,6 +24,7 @@ struct _SeafileSession { GKeyFile *ccnet_config; SeafDB *db; SeafDB *ccnet_db; + SeafDB *seahub_db; SeafBlockManager *block_mgr; SeafFSManager *fs_mgr; diff --git a/server/seafile-session.c b/server/seafile-session.c index a2409ffd..a697e912 100644 --- a/server/seafile-session.c +++ b/server/seafile-session.c @@ -218,6 +218,8 @@ seafile_session_new(const char *central_config_dir, goto onerror; } + load_seahub_database_config (session); + session->cfg_mgr = seaf_cfg_manager_new (session); if (!session->cfg_mgr) goto onerror; diff --git a/server/seafile-session.h b/server/seafile-session.h index 05a141c8..0dbb1186 100644 --- a/server/seafile-session.h +++ b/server/seafile-session.h @@ -47,6 +47,7 @@ struct _SeafileSession { GKeyFile *ccnet_config; SeafDB *db; CcnetDB *ccnet_db; + SeafDB *seahub_db; SeafBlockManager *block_mgr; SeafFSManager *fs_mgr;