feat: add msglib message source metadata
This commit is contained in:
@@ -8,7 +8,7 @@ namespace MsgLibReadSidecar
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private const string Version = "0.2.0";
|
||||
private const string Version = "0.3.0";
|
||||
private const string DefaultPassword = "123";
|
||||
|
||||
private static readonly HashSet<string> DefaultTargetTables = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
@@ -46,6 +46,9 @@ namespace MsgLibReadSidecar
|
||||
case "display_sources":
|
||||
response = SidecarProtocol.Success(requestId, op, SchemaSummary(opArgs, true));
|
||||
break;
|
||||
case "message_sources":
|
||||
response = SidecarProtocol.Success(requestId, op, MessageSources(opArgs));
|
||||
break;
|
||||
case "display_entities":
|
||||
response = SidecarProtocol.Success(requestId, op, DisplayEntities(opArgs));
|
||||
break;
|
||||
@@ -123,6 +126,40 @@ namespace MsgLibReadSidecar
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> MessageSources(Dictionary<string, object> args)
|
||||
{
|
||||
string sqliteDllPath = SidecarProtocol.GetString(args, "sqlite_dll_path", "");
|
||||
string dbPath = SidecarProtocol.GetString(args, "db_path", "");
|
||||
string password = SidecarProtocol.GetString(args, "password", DefaultPassword);
|
||||
|
||||
ValidateInputs(sqliteDllPath, dbPath);
|
||||
|
||||
var result = new Dictionary<string, object>
|
||||
{
|
||||
{ "metadata_only", true },
|
||||
{ "read_only", true },
|
||||
{ "message_body_values_returned", false },
|
||||
{ "raw_rows_returned", false },
|
||||
{ "file_paths_returned", false },
|
||||
{ "provider", "System.Data.SQLite" },
|
||||
{ "process_bits", IntPtr.Size * 8 }
|
||||
};
|
||||
|
||||
using (DbConnection connection = OpenSqliteConnection(sqliteDllPath, dbPath, password))
|
||||
{
|
||||
connection.Open();
|
||||
TryExecuteNonQuery(connection, "PRAGMA query_only=ON");
|
||||
List<Dictionary<string, object>> tables = ReadMasterTables(connection, 256);
|
||||
HashSet<string> messageTables = BuildMessageSourceTableSet();
|
||||
List<Dictionary<string, object>> columns = ReadColumns(connection, tables, messageTables);
|
||||
Dictionary<string, HashSet<string>> columnMap = BuildColumnMap(columns);
|
||||
Dictionary<string, string> rowCounts = ReadTargetCountMap(connection, tables, messageTables);
|
||||
result["message_sources"] = BuildMessageSources(tables, columnMap, rowCounts);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static Dictionary<string, object> DisplayEntities(Dictionary<string, object> args)
|
||||
{
|
||||
@@ -288,6 +325,16 @@ namespace MsgLibReadSidecar
|
||||
return rows;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> ReadTargetCountMap(DbConnection connection, List<Dictionary<string, object>> tables, HashSet<string> targetTables)
|
||||
{
|
||||
var rowCounts = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (Dictionary<string, object> item in ReadTargetCounts(connection, tables, targetTables))
|
||||
{
|
||||
rowCounts[Convert.ToString(item["table"])] = Convert.ToString(item["row_count"]);
|
||||
}
|
||||
return rowCounts;
|
||||
}
|
||||
|
||||
private static List<Dictionary<string, object>> BuildDisplaySources(List<Dictionary<string, object>> tables, List<Dictionary<string, object>> columns)
|
||||
{
|
||||
var tableSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
@@ -320,6 +367,115 @@ namespace MsgLibReadSidecar
|
||||
return sources;
|
||||
}
|
||||
|
||||
private sealed class MessageSourceSpec
|
||||
{
|
||||
public string Source;
|
||||
public string Table;
|
||||
public string Role;
|
||||
public string[] RequiredColumns;
|
||||
}
|
||||
|
||||
private static HashSet<string> BuildMessageSourceTableSet()
|
||||
{
|
||||
var tables = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (MessageSourceSpec spec in BuildMessageSourceSpecs())
|
||||
{
|
||||
tables.Add(spec.Table);
|
||||
}
|
||||
return tables;
|
||||
}
|
||||
|
||||
private static List<MessageSourceSpec> BuildMessageSourceSpecs()
|
||||
{
|
||||
return new List<MessageSourceSpec>
|
||||
{
|
||||
new MessageSourceSpec
|
||||
{
|
||||
Source = "direct_messages",
|
||||
Table = "tblPersonMsg",
|
||||
Role = "direct",
|
||||
RequiredColumns = new string[] { "Id", "SndPersonId", "RecvPersonId", "ObjPersonId", "ActionTime", "MsgText", "MessageBody" }
|
||||
},
|
||||
new MessageSourceSpec
|
||||
{
|
||||
Source = "group_messages",
|
||||
Table = "tblMsgGroupPersonMsg",
|
||||
Role = "group",
|
||||
RequiredColumns = new string[] { "Id", "SndPersonId", "MsgGroupId", "MsgGroupName", "MsgTime", "MsgText", "MessageBody" }
|
||||
},
|
||||
new MessageSourceSpec
|
||||
{
|
||||
Source = "system_messages",
|
||||
Table = "TD_SystemMessageRecord",
|
||||
Role = "system",
|
||||
RequiredColumns = new string[] { "MsgGuid", "MsgType", "MsgTitle", "MsgText", "SendPersonJid", "MsgTime", "MsgReadState" }
|
||||
},
|
||||
new MessageSourceSpec
|
||||
{
|
||||
Source = "group_receipts",
|
||||
Table = "TD_GroupReceiptMessage",
|
||||
Role = "receipt_metadata",
|
||||
RequiredColumns = new string[] { "MsgGuid", "PersonID", "ReceiptTime" }
|
||||
},
|
||||
new MessageSourceSpec
|
||||
{
|
||||
Source = "received_file_metadata",
|
||||
Table = "TD_ReceiveFileRecord",
|
||||
Role = "attachment_metadata",
|
||||
RequiredColumns = new string[] { "ReceiveMsgGuid", "FileName", "FileSize", "SourceID", "SourceName", "FileType", "SendPersonJid", "SendPersonName", "SendTime" }
|
||||
},
|
||||
new MessageSourceSpec
|
||||
{
|
||||
Source = "recent_conversation_index",
|
||||
Table = "tblRecent",
|
||||
Role = "conversation_index",
|
||||
RequiredColumns = new string[] { "Id", "PersonId", "PersonName", "ActionTime", "FType" }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static List<Dictionary<string, object>> BuildMessageSources(List<Dictionary<string, object>> tables, Dictionary<string, HashSet<string>> columnMap, Dictionary<string, string> rowCounts)
|
||||
{
|
||||
var tableSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (Dictionary<string, object> table in tables)
|
||||
{
|
||||
if (string.Equals(Convert.ToString(table["type"]), "table", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
tableSet.Add(Convert.ToString(table["name"]));
|
||||
}
|
||||
}
|
||||
|
||||
var sources = new List<Dictionary<string, object>>();
|
||||
foreach (MessageSourceSpec spec in BuildMessageSourceSpecs())
|
||||
{
|
||||
AddMessageSource(sources, tableSet, columnMap, rowCounts, spec);
|
||||
}
|
||||
return sources;
|
||||
}
|
||||
|
||||
private static void AddMessageSource(List<Dictionary<string, object>> sources, HashSet<string> tableSet, Dictionary<string, HashSet<string>> columnMap, Dictionary<string, string> rowCounts, MessageSourceSpec spec)
|
||||
{
|
||||
var presentColumns = new List<string>();
|
||||
if (columnMap.ContainsKey(spec.Table))
|
||||
{
|
||||
foreach (string column in spec.RequiredColumns)
|
||||
{
|
||||
if (columnMap[spec.Table].Contains(column)) presentColumns.Add(column);
|
||||
}
|
||||
}
|
||||
string rowCount = rowCounts.ContainsKey(spec.Table) ? rowCounts[spec.Table] : "0";
|
||||
sources.Add(new Dictionary<string, object>
|
||||
{
|
||||
{ "source", spec.Source },
|
||||
{ "table", spec.Table },
|
||||
{ "role", spec.Role },
|
||||
{ "available", tableSet.Contains(spec.Table) && presentColumns.Count == spec.RequiredColumns.Length },
|
||||
{ "required_columns", spec.RequiredColumns },
|
||||
{ "present_columns", presentColumns.ToArray() },
|
||||
{ "row_count", rowCount }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private sealed class DisplayEntitySpec
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user