221 lines
7.4 KiB
C#
221 lines
7.4 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
using Discord;
|
||
using Discord.WebSocket;
|
||
using DML.Application.Classes;
|
||
using DML.Client;
|
||
using SweetLib.Utils;
|
||
using SweetLib.Utils.Extensions;
|
||
using static SweetLib.Utils.Logger.Logger;
|
||
|
||
namespace DML.AppCore.Classes
|
||
{
|
||
internal enum JobState
|
||
{
|
||
Idle,
|
||
Scanning,
|
||
Listening
|
||
}
|
||
|
||
public class Job
|
||
{
|
||
public int Id { get; set; }
|
||
public ulong GuildId { get; set; }
|
||
public ulong ChannelId { get; set; }
|
||
public double KnownTimestamp { get; set; } = 0;
|
||
private double StopTimestamp { get; set; } = 0;
|
||
private bool IsValid { get; set; } = true;
|
||
internal JobState State { get; set; } = JobState.Idle;
|
||
|
||
|
||
internal void Store()
|
||
{
|
||
Debug("Storing job to database...");
|
||
Trace("Getting jobs collection...");
|
||
var jobDb = Core.Database.GetCollection<Job>("jobs");
|
||
|
||
Trace("Adding new value...");
|
||
|
||
if (jobDb.Find(x => x.ChannelId == ChannelId && x.GuildId == GuildId).Any())
|
||
{
|
||
jobDb.Update(this);
|
||
}
|
||
else
|
||
{
|
||
jobDb.Insert(this);
|
||
}
|
||
}
|
||
|
||
public void Delete()
|
||
{
|
||
Debug("Deleting job from database...");
|
||
Trace("Getting jobs collection...");
|
||
var jobDb = Core.Database.GetCollection<Job>("jobs");
|
||
|
||
Trace("Deleting value...");
|
||
jobDb.Delete(Id);
|
||
}
|
||
|
||
private SocketGuild FindServerById(ulong id)
|
||
{
|
||
Trace($"Trying to find server by Id: {id}");
|
||
return (from s in DMLClient.Client.Guilds where s.Id == id select s).FirstOrDefault();
|
||
}
|
||
|
||
private SocketTextChannel FindChannelById(SocketGuild server, ulong id)
|
||
{
|
||
Trace($"Trying to find channel in {server} by id: {id}");
|
||
return (from c in server.TextChannels where c.Id == id select c).FirstOrDefault();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Performs scanning task of the job.
|
||
/// </summary>
|
||
/// <returns>Returns true if the newest messages have been scanned.</returns>
|
||
internal async Task<bool> Scan()
|
||
{
|
||
Debug($"Starting scan of guild {GuildId} channel {ChannelId}...");
|
||
var result = new List<IMessage>();
|
||
|
||
var limit = 100;
|
||
var lastId = ulong.MaxValue;
|
||
var isFirst = true;
|
||
var finished = false;
|
||
var scanStartTimeStamp = DateTime.UtcNow;
|
||
|
||
var guild = FindServerById(GuildId);
|
||
var channel = FindChannelById(guild, ChannelId);
|
||
|
||
Debug("Checking channel access");
|
||
if (channel.GetUser(channel.Guild.CurrentUser.Id) == null)
|
||
{
|
||
Info("Skipping channel without access");
|
||
return true;
|
||
}
|
||
|
||
if (Math.Abs(StopTimestamp) < 0.4)
|
||
StopTimestamp = KnownTimestamp;
|
||
Trace("Initialized scanning parameters.");
|
||
|
||
while (!finished)
|
||
{
|
||
Trace("Entering scanning loop...");
|
||
var messages = new List<IMessage>();
|
||
|
||
Trace($"Downloading next {limit} messages...");
|
||
if (isFirst)
|
||
{
|
||
var realMessages = await channel.GetMessagesAsync(limit).ToArray();
|
||
|
||
messages.AddRange(realMessages.SelectMany(realMessageArray => realMessageArray));
|
||
}
|
||
else
|
||
{
|
||
var realMessages = await channel.GetMessagesAsync(lastId, Direction.Before, limit).ToArray();
|
||
|
||
messages.AddRange(realMessages.SelectMany(realMessageArray => realMessageArray));
|
||
}
|
||
|
||
Trace($"Downloaded {messages.Count} messages.");
|
||
isFirst = false;
|
||
|
||
foreach (var m in messages)
|
||
{
|
||
if (!IsValid)
|
||
return false;
|
||
|
||
Core.Scheduler.MessagesScanned++;
|
||
|
||
Debug($"Processing message {m.Id}");
|
||
if (m.Id < lastId)
|
||
{
|
||
Trace($"Updating lastId ({lastId}) to {m.Id}");
|
||
lastId = m.Id;
|
||
}
|
||
|
||
if (m.CreatedAt.UtcDateTime.ToUnixTimeStamp() <= StopTimestamp)
|
||
{
|
||
Debug("Found a message with a known timestamp...Stopping scan.");
|
||
finished = true;
|
||
continue;
|
||
}
|
||
|
||
Trace($"Message {m.Id} has {m.Attachments.Count} attachments.");
|
||
if (m.Attachments.Count > 0)
|
||
{
|
||
result.Add(m);
|
||
Core.Scheduler.TotalAttachments += (ulong)m.Attachments.Count;
|
||
Trace($"Added message {m.Id}");
|
||
}
|
||
Debug($"Finished message {m.Id}");
|
||
}
|
||
|
||
finished = finished || messages.Count < limit;
|
||
}
|
||
|
||
Trace($"Downloaded all messages for guild {GuildId} channel {ChannelId}.");
|
||
|
||
Trace("Sorting messages...");
|
||
result.Sort((a, b) => DateTime.Compare(a.CreatedAt.UtcDateTime, b.CreatedAt.UtcDateTime));
|
||
|
||
foreach (var r in result)
|
||
{
|
||
foreach (var a in r.Attachments)
|
||
{
|
||
var mediaData = new MediaData
|
||
{
|
||
Id = a.Id,
|
||
GuildId = (r.Channel as SocketTextChannel)?.Guild?.Id ?? 0,
|
||
ChannelId = r.Channel.Id,
|
||
DownloadSource = a.Url,
|
||
Filename = a.Filename,
|
||
TimeStamp = r.CreatedAt.UtcDateTime.ToUnixTimeStamp(),
|
||
FileSize = a.Size
|
||
};
|
||
mediaData.Store();
|
||
}
|
||
}
|
||
|
||
if (result.Count > 0)
|
||
{
|
||
Trace("Updating StopTimestamp for next scan...");
|
||
StopTimestamp = result[result.Count - 1].CreatedAt.UtcDateTime.ToUnixTimeStamp();
|
||
KnownTimestamp = StopTimestamp;
|
||
Store();
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
// if we found any messages we remember the timestamp of starting so we don´t have to scan all past messages....
|
||
StopTimestamp = scanStartTimeStamp.ToUnixTimeStamp();
|
||
KnownTimestamp = StopTimestamp;
|
||
Store();
|
||
|
||
var realLastMessage = await channel.GetMessagesAsync(1).ToArray();
|
||
return scanStartTimeStamp > (realLastMessage.SelectMany(realLastMessageArray => realLastMessageArray)
|
||
.FirstOrDefault()?.CreatedAt.UtcDateTime ??
|
||
scanStartTimeStamp);
|
||
}
|
||
|
||
Debug($"Fisnished scan of guild {GuildId} channel {ChannelId}.");
|
||
}
|
||
|
||
public void Stop()
|
||
{
|
||
IsValid = false;
|
||
}
|
||
|
||
public static IEnumerable<Job> RestoreJobs()
|
||
{
|
||
Debug("Restoring jobs...");
|
||
Trace("Getting jobs collection...");
|
||
var jobDb = Core.Database.GetCollection<Job>("jobs");
|
||
|
||
Trace("Creating new empty job list");
|
||
return jobDb.FindAll();
|
||
}
|
||
}
|
||
}
|