namespace BotSharp.Plugin.MongoStorage; public class MongoDbContext { private readonly MongoClient _mongoClient; private readonly string _mongoDbDatabaseName; private readonly string _collectionPrefix; private const string DB_NAME_INDEX = "authSource"; public MongoDbContext(BotSharpDatabaseSettings dbSettings) { var mongoDbConnectionString = dbSettings.BotSharpMongoDb; _mongoClient = new MongoClient(mongoDbConnectionString); _mongoDbDatabaseName = GetDatabaseName(mongoDbConnectionString); _collectionPrefix = dbSettings.TablePrefix.IfNullOrEmptyAs("BotSharp"); } private string GetDatabaseName(string mongoDbConnectionString) { var databaseName = mongoDbConnectionString.Substring(mongoDbConnectionString.LastIndexOf("/", StringComparison.InvariantCultureIgnoreCase) + 1); var symbol = "?"; if (databaseName.Contains(symbol)) { var markIdx = databaseName.IndexOf(symbol, StringComparison.InvariantCultureIgnoreCase); var db = databaseName.Substring(0, markIdx); if (!string.IsNullOrWhiteSpace(db)) { return db; } var queryStr = databaseName.Substring(markIdx + 1); var queries = queryStr.Split("&", StringSplitOptions.RemoveEmptyEntries).Select(x => new { Key = x.Split("=")[0], Value = x.Split("=")[1] }).ToList(); var source = queries.FirstOrDefault(x => x.Key.IsEqualTo(DB_NAME_INDEX)); if (source != null) { databaseName = source.Value; } } return databaseName; } private IMongoDatabase Database => _mongoClient.GetDatabase(_mongoDbDatabaseName); #region Private methods private bool CollectionExists(IMongoDatabase database, string collectionName) { var filter = Builders.Filter.Eq("name", collectionName); var collections = database.ListCollectionNames(new ListCollectionNamesOptions { Filter = filter }).ToList(); return collections.Any(); } private IMongoCollection GetCollectionOrCreate(string name) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException($"The collection {name} cannot be empty."); var collectionName = $"{_collectionPrefix}_{name}"; if (!CollectionExists(Database, collectionName)) { Database.CreateCollection(collectionName); } var collection = Database.GetCollection(collectionName); return collection; } #region Indexes private IMongoCollection CreateConversationIndex() { var collection = GetCollectionOrCreate("Conversations"); var indexes = collection.Indexes.List().ToList(); var createTimeIndex = indexes.FirstOrDefault(x => x.GetElement("name").ToString().StartsWith("CreatedTime")); if (createTimeIndex == null) { var indexDef = Builders.IndexKeys.Descending(x => x.CreatedTime); collection.Indexes.CreateOne(new CreateIndexModel(indexDef)); } return collection; } private IMongoCollection CreateConversationStateIndex() { var collection = GetCollectionOrCreate("ConversationStates"); var indexes = collection.Indexes.List().ToList(); var stateIndex = indexes.FirstOrDefault(x => x.GetElement("name").ToString().StartsWith("States.Key")); if (stateIndex == null) { var indexDef = Builders.IndexKeys.Ascending("States.Key"); collection.Indexes.CreateOne(new CreateIndexModel(indexDef)); } return collection; } private IMongoCollection CreateAgentTaskIndex() { var collection = GetCollectionOrCreate("AgentTasks"); var indexes = collection.Indexes.List().ToList(); var createTimeIndex = indexes.FirstOrDefault(x => x.GetElement("name").ToString().StartsWith("CreatedTime")); if (createTimeIndex == null) { var indexDef = Builders.IndexKeys.Descending(x => x.CreatedTime); collection.Indexes.CreateOne(new CreateIndexModel(indexDef)); } return collection; } private IMongoCollection CreateContentLogIndex() { var collection = GetCollectionOrCreate("ConversationContentLogs"); var indexes = collection.Indexes.List().ToList(); var createTimeIndex = indexes.FirstOrDefault(x => x.GetElement("name").ToString().StartsWith("CreateTime")); if (createTimeIndex == null) { var indexDef = Builders.IndexKeys.Ascending(x => x.CreatedTime); collection.Indexes.CreateOne(new CreateIndexModel(indexDef)); } return collection; } private IMongoCollection CreateStateLogIndex() { var collection = GetCollectionOrCreate("ConversationStateLogs"); var indexes = collection.Indexes.List().ToList(); var createTimeIndex = indexes.FirstOrDefault(x => x.GetElement("name").ToString().StartsWith("CreateTime")); if (createTimeIndex == null) { var indexDef = Builders.IndexKeys.Ascending(x => x.CreatedTime); collection.Indexes.CreateOne(new CreateIndexModel(indexDef)); } return collection; } #endregion #endregion public IMongoCollection Agents => GetCollectionOrCreate("Agents"); public IMongoCollection AgentTasks => CreateAgentTaskIndex(); public IMongoCollection Conversations => CreateConversationIndex(); public IMongoCollection ConversationDialogs => GetCollectionOrCreate("ConversationDialogs"); public IMongoCollection ConversationStates => CreateConversationStateIndex(); public IMongoCollection LlmCompletionLogs => GetCollectionOrCreate("LlmCompletionLogs"); public IMongoCollection ContentLogs => CreateContentLogIndex(); public IMongoCollection StateLogs => CreateStateLogIndex(); public IMongoCollection Users => GetCollectionOrCreate("Users"); public IMongoCollection UserAgents => GetCollectionOrCreate("UserAgents"); public IMongoCollection Plugins => GetCollectionOrCreate("Plugins"); public IMongoCollection TranslationMemories => GetCollectionOrCreate("TranslationMemories"); public IMongoCollection KnowledgeCollectionConfigs => GetCollectionOrCreate("KnowledgeCollectionConfigs"); public IMongoCollection KnowledgeCollectionFileMeta => GetCollectionOrCreate("KnowledgeCollectionFileMeta"); public IMongoCollection Roles => GetCollectionOrCreate("Roles"); public IMongoCollection RoleAgents => GetCollectionOrCreate("RoleAgents"); public IMongoCollection CrontabItems => GetCollectionOrCreate("CronTabItems"); public IMongoCollection GlobalStatistics => GetCollectionOrCreate("GlobalStatistics"); }