feat: split out messages table from main database
This commit is contained in:
parent
09ac002d26
commit
bf7747ab34
@ -92,7 +92,7 @@ public class DiscordControllerV2: PKControllerBase
|
||||
[HttpGet("messages/{messageId}")]
|
||||
public async Task<ActionResult<JObject>> MessageGet(ulong messageId)
|
||||
{
|
||||
var msg = await _db.Execute(c => _repo.GetMessage(c, messageId));
|
||||
var msg = await _repo.GetFullMessage(messageId);
|
||||
if (msg == null)
|
||||
throw Errors.MessageNotFound;
|
||||
|
||||
|
@ -197,7 +197,7 @@ public class Checks
|
||||
if (messageId == null || channelId == null)
|
||||
throw new PKError(failedToGetMessage);
|
||||
|
||||
var proxiedMsg = await ctx.Database.Execute(conn => ctx.Repository.GetMessage(conn, messageId.Value));
|
||||
var proxiedMsg = await ctx.Repository.GetMessage(messageId.Value);
|
||||
if (proxiedMsg != null)
|
||||
{
|
||||
await ctx.Reply($"{Emojis.Success} This message was proxied successfully.");
|
||||
|
@ -55,9 +55,9 @@ public class ProxiedMessage
|
||||
|
||||
public async Task ReproxyMessage(Context ctx)
|
||||
{
|
||||
var msg = await GetMessageToEdit(ctx, ReproxyTimeout, true);
|
||||
var (msg, systemId) = await GetMessageToEdit(ctx, ReproxyTimeout, true);
|
||||
|
||||
if (ctx.System.Id != msg.System?.Id)
|
||||
if (ctx.System.Id != systemId)
|
||||
throw new PKError("Can't reproxy a message sent by a different system.");
|
||||
|
||||
// Get target member ID
|
||||
@ -68,14 +68,14 @@ public class ProxiedMessage
|
||||
// Fetch members and get the ProxyMember for `target`
|
||||
List<ProxyMember> members;
|
||||
using (_metrics.Measure.Timer.Time(BotMetrics.ProxyMembersQueryTime))
|
||||
members = (await _repo.GetProxyMembers(ctx.Author.Id, msg.Message.Guild!.Value)).ToList();
|
||||
members = (await _repo.GetProxyMembers(ctx.Author.Id, msg.Guild!.Value)).ToList();
|
||||
var match = members.Find(x => x.Id == target.Id);
|
||||
if (match == null)
|
||||
throw new PKError("Could not find a member to reproxy the message with.");
|
||||
|
||||
try
|
||||
{
|
||||
await _proxy.ExecuteReproxy(ctx.Message, msg.Message, members, match);
|
||||
await _proxy.ExecuteReproxy(ctx.Message, msg, members, match);
|
||||
|
||||
if (ctx.Guild == null)
|
||||
await _rest.CreateReaction(ctx.Channel.Id, ctx.Message.Id, new Emoji { Name = Emojis.Success });
|
||||
@ -90,15 +90,15 @@ public class ProxiedMessage
|
||||
|
||||
public async Task EditMessage(Context ctx)
|
||||
{
|
||||
var msg = await GetMessageToEdit(ctx, EditTimeout, false);
|
||||
var (msg, systemId) = await GetMessageToEdit(ctx, EditTimeout, false);
|
||||
|
||||
if (ctx.System.Id != msg.System?.Id)
|
||||
if (ctx.System.Id != systemId)
|
||||
throw new PKError("Can't edit a message sent by a different system.");
|
||||
|
||||
if (!ctx.HasNext())
|
||||
throw new PKSyntaxError("You need to include the message to edit in.");
|
||||
|
||||
var originalMsg = await _rest.GetMessageOrNull(msg.Message.Channel, msg.Message.Mid);
|
||||
var originalMsg = await _rest.GetMessageOrNull(msg.Channel, msg.Mid);
|
||||
if (originalMsg == null)
|
||||
throw new PKError("Could not edit message.");
|
||||
|
||||
@ -124,7 +124,7 @@ public class ProxiedMessage
|
||||
try
|
||||
{
|
||||
var editedMsg =
|
||||
await _webhookExecutor.EditWebhookMessage(msg.Message.Channel, msg.Message.Mid, newContent);
|
||||
await _webhookExecutor.EditWebhookMessage(msg.Channel, msg.Mid, newContent);
|
||||
|
||||
if (ctx.Guild == null)
|
||||
await _rest.CreateReaction(ctx.Channel.Id, ctx.Message.Id, new Emoji { Name = Emojis.Success });
|
||||
@ -132,7 +132,7 @@ public class ProxiedMessage
|
||||
if ((await ctx.BotPermissions).HasFlag(PermissionSet.ManageMessages))
|
||||
await _rest.DeleteMessage(ctx.Channel.Id, ctx.Message.Id);
|
||||
|
||||
await _logChannel.LogMessage(msg.Message, ctx.Message, editedMsg, originalMsg!.Content!);
|
||||
await _logChannel.LogMessage(msg, ctx.Message, editedMsg, originalMsg!.Content!);
|
||||
}
|
||||
catch (NotFoundException)
|
||||
{
|
||||
@ -140,18 +140,18 @@ public class ProxiedMessage
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<FullMessage> GetMessageToEdit(Context ctx, Duration timeout, bool isReproxy)
|
||||
private async Task<(PKMessage, SystemId)> GetMessageToEdit(Context ctx, Duration timeout, bool isReproxy)
|
||||
{
|
||||
var editType = isReproxy ? "reproxy" : "edit";
|
||||
var editTypeAction = isReproxy ? "reproxied" : "edited";
|
||||
|
||||
FullMessage? msg = null;
|
||||
PKMessage? msg = null;
|
||||
|
||||
var (referencedMessage, _) = ctx.MatchMessage(false);
|
||||
if (referencedMessage != null)
|
||||
{
|
||||
await using var conn = await ctx.Database.Obtain();
|
||||
msg = await ctx.Repository.GetMessage(conn, referencedMessage.Value);
|
||||
msg = await ctx.Repository.GetMessage(referencedMessage.Value);
|
||||
if (msg == null)
|
||||
throw new PKError("This is not a message proxied by PluralKit.");
|
||||
}
|
||||
@ -161,7 +161,7 @@ public class ProxiedMessage
|
||||
if (ctx.Guild == null)
|
||||
throw new PKSyntaxError($"You must use a message link to {editType} messages in DMs.");
|
||||
|
||||
PKMessage? recent;
|
||||
ulong? recent = null;
|
||||
|
||||
if (isReproxy)
|
||||
recent = await ctx.Repository.GetLastMessage(ctx.Guild.Id, ctx.Channel.Id, ctx.Author.Id);
|
||||
@ -172,17 +172,21 @@ public class ProxiedMessage
|
||||
throw new PKSyntaxError($"Could not find a recent message to {editType}.");
|
||||
|
||||
await using var conn = await ctx.Database.Obtain();
|
||||
msg = await ctx.Repository.GetMessage(conn, recent.Mid);
|
||||
msg = await ctx.Repository.GetMessage(recent.Value);
|
||||
if (msg == null)
|
||||
throw new PKSyntaxError($"Could not find a recent message to {editType}.");
|
||||
}
|
||||
|
||||
if (msg.Message.Channel != ctx.Channel.Id)
|
||||
var member = await ctx.Repository.GetMember(msg.Member!.Value);
|
||||
if (member == null)
|
||||
throw new PKSyntaxError($"Could not find a recent message to {editType}.");
|
||||
|
||||
if (msg.Channel != ctx.Channel.Id)
|
||||
{
|
||||
var error =
|
||||
"The channel where the message was sent does not exist anymore, or you are missing permissions to access it.";
|
||||
|
||||
var channel = await _rest.GetChannelOrNull(msg.Message.Channel);
|
||||
var channel = await _rest.GetChannelOrNull(msg.Channel);
|
||||
if (channel == null)
|
||||
throw new PKError(error);
|
||||
|
||||
@ -192,16 +196,18 @@ public class ProxiedMessage
|
||||
throw new PKError(error);
|
||||
}
|
||||
|
||||
var isLatestMessage = _lastMessageCache.GetLastMessage(ctx.Message.ChannelId)?.Current.Id == ctx.Message.Id
|
||||
? _lastMessageCache.GetLastMessage(ctx.Message.ChannelId)?.Previous?.Id == msg.Message.Mid
|
||||
: _lastMessageCache.GetLastMessage(ctx.Message.ChannelId)?.Current.Id == msg.Message.Mid;
|
||||
var lastMessage = _lastMessageCache.GetLastMessage(ctx.Message.ChannelId);
|
||||
|
||||
var msgTimestamp = DiscordUtils.SnowflakeToInstant(msg.Message.Mid);
|
||||
var isLatestMessage = lastMessage?.Current.Id == ctx.Message.Id
|
||||
? lastMessage?.Previous?.Id == msg.Mid
|
||||
: lastMessage?.Current.Id == msg.Mid;
|
||||
|
||||
var msgTimestamp = DiscordUtils.SnowflakeToInstant(msg.Mid);
|
||||
if (isReproxy && !isLatestMessage)
|
||||
if (SystemClock.Instance.GetCurrentInstant() - msgTimestamp > timeout)
|
||||
throw new PKError($"The message is too old to be {editTypeAction}.");
|
||||
|
||||
return msg;
|
||||
return (msg, member.System);
|
||||
}
|
||||
|
||||
private async Task<PKMessage?> FindRecentMessage(Context ctx, Duration timeout)
|
||||
@ -229,7 +235,7 @@ public class ProxiedMessage
|
||||
|
||||
var isDelete = ctx.Match("delete") || ctx.MatchFlag("delete");
|
||||
|
||||
var message = await ctx.Database.Execute(c => ctx.Repository.GetMessage(c, messageId.Value));
|
||||
var message = await ctx.Repository.GetFullMessage(messageId.Value);
|
||||
if (message == null)
|
||||
{
|
||||
if (isDelete)
|
||||
|
@ -91,7 +91,7 @@ public class ReactionAdded: IEventHandler<MessageReactionAddEvent>
|
||||
// Message deletion
|
||||
case "\u274C": // Red X
|
||||
{
|
||||
var msg = await _db.Execute(c => _repo.GetMessage(c, evt.MessageId));
|
||||
var msg = await _repo.GetMessage(evt.MessageId);
|
||||
if (msg != null)
|
||||
await HandleProxyDeleteReaction(evt, msg);
|
||||
|
||||
@ -100,7 +100,7 @@ public class ReactionAdded: IEventHandler<MessageReactionAddEvent>
|
||||
case "\u2753": // Red question mark
|
||||
case "\u2754": // White question mark
|
||||
{
|
||||
var msg = await _db.Execute(c => _repo.GetMessage(c, evt.MessageId));
|
||||
var msg = await _repo.GetFullMessage(evt.MessageId);
|
||||
if (msg != null)
|
||||
await HandleQueryReaction(evt, msg);
|
||||
|
||||
@ -113,7 +113,7 @@ public class ReactionAdded: IEventHandler<MessageReactionAddEvent>
|
||||
case "\u23F0": // Alarm clock
|
||||
case "\u2757": // Exclamation mark
|
||||
{
|
||||
var msg = await _db.Execute(c => _repo.GetMessage(c, evt.MessageId));
|
||||
var msg = await _repo.GetFullMessage(evt.MessageId);
|
||||
if (msg != null)
|
||||
await HandlePingReaction(evt, msg);
|
||||
break;
|
||||
@ -121,15 +121,15 @@ public class ReactionAdded: IEventHandler<MessageReactionAddEvent>
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask HandleProxyDeleteReaction(MessageReactionAddEvent evt, FullMessage msg)
|
||||
private async ValueTask HandleProxyDeleteReaction(MessageReactionAddEvent evt, PKMessage msg)
|
||||
{
|
||||
if (!(await _cache.PermissionsIn(evt.ChannelId)).HasFlag(PermissionSet.ManageMessages))
|
||||
return;
|
||||
|
||||
var system = await _repo.GetSystemByAccount(evt.UserId);
|
||||
var isSameSystem = msg.Member != null && await _repo.IsMemberOwnedByAccount(msg.Member.Value, evt.UserId);
|
||||
|
||||
// Can only delete your own message
|
||||
if (msg.System?.Id != system?.Id && msg.Message.Sender != evt.UserId) return;
|
||||
// Can only delete your own message (same system or same Discord account)
|
||||
if (!isSameSystem && msg.Sender != evt.UserId) return;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -375,7 +375,7 @@ public class ProxyService
|
||||
// cache is out of date or channel is empty.
|
||||
return proxyName;
|
||||
|
||||
var pkMessage = await _db.Execute(conn => _repo.GetMessage(conn, lastMessage.Id));
|
||||
var pkMessage = await _repo.GetMessage(lastMessage.Id);
|
||||
|
||||
if (lastMessage.AuthorUsername == proxyName)
|
||||
{
|
||||
@ -385,12 +385,12 @@ public class ProxyService
|
||||
return FixSameNameInner(proxyName);
|
||||
|
||||
// last message was proxied by a different member
|
||||
if (pkMessage.Member?.Id != member.Id)
|
||||
if (pkMessage.Member != member.Id)
|
||||
return FixSameNameInner(proxyName);
|
||||
}
|
||||
|
||||
// if we fixed the name last message and it's the same member proxying, we want to fix it again
|
||||
if (lastMessage.AuthorUsername == FixSameNameInner(proxyName) && pkMessage?.Member?.Id == member.Id)
|
||||
if (lastMessage.AuthorUsername == FixSameNameInner(proxyName) && pkMessage?.Member == member.Id)
|
||||
return FixSameNameInner(proxyName);
|
||||
|
||||
// No issues found, current proxy name is fine.
|
||||
|
@ -5,6 +5,7 @@ namespace PluralKit.Core;
|
||||
public class CoreConfig
|
||||
{
|
||||
public string Database { get; set; }
|
||||
public string? MessagesDatabase { get; set; }
|
||||
public string? DatabasePassword { get; set; }
|
||||
public string RedisAddr { get; set; }
|
||||
public bool UseRedisMetrics { get; set; } = false;
|
||||
|
@ -25,6 +25,7 @@ internal partial class Database: IDatabase
|
||||
private readonly DbConnectionCountHolder _countHolder;
|
||||
private readonly DatabaseMigrator _migrator;
|
||||
private readonly string _connectionString;
|
||||
private readonly string _messagesConnectionString;
|
||||
|
||||
public Database(CoreConfig config, DbConnectionCountHolder countHolder, ILogger logger,
|
||||
IMetrics metrics, DatabaseMigrator migrator)
|
||||
@ -35,20 +36,26 @@ internal partial class Database: IDatabase
|
||||
_migrator = migrator;
|
||||
_logger = logger.ForContext<Database>();
|
||||
|
||||
var connectionString = new NpgsqlConnectionStringBuilder(_config.Database)
|
||||
string connectionString(string src)
|
||||
{
|
||||
Pooling = true,
|
||||
Enlist = false,
|
||||
NoResetOnClose = true,
|
||||
var builder = new NpgsqlConnectionStringBuilder(src)
|
||||
{
|
||||
Pooling = true,
|
||||
Enlist = false,
|
||||
NoResetOnClose = true,
|
||||
|
||||
// Lower timeout than default (15s -> 2s), should ideally fail-fast instead of hanging
|
||||
Timeout = 2
|
||||
};
|
||||
// Lower timeout than default (15s -> 2s), should ideally fail-fast instead of hanging
|
||||
Timeout = 2
|
||||
};
|
||||
|
||||
if (_config.DatabasePassword != null)
|
||||
connectionString.Password = _config.DatabasePassword;
|
||||
if (_config.DatabasePassword != null)
|
||||
builder.Password = _config.DatabasePassword;
|
||||
|
||||
_connectionString = connectionString.ConnectionString;
|
||||
return builder.ConnectionString;
|
||||
}
|
||||
|
||||
_connectionString = connectionString(_config.Database);
|
||||
_messagesConnectionString = connectionString(_config.MessagesDatabase ?? _config.Database);
|
||||
}
|
||||
|
||||
private static readonly PostgresCompiler _compiler = new();
|
||||
@ -88,14 +95,14 @@ internal partial class Database: IDatabase
|
||||
}
|
||||
|
||||
// TODO: make sure every SQL query is behind a logged query method
|
||||
public async Task<IPKConnection> Obtain()
|
||||
public async Task<IPKConnection> Obtain(bool messages = false)
|
||||
{
|
||||
// Mark the request (for a handle, I guess) in the metrics
|
||||
_metrics.Measure.Meter.Mark(CoreMetrics.DatabaseRequests);
|
||||
|
||||
// Create a connection and open it
|
||||
// We wrap it in PKConnection for tracing purposes
|
||||
var conn = new PKConnection(new NpgsqlConnection(_connectionString), _countHolder, _logger, _metrics);
|
||||
var conn = new PKConnection(new NpgsqlConnection(messages ? _messagesConnectionString : _connectionString), _countHolder, _logger, _metrics);
|
||||
await conn.OpenAsync();
|
||||
return conn;
|
||||
}
|
||||
|
@ -31,10 +31,17 @@ internal partial class Database: IDatabase
|
||||
yield return val;
|
||||
}
|
||||
|
||||
public async Task<int> ExecuteQuery(Query q, string extraSql = "", [CallerMemberName] string queryName = "")
|
||||
public async Task<T> QueryFirst<T>(string q, object param = null, [CallerMemberName] string queryName = "", bool messages = false)
|
||||
{
|
||||
using var conn = await Obtain(messages);
|
||||
using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName)))
|
||||
return await conn.QueryFirstOrDefaultAsync<T>(q, param);
|
||||
}
|
||||
|
||||
public async Task<int> ExecuteQuery(Query q, string extraSql = "", [CallerMemberName] string queryName = "", bool messages = false)
|
||||
{
|
||||
var query = _compiler.Compile(q);
|
||||
using var conn = await Obtain();
|
||||
using var conn = await Obtain(messages);
|
||||
using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName)))
|
||||
return await conn.ExecuteAsync(query.Sql + $" {extraSql}", query.NamedBindings);
|
||||
}
|
||||
|
@ -7,15 +7,16 @@ namespace PluralKit.Core;
|
||||
public interface IDatabase
|
||||
{
|
||||
Task ApplyMigrations();
|
||||
Task<IPKConnection> Obtain();
|
||||
Task<IPKConnection> Obtain(bool messages = false);
|
||||
Task Execute(Func<IPKConnection, Task> func);
|
||||
Task<T> Execute<T>(Func<IPKConnection, Task<T>> func);
|
||||
IAsyncEnumerable<T> Execute<T>(Func<IPKConnection, IAsyncEnumerable<T>> func);
|
||||
Task<int> ExecuteQuery(Query q, string extraSql = "", [CallerMemberName] string queryName = "");
|
||||
Task<int> ExecuteQuery(Query q, string extraSql = "", [CallerMemberName] string queryName = "", bool messages = false);
|
||||
|
||||
Task<int> ExecuteQuery(IPKConnection? conn, Query q, string extraSql = "",
|
||||
[CallerMemberName] string queryName = "");
|
||||
|
||||
Task<T> QueryFirst<T>(string q, object param = null, [CallerMemberName] string queryName = "", bool messages = false);
|
||||
Task<T> QueryFirst<T>(Query q, string extraSql = "", [CallerMemberName] string queryName = "");
|
||||
|
||||
Task<T> QueryFirst<T>(IPKConnection? conn, Query q, string extraSql = "",
|
||||
|
@ -89,4 +89,12 @@ public partial class ModelRepository
|
||||
if (oldMember != null)
|
||||
_ = _dispatch.Dispatch(oldMember.System, oldMember.Uuid, DispatchEvent.DELETE_MEMBER);
|
||||
}
|
||||
|
||||
public async Task<bool> IsMemberOwnedByAccount(MemberId id, ulong userId)
|
||||
{
|
||||
return await _db.QueryFirst<bool>(
|
||||
"select true from accounts, members where members.id = @member and accounts.uid = @account and members.system = accounts.system",
|
||||
new { member = id, account = userId }
|
||||
);
|
||||
}
|
||||
}
|
@ -20,29 +20,38 @@ public partial class ModelRepository
|
||||
_logger.Debug("Stored message {@StoredMessage} in channel {Channel}", msg, msg.Channel);
|
||||
|
||||
// "on conflict do nothing" in the (pretty rare) case of duplicate events coming in from Discord, which would lead to a DB error before
|
||||
return _db.ExecuteQuery(query, "on conflict do nothing");
|
||||
return _db.ExecuteQuery(query, "on conflict do nothing", messages: true);
|
||||
}
|
||||
|
||||
// todo: add a Mapper to QuerySingle and move this to SqlKata
|
||||
public async Task<FullMessage?> GetMessage(IPKConnection conn, ulong id)
|
||||
public async Task<PKMessage?> GetMessage(ulong id)
|
||||
{
|
||||
FullMessage Mapper(PKMessage msg, PKMember member, PKSystem system) =>
|
||||
new() { Message = msg, System = system, Member = member };
|
||||
return await _db.QueryFirst<PKMessage?>(
|
||||
"select * from messages where mid = @Id",
|
||||
new { Id = id },
|
||||
messages: true
|
||||
);
|
||||
}
|
||||
|
||||
var query = "select * from messages"
|
||||
+ " left join members on messages.member = members.id"
|
||||
+ " left join systems on members.system = systems.id"
|
||||
+ " where (mid = @Id or original_mid = @Id)";
|
||||
public async Task<FullMessage?> GetFullMessage(ulong id)
|
||||
{
|
||||
var rawMessage = await GetMessage(id);
|
||||
if (rawMessage == null) return null;
|
||||
|
||||
var result = await conn.QueryAsync<PKMessage, PKMember, PKSystem, FullMessage>(
|
||||
query, Mapper, new { Id = id });
|
||||
return result.FirstOrDefault();
|
||||
var member = rawMessage.Member == null ? null : await GetMember(rawMessage.Member.Value);
|
||||
var system = member == null ? null : await GetSystem(member.System);
|
||||
|
||||
return new FullMessage
|
||||
{
|
||||
Message = rawMessage,
|
||||
Member = member,
|
||||
System = system,
|
||||
};
|
||||
}
|
||||
|
||||
public async Task DeleteMessage(ulong id)
|
||||
{
|
||||
var query = new Query("messages").AsDelete().Where("mid", id);
|
||||
var rowCount = await _db.ExecuteQuery(query);
|
||||
var rowCount = await _db.ExecuteQuery(query, messages: true);
|
||||
if (rowCount > 0)
|
||||
_logger.Information("Deleted message {MessageId} from database", id);
|
||||
}
|
||||
@ -52,22 +61,9 @@ public partial class ModelRepository
|
||||
// Npgsql doesn't support ulongs in general - we hacked around it for plain ulongs but tbh not worth it for collections of ulong
|
||||
// Hence we map them to single longs, which *are* supported (this is ok since they're Technically (tm) stored as signed longs in the db anyway)
|
||||
var query = new Query("messages").AsDelete().WhereIn("mid", ids.Select(id => (long)id).ToArray());
|
||||
var rowCount = await _db.ExecuteQuery(query);
|
||||
var rowCount = await _db.ExecuteQuery(query, messages: true);
|
||||
if (rowCount > 0)
|
||||
_logger.Information("Bulk deleted messages ({FoundCount} found) from database: {MessageIds}", rowCount,
|
||||
ids);
|
||||
}
|
||||
|
||||
public Task<PKMessage?> GetLastMessage(ulong guildId, ulong channelId, ulong accountId)
|
||||
{
|
||||
// Want to index scan on the (guild, sender, mid) index so need the additional constraint
|
||||
var query = new Query("messages")
|
||||
.Where("guild", guildId)
|
||||
.Where("channel", channelId)
|
||||
.Where("sender", accountId)
|
||||
.OrderByDesc("mid")
|
||||
.Limit(1);
|
||||
|
||||
return _db.QueryFirst<PKMessage?>(query);
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import (
|
||||
)
|
||||
|
||||
var data_db *pgx.Conn
|
||||
var messages_db *pgx.Conn
|
||||
var stats_db *pgx.Conn
|
||||
var rdb *redis.Client
|
||||
|
||||
@ -20,6 +21,7 @@ func run_simple_pg_query(c *pgx.Conn, sql string) {
|
||||
|
||||
func connect_dbs() {
|
||||
data_db = pg_connect(get_env_var("DATA_DB_URI"))
|
||||
messages_db = pg_connect(get_env_var("MESSAGES_DB_URI"))
|
||||
stats_db = pg_connect(get_env_var("STATS_DB_URI"))
|
||||
rdb = redis_connect(get_env_var("REDIS_ADDR"))
|
||||
}
|
||||
|
@ -37,6 +37,15 @@ func run_redis_query() []rstatval {
|
||||
return values
|
||||
}
|
||||
|
||||
func get_message_count() int {
|
||||
var count int
|
||||
row := messages_db.QueryRow(context.Background(), "select count(*) as count from systems")
|
||||
if err := row.Scan(&count); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func run_data_stats_query() map[string]interface{} {
|
||||
s := map[string]interface{}{}
|
||||
|
||||
|
@ -36,14 +36,12 @@ func update_db_meta() {
|
||||
}
|
||||
|
||||
func update_db_message_meta() {
|
||||
// since we're doing this concurrently, it needs a separate db connection
|
||||
tmp_db := pg_connect(get_env_var("DATA_DB_URI"))
|
||||
defer tmp_db.Close(context.Background())
|
||||
count := get_message_count()
|
||||
|
||||
key := "message"
|
||||
q := fmt.Sprintf("update info set %s_count = (select count(*) from %s)", key, plural(key))
|
||||
log.Println("data db query:", q)
|
||||
run_simple_pg_query(tmp_db, q)
|
||||
_, err := data_db.Exec(context.Background(), "update info set message_count = $1", count)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func update_stats() {
|
||||
|
Loading…
Reference in New Issue
Block a user